In order to support (ESP)/ubootefi.var and preseed variables greater than EFI_VAR_BUF_SIZE (0x4000), dynamically determine the variable list size that will fit both and the ones that are created at boot time.
Signed-off-by: Paulo Alcantara (SUSE) <p...@cjr.nz> --- include/efi_variable.h | 15 +++++++++++++-- lib/efi_loader/efi_var_file.c | 36 ++++++++++++++++++++++++++++------- lib/efi_loader/efi_var_mem.c | 12 +++++++----- lib/efi_loader/efi_variable.c | 35 +++++++++++++++++++++++++++++++--- 4 files changed, 81 insertions(+), 17 deletions(-) diff --git a/include/efi_variable.h b/include/efi_variable.h index 4704a3c16e65..cd40dfe3359d 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -8,6 +8,8 @@ #include <linux/bitops.h> +extern efi_uintn_t __efi_runtime_data efi_var_buf_size; + #define EFI_VARIABLE_READ_ONLY BIT(31) enum efi_auth_var_type { @@ -91,7 +93,7 @@ efi_status_t efi_query_variable_info_int(u32 attributes, #define EFI_VAR_FILE_NAME "ubootefi.var" -#define EFI_VAR_BUF_SIZE 0x4000 +#define EFI_VAR_DEFAULT_BUF_SIZE 0x4000 /* * This constant identifies the file format for storing UEFI variables in @@ -179,12 +181,21 @@ efi_status_t efi_var_restore(struct efi_var_file *buf); */ efi_status_t efi_var_from_file(void); +/** + * efi_var_file_size() - determine variable file size + * + * @fsize: variable file size + * Return: status code + */ +efi_status_t __maybe_unused efi_var_file_size(efi_uintn_t *fsize); + /** * efi_var_mem_init() - set-up variable list * + * @mem_size: variable list size * Return: status code */ -efi_status_t efi_var_mem_init(void); +efi_status_t efi_var_mem_init(efi_uintn_t mem_size); /** * efi_var_mem_find() - find a variable in the list diff --git a/lib/efi_loader/efi_var_file.c b/lib/efi_loader/efi_var_file.c index b171d2d1a8f7..42c674241ef4 100644 --- a/lib/efi_loader/efi_var_file.c +++ b/lib/efi_loader/efi_var_file.c @@ -49,7 +49,7 @@ static efi_status_t __maybe_unused efi_set_blk_dev_to_system_partition(void) efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp, loff_t *lenp, u32 check_attr_mask) { - size_t len = EFI_VAR_BUF_SIZE; + size_t len = efi_var_buf_size; struct efi_var_file *buf; struct efi_var_entry *var, *old_var; size_t old_var_name_length = 2; @@ -193,12 +193,17 @@ efi_status_t efi_var_restore(struct efi_var_file *buf) efi_status_t efi_var_from_file(void) { #ifdef CONFIG_EFI_VARIABLE_FILE_STORE - struct efi_var_file *buf; + struct efi_var_file *buf = NULL; + efi_uintn_t fsize; loff_t len; efi_status_t ret; int r; - buf = calloc(1, EFI_VAR_BUF_SIZE); + ret = efi_var_file_size(&fsize); + if (ret != EFI_SUCCESS) + goto error; + + buf = calloc(1, fsize); if (!buf) { log_err("Out of memory\n"); return EFI_OUT_OF_RESOURCES; @@ -206,10 +211,10 @@ efi_status_t efi_var_from_file(void) ret = efi_set_blk_dev_to_system_partition(); if (ret != EFI_SUCCESS) - goto error; - r = fs_read(EFI_VAR_FILE_NAME, map_to_sysmem(buf), 0, EFI_VAR_BUF_SIZE, - &len); - if (r || len < sizeof(struct efi_var_file)) { + return ret; + + r = fs_read(EFI_VAR_FILE_NAME, map_to_sysmem(buf), 0, fsize, &len); + if (r || len != fsize) { log_err("Failed to load EFI variables\n"); goto error; } @@ -220,3 +225,20 @@ error: #endif return EFI_SUCCESS; } + +efi_status_t __maybe_unused efi_var_file_size(efi_uintn_t *fsize) +{ + efi_status_t ret; + loff_t size; + int r; + + ret = efi_set_blk_dev_to_system_partition(); + if (ret != EFI_SUCCESS) + return ret; + + r = fs_size(EFI_VAR_FILE_NAME, &size); + if (r) + size = 0; + *fsize = size; + return EFI_SUCCESS; +} diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c index d155f25f60e6..323c3b71ace0 100644 --- a/lib/efi_loader/efi_var_mem.c +++ b/lib/efi_loader/efi_var_mem.c @@ -11,6 +11,7 @@ #include <u-boot/crc.h> struct efi_var_file __efi_runtime_data *efi_var_buf; +efi_uintn_t __efi_runtime_data efi_var_buf_size; static struct efi_var_entry __efi_runtime_data *efi_current_var; /** @@ -146,7 +147,7 @@ efi_status_t __efi_runtime efi_var_mem_ins( data = var->name + var_name_len; if ((uintptr_t)data - (uintptr_t)efi_var_buf + size1 + size2 > - EFI_VAR_BUF_SIZE) + efi_var_buf_size) return EFI_OUT_OF_RESOURCES; var->attr = attributes; @@ -171,7 +172,7 @@ efi_status_t __efi_runtime efi_var_mem_ins( u64 __efi_runtime efi_var_mem_free(void) { - return EFI_VAR_BUF_SIZE - efi_var_buf->length - + return efi_var_buf_size - efi_var_buf->length - sizeof(struct efi_var_entry); } @@ -235,7 +236,7 @@ efi_var_mem_notify_virtual_address_map(struct efi_event *event, void *context) efi_current_var = NULL; } -efi_status_t efi_var_mem_init(void) +efi_status_t efi_var_mem_init(efi_uintn_t mem_size) { u64 memory; efi_status_t ret; @@ -243,12 +244,13 @@ efi_status_t efi_var_mem_init(void) ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_RUNTIME_SERVICES_DATA, - efi_size_in_pages(EFI_VAR_BUF_SIZE), + efi_size_in_pages(mem_size), &memory); if (ret != EFI_SUCCESS) return ret; efi_var_buf = (struct efi_var_file *)(uintptr_t)memory; - memset(efi_var_buf, 0, EFI_VAR_BUF_SIZE); + efi_var_buf_size = mem_size; + memset(efi_var_buf, 0, efi_var_buf_size); efi_var_buf->magic = EFI_VAR_FILE_MAGIC; efi_var_buf->length = (uintptr_t)efi_var_buf->var - (uintptr_t)efi_var_buf; diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 0c689cfb4705..af84c01c1f27 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -431,10 +431,10 @@ efi_status_t efi_query_variable_info_int(u32 attributes, u64 *remaining_variable_storage_size, u64 *maximum_variable_size) { - *maximum_variable_storage_size = EFI_VAR_BUF_SIZE - + *maximum_variable_storage_size = efi_var_buf_size - sizeof(struct efi_var_file); *remaining_variable_storage_size = efi_var_mem_free(); - *maximum_variable_size = EFI_VAR_BUF_SIZE - + *maximum_variable_size = efi_var_buf_size - sizeof(struct efi_var_file) - sizeof(struct efi_var_entry); return EFI_SUCCESS; @@ -496,6 +496,30 @@ void efi_variables_boot_exit_notify(void) efi_update_table_header_crc32(&efi_runtime_services.hdr); } +/** + * efi_var_mem_size() - determine variable storage size + * + * Return: status code + */ +static efi_status_t efi_var_mem_size(efi_uintn_t *size) +{ + efi_status_t ret; + efi_uintn_t nsize = EFI_VAR_DEFAULT_BUF_SIZE; + + if (IS_ENABLED(CONFIG_EFI_VARIABLES_PRESEED)) + nsize += (uintptr_t)__efi_var_file_end - (uintptr_t)__efi_var_file_begin; + if (IS_ENABLED(CONFIG_EFI_VARIABLE_FILE_STORE)) { + efi_uintn_t fsize; + + ret = efi_var_file_size(&fsize); + if (ret != EFI_SUCCESS) + return ret; + nsize += fsize; + } + *size = nsize; + return EFI_SUCCESS; +} + /** * efi_init_variables() - initialize variable services * @@ -504,8 +528,13 @@ void efi_variables_boot_exit_notify(void) efi_status_t efi_init_variables(void) { efi_status_t ret; + efi_uintn_t mem_size; - ret = efi_var_mem_init(); + ret = efi_var_mem_size(&mem_size); + if (ret != EFI_SUCCESS) + return ret; + + ret = efi_var_mem_init(mem_size); if (ret != EFI_SUCCESS) return ret; -- 2.29.2