[PATCH 10/16] efi_loader: UEFI variable persistence

Punit Agrawal punit1.agrawal at toshiba.co.jp
Fri Mar 27 09:07:30 CET 2020


Heinrich Schuchardt <xypron.glpk at gmx.de> writes:

> Persist non-volatile UEFI variables in a file on the EFI system partition.
>
> The file is written:
>
> * whenever a non-volatile UEFI variable is changed after initialization
>   of the UEFI sub-system.
> * upon ExitBootServices()

I might be missing something but how does this cope with the ESP being
on a storage medium access to which is owned by the OS at runtime? e.g.,
partition on eMMC or SATA drive.

>
> The file is read during the UEFI sub-system initialization to restore
> non-volatile UEFI variables.
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
>  include/efi_variable.h              |  36 +++++
>  lib/efi_loader/Kconfig              |   8 +
>  lib/efi_loader/Makefile             |   1 +
>  lib/efi_loader/efi_variable.c       |  12 +-
>  lib/efi_loader/efi_variables_file.c | 235 ++++++++++++++++++++++++++++
>  5 files changed, 291 insertions(+), 1 deletion(-)
>  create mode 100644 include/efi_variable.h
>  create mode 100644 lib/efi_loader/efi_variables_file.c
>

[...]

> diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
> index e10ca05549..41705fc252 100644
> --- a/lib/efi_loader/Kconfig
> +++ b/lib/efi_loader/Kconfig
> @@ -27,6 +27,14 @@ config EFI_LOADER
>
>  if EFI_LOADER
>
> +config EFI_VARIABLE_FILE_STORE
> +	bool "Store non-volatile UEFI variables as file"
> +	depends on FAT_WRITE
> +	default y
> +	help
> +	  Select tis option if you want non-volatile UEFI variables to be stored

                 this

> +	  as file /ubootefi.var on the EFI system partition.
> +
>  config EFI_GET_TIME
>  	bool "GetTime() runtime service"
>  	depends on DM_RTC

[...]

