[PATCH] lib/efi_loader: dynamically determine var store size

Heinrich Schuchardt xypron.glpk at gmx.de
Sun Dec 20 10:30:19 CET 2020


On 12/9/20 7:03 PM, Paulo Alcantara wrote:
> 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.

This patch indicates that 16 KiB is too small for storing the UEFI
variables you would like to manage. Please, indicate what size your
variables file currently has.

The current file size does not say anything about the future need of a
user. So this patch only partially addresses the problem.

The easiest thing to do is moving EFI_VAR_BUF_SIZE to Kconfig. This
reduces code complexity and seems more adequate to solve the problem.

Best regards

Heinrich

>
> Signed-off-by: Paulo Alcantara (SUSE) <pc at 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;
>
>



More information about the U-Boot mailing list