UEFI volatile variables are managed in efi_var_htab while UEFI non-volatile
variables are in efi_nv_var_htab. At every SetVariable API, env_efi_save()
will also be called to save data cache (hash table) to persistent storage.

Signed-off-by: AKASHI Takahiro <takahiro.aka...@linaro.org>
---
 lib/efi_loader/efi_variable.c | 162 ++++++++++++++++++++++++++++++++--
 1 file changed, 155 insertions(+), 7 deletions(-)

diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 2f489ab9db97..f7b1ce2f3350 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -48,6 +48,115 @@
  * converted to utf16?
  */
 
+/*
+ * We will maintain two variable database: one for volatile variables,
+ * the other for non-volatile variables. The former exists only in memory
+ * and will go away at re-boot. The latter is currently backed up by the same
+ * device as U-Boot environment and also works as variables cache.
+ */
+
+enum efi_var_type {
+       EFI_VAR_TYPE_VOLATILE,
+       EFI_VAR_TYPE_NON_VOLATILE,
+};
+
+struct hsearch_data efi_var_htab;
+struct hsearch_data efi_nv_var_htab;
+
+static char *env_efi_get(const char *name, int type)
+{
+       struct hsearch_data *htab;
+       ENTRY e, *ep;
+
+       /* WATCHDOG_RESET(); */
+
+       if (type == EFI_VAR_TYPE_VOLATILE)
+               htab = &efi_var_htab;
+       else
+               htab = &efi_nv_var_htab;
+
+       e.key   = name;
+       e.data  = NULL;
+       hsearch_r(e, FIND, &ep, htab, 0);
+
+       return ep ? ep->data : NULL;
+}
+
+static int env_efi_set(const char *name, const char *value, int type)
+{
+       struct hsearch_data *htab;
+       ENTRY e, *ep;
+       int ret;
+
+       if (type == EFI_VAR_TYPE_VOLATILE)
+               htab = &efi_var_htab;
+       else
+               htab = &efi_nv_var_htab;
+
+       /* delete */
+       if (!value || *value == '\0') {
+               ret = hdelete_r(name, htab, H_PROGRAMMATIC);
+               return !ret;
+       }
+
+       /* set */
+       e.key   = name;
+       e.data  = (char *)value;
+       hsearch_r(e, ENTER, &ep, htab, H_PROGRAMMATIC);
+       if (!ep) {
+               printf("## Error inserting \"%s\" variable, errno=%d\n",
+                      name, errno);
+               return 1;
+       }
+
+       return 0;
+}
+
+int efi_variable_import(const char *buf, int check)
+{
+       env_t *ep = (env_t *)buf;
+
+       if (check) {
+               u32 crc;
+
+               memcpy(&crc, &ep->crc, sizeof(crc));
+
+               if (crc32(0, ep->data, CONFIG_ENV_EFI_SIZE) != crc) {
+                       pr_err("bad CRC of UEFI variables\n");
+                       return -ENOMSG; /* needed for env_load() */
+               }
+       }
+
+       if (himport_r(&efi_nv_var_htab, (char *)ep->data, CONFIG_ENV_EFI_SIZE,
+                     '\0', 0, 0, 0, NULL))
+               return 0;
+
+       pr_err("Cannot import environment: errno = %d\n", errno);
+
+       /* set_default_env("import failed", 0); */
+
+       return -EIO;
+}
+
+/* Export the environment and generate CRC for it. */
+int efi_variable_export(env_t *env_out)
+{
+       char *res;
+       ssize_t len;
+
+       res = (char *)env_out->data;
+       len = hexport_r(&efi_nv_var_htab, '\0', 0, &res, CONFIG_ENV_EFI_SIZE,
+                       0, NULL);
+       if (len < 0) {
+               pr_err("Cannot export environment: errno = %d\n", errno);
+               return 1;
+       }
+
+       env_out->crc = crc32(0, env_out->data, CONFIG_ENV_EFI_SIZE);
+
+       return 0;
+}
+
 #define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_"))
 
 /**
@@ -184,7 +293,9 @@ efi_status_t EFIAPI efi_get_variable(u16 *variable_name,
 
        EFI_PRINT("get '%s'\n", native_name);
 
-       val = env_get(native_name);
+       val = env_efi_get(native_name, EFI_VAR_TYPE_VOLATILE);
+       if (!val)
+               val = env_efi_get(native_name, EFI_VAR_TYPE_NON_VOLATILE);
        free(native_name);
        if (!val)
                return EFI_EXIT(EFI_NOT_FOUND);
@@ -326,7 +437,7 @@ efi_status_t EFIAPI efi_get_next_variable_name(efi_uintn_t 
*variable_name_size,
                                               u16 *variable_name,
                                               const efi_guid_t *vendor)
 {
-       char *native_name, *variable;
+       char *native_name, *variable, *tmp_list, *merged_list;
        ssize_t name_len, list_len;
        char regex[256];
        char * const regexlist[] = {regex};
@@ -382,10 +493,39 @@ efi_status_t EFIAPI 
efi_get_next_variable_name(efi_uintn_t *variable_name_size,
                efi_cur_variable = NULL;
 
                snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*");
-               list_len = hexport_r(&env_htab, '\n',
+               list_len = hexport_r(&efi_var_htab, '\n',
                                     H_MATCH_REGEX | H_MATCH_KEY,
                                     &efi_variables_list, 0, 1, regexlist);
-               /* 1 indicates that no match was found */
+               /*
+                * Note: '1' indicates that nothing is matched
+                */
+               if (list_len <= 1) {
+                       free(efi_variables_list);
+                       efi_variables_list = NULL;
+                       list_len = hexport_r(&efi_nv_var_htab, '\n',
+                                            H_MATCH_REGEX | H_MATCH_KEY,
+                                            &efi_variables_list, 0, 1,
+                                            regexlist);
+               } else {
+                       tmp_list = NULL;
+                       list_len = hexport_r(&efi_nv_var_htab, '\n',
+                                            H_MATCH_REGEX | H_MATCH_KEY,
+                                            &tmp_list, 0, 1,
+                                            regexlist);
+                       if (list_len <= 1) {
+                               list_len = 2; /* don't care actual number */
+                       } else {
+                               /* merge two variables lists */
+                               merged_list = malloc(strlen(efi_variables_list)
+                                                       + strlen(tmp_list) + 1);
+                               strcpy(merged_list, efi_variables_list);
+                               strcat(merged_list, tmp_list);
+                               free(efi_variables_list);
+                               free(tmp_list);
+                               efi_variables_list = merged_list;
+                       }
+               }
+
                if (list_len <= 1)
                        return EFI_EXIT(EFI_NOT_FOUND);
 