> diff --git a/lib/efi_loader/efi_variables_file.c b/lib/efi_loader/efi_variables_file.c
> new file mode 100644
> index 0000000000..4a918d3fde
> --- /dev/null
> +++ b/lib/efi_loader/efi_variables_file.c
> @@ -0,0 +1,235 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * File interface for UEFI variables
> + *
> + * Copyright (c) 2020, Heinrich Schuchardt
> + */
> +
> +#include <common.h>
> +#include <charset.h>
> +#include <fs.h>
> +#include <malloc.h>
> +#include <mapmem.h>
> +#include <efi_loader.h>
> +#include <efi_variable.h>
> +#include <u-boot/crc.h>
> +
> +#define PART_STR_LEN 10
> +
> +/**
> + * efi_set_blk_dev_to_system_partition() - select EFI system partition
> + *
> + * Set the EFI system partition as current block device.
> + *
> + * Return:	status code
> + */
> +static efi_status_t __maybe_unused efi_set_blk_dev_to_system_partition(void)
> +{
> +	char part_str[PART_STR_LEN];
> +	int r;
> +
> +	if (!efi_system_partition.if_type)
> +		return EFI_NOT_FOUND;
> +	snprintf(part_str, PART_STR_LEN, "%u:%u",
> +		 efi_system_partition.devnum, efi_system_partition.part);
> +	r = fs_set_blk_dev(blk_get_if_type_name(efi_system_partition.if_type),
> +			   part_str, FS_TYPE_ANY);
> +	if (r) {
> +		printf("Cannot read EFI system partition\n");
> +		return EFI_DEVICE_ERROR;
> +	}
> +	return EFI_SUCCESS;
> +}
> +
> +/**
> + * efi_var_collect() - collect non-volatile variables in buffer
> + *
> + * A buffer is allocated and filled with all non-volatile variables in a
> + * format ready to be written to disk.
> + *
> + * @bufp:	pointer to pointer of buffer with collected variables
> + * @lenp:	pointer to length of buffer
> + * Return:	status code
> + */
> +static efi_status_t __maybe_unused efi_var_collect(struct efi_var_file **bufp,
> +						   loff_t *lenp)
> +{
> +	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;
> +
> +	*bufp = NULL; /* Avoid double free() */
> +	buf = calloc(1, len);
> +	if (!buf)
> +		return EFI_OUT_OF_RESOURCES;
> +	var = buf->var;
> +	old_var = var;
> +	for (;;) {
> +		efi_uintn_t data_length, var_name_length;
> +		u8 *data;
> +		efi_status_t ret;
> +
> +		if ((uintptr_t)buf + len <=
> +		    (uintptr_t)var->name + old_var_name_length)
> +			return EFI_BUFFER_TOO_SMALL;
> +
> +		var_name_length = (uintptr_t)buf + len - (uintptr_t)var->name;
> +		memcpy(var->name, old_var->name, old_var_name_length);
> +		guidcpy(&var->guid, &old_var->guid);
> +		ret = efi_get_next_variable_name_int(
> +				&var_name_length, var->name, &var->guid);
> +		if (ret == EFI_NOT_FOUND)
> +			break;
> +		if (ret != EFI_SUCCESS) {
> +			free(buf);
> +			return ret;
> +		}
> +		old_var_name_length = var_name_length;
> +		old_var = var;
> +
> +		data = (u8 *)var->name + old_var_name_length;
> +		data_length = (uintptr_t)buf + len - (uintptr_t)data;
> +		ret = efi_get_variable_int(var->name, &var->guid,
> +					   &var->attr, &data_length, data);
> +		if (ret != EFI_SUCCESS) {
> +			free(buf);
> +			return ret;
> +		}
> +		if (!(var->attr & EFI_VARIABLE_NON_VOLATILE))
> +			continue;
> +		var->length = data_length;
> +		var = (struct efi_var_entry *)
> +		      ALIGN((uintptr_t)data + data_length, 8);
> +	}
> +
> +	buf->reserved = 0;
> +	buf->magic = EFI_VAR_FILE_MAGIC;
> +	len = (uintptr_t)var - (uintptr_t)buf;
> +	buf->crc32 = crc32(0, (u8 *)buf->var,
> +			   len - sizeof(struct efi_var_file));
> +	buf->length = len;
> +	*bufp = buf;
> +	*lenp = len;
> +
> +	return EFI_SUCCESS;
> +}
> +
> +/**
> + * efi_var_to_file() - save non-volatile variables as file
> + *
> + * File ubootefi.var is created on the EFI system partion.
> + *
> + * Return:	status code
> + */

The return value doesn't seem to be used in this patch. Is it really
needed?

Thanks,
Punit

> +efi_status_t efi_var_to_file(void)
> +{
> +#ifdef CONFIG_EFI_VARIABLE_FILE_STORE
> +	efi_status_t ret;
> +	struct efi_var_file *buf;
> +	loff_t len;
> +	loff_t actlen;
> +	int r;
> +
> +	ret = efi_var_collect(&buf, &len);
> +	if (ret != EFI_SUCCESS)
> +		goto error;
> +
> +	ret = efi_set_blk_dev_to_system_partition();
> +	if (ret != EFI_SUCCESS)
> +		goto error;
> +
> +	r = fs_write(EFI_VAR_FILE_NAME, map_to_sysmem(buf), 0, len, &actlen);
> +	if (r || len != actlen)
> +		ret =  EFI_DEVICE_ERROR;
> +
> +error:
> +	if (ret != EFI_SUCCESS)
> +		printf("Failed to persist EFI variables\n");
> +	free(buf);
> +	return ret;
> +#else
> +	return EFI_SUCCESS;
> +#endif
> +}
> +

[...]



More information about the U-Boot mailing list