From mboxrd@z Thu Jan 1 00:00:00 1970 From: AKASHI Takahiro Date: Wed, 24 Apr 2019 15:30:41 +0900 Subject: [U-Boot] [PATCH v2 07/11] efi_loader: variable: split UEFI variables from U-Boot environment In-Reply-To: <20190424063045.14443-1-takahiro.akashi@linaro.org> References: <20190424063045.14443-1-takahiro.akashi@linaro.org> Message-ID: <20190424063045.14443-8-takahiro.akashi@linaro.org> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 --- 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