@@ -420,6 +560,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
        char *native_name = NULL, *val = NULL, *s;
        efi_status_t ret = EFI_SUCCESS;
        u32 attr;
+       int type;
 
        EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
                  data_size, data);
@@ -435,14 +576,18 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
 
 #define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | 
EFI_VARIABLE_BOOTSERVICE_ACCESS)
 
+       type = (attributes & EFI_VARIABLE_NON_VOLATILE) ?
+               EFI_VAR_TYPE_NON_VOLATILE : EFI_VAR_TYPE_VOLATILE;
        if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
                /* delete the variable: */
-               env_set(native_name, NULL);
+               env_efi_set(native_name, NULL, type);
                ret = EFI_SUCCESS;
                goto out;
        }
 
-       val = env_get(native_name);
+       val = env_efi_get(native_name, EFI_VAR_TYPE_VOLATILE);
+       if (!val)
+               val = env_efi_get(native_name, EFI_VAR_TYPE_NON_VOLATILE);
        if (val) {
                parse_attr(val, &attr);
 
@@ -493,9 +638,12 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
 
        EFI_PRINT("setting: %s=%s\n", native_name, val);
 
-       if (env_set(native_name, val))
+       if (env_efi_set(native_name, val, type))
                ret = EFI_DEVICE_ERROR;
 
+       /* FIXME: what if save failed? */
+       env_efi_save();
+
 out:
        free(native_name);
        free(val);
-- 
2.20.1

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to