Heinrich Schuchardt <xypron.g...@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.g...@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
> +}
> +

[...]

Reply via email to