From mboxrd@z Thu Jan 1 00:00:00 1970 From: AKASHI Takahiro Date: Wed, 24 Apr 2019 15:30:39 +0900 Subject: [U-Boot] [PATCH v2 05/11] env: save UEFI non-volatile variables in dedicated storage In-Reply-To: <20190424063045.14443-1-takahiro.akashi@linaro.org> References: <20190424063045.14443-1-takahiro.akashi@linaro.org> Message-ID: <20190424063045.14443-6-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 We need a variant of env_save()/env_load() to handle dedicated storage for UEFI variables. It is assumed that env_efi_load() will be called only ince at init and that env_efi_save() will be called at every SetVariable. In this patch, new parameters will be expected to be configured: CONFIG_ENV_EFI_FAT_DEVICE_AND_PART CONFIG_ENV_EFI_FAT_FILE in case of CONFIG_ENV_IS_IN_FAT. Signed-off-by: AKASHI Takahiro --- env/Kconfig | 34 ++++++++++ env/env.c | 98 ++++++++++++++++++++++++++- env/fat.c | 109 ++++++++++++++++++++++++++++++ include/asm-generic/global_data.h | 1 + include/environment.h | 24 +++++++ 5 files changed, 265 insertions(+), 1 deletion(-) diff --git a/env/Kconfig b/env/Kconfig index 78300660c720..8f59e9347d4b 100644 --- a/env/Kconfig +++ b/env/Kconfig @@ -438,6 +438,34 @@ config ENV_FAT_FILE It's a string of the FAT file name. This file use to store the environment. +config ENV_EFI_FAT_DEVICE_AND_PART + string "Device and partition for where to store the UEFI non-volatile variables in FAT" + depends on ENV_IS_IN_FAT + depends on EFI_LOADER + help + Define this to a string to specify the partition of the device. It can + be as following: + + "D:P", "D:0", "D", "D:" or "D:auto" (D, P are integers. And P >= 1) + - "D:P": device D partition P. Error occurs if device D has no + partition table. + - "D:0": device D. + - "D" or "D:": device D partition 1 if device D has partition + table, or the whole device D if has no partition + table. + - "D:auto": first partition in device D with bootable flag set. + If none, first valid partition in device D. If no + partition table then means device D. + +config ENV_EFI_FAT_FILE + string "Name of the FAT file to use for the UEFI non-volatile variables" + depends on ENV_IS_IN_FAT + depends on EFI_LOADER + default "uboot_efi.env" + help + It's a string of the FAT file name. This file use to store the + UEFI non-volatile variables. + config ENV_EXT4_INTERFACE string "Name of the block device for the environment" depends on ENV_IS_IN_EXT4 @@ -470,6 +498,12 @@ config ENV_EXT4_FILE It's a string of the EXT4 file name. This file use to store the environment (explicit path to the file) +config ENV_EFI_SIZE + hex "UEFI Variables Environment Size" + default 0x20000 + help + Size of the UEFI variables storage area + if ARCH_ROCKCHIP || ARCH_SUNXI || ARCH_ZYNQ || ARCH_ZYNQMP || ARCH_VERSAL || ARC config ENV_OFFSET diff --git a/env/env.c b/env/env.c index 4b417b90a291..d5af761ba57e 100644 --- a/env/env.c +++ b/env/env.c @@ -24,6 +24,10 @@ void env_fix_drivers(void) entry->load += gd->reloc_off; if (entry->save) entry->save += gd->reloc_off; + if (entry->efi_load) + entry->efi_load += gd->reloc_off; + if (entry->efi_save) + entry->efi_save += gd->reloc_off; if (entry->init) entry->init += gd->reloc_off; } @@ -125,7 +129,8 @@ __weak enum env_location env_get_location(enum env_operation op, int prio) if (prio >= ARRAY_SIZE(env_locations)) return ENVL_UNKNOWN; - gd->env_load_prio = prio; + if (op != ENVOP_EFI) + gd->env_load_prio = prio; return env_locations[prio]; } @@ -280,3 +285,94 @@ int env_init(void) return ret; } + +#ifdef CONFIG_EFI_LOADER +extern struct hsearch_data efi_var_htab; +extern struct hsearch_data efi_nv_var_htab; + +/* TODO: experimental */ +int env_efi_save(void) +{ + struct env_driver *drv = NULL; + int ret; + + if (!efi_nv_var_htab.table) + return 0; + + if (gd->env_efi_prio == -1) { + printf("Cannot save UEFI non-volatile variable\n"); + return -1; + } + + drv = _env_driver_lookup(env_get_location(ENVOP_EFI, gd->env_efi_prio)); + if (!drv) { + printf("Cannot save UEFI non-volatile variable\n"); + return -1; + } + + ret = drv->efi_save(); + if (ret) + printf("Saving UEFI non-volatile variable failed\n"); + + return ret; +} + +/* TODO: experimental */ +/* This function should be called only once at init */ +int env_efi_load(void) +{ + struct env_driver *drv = NULL; + int prio, ret; + enum env_location loc; + + gd->env_efi_prio = -1; + + /* volatile variables */ + if (!efi_var_htab.table) { + ret = himport_r(&efi_var_htab, NULL, 0, '\0', 0, 0, 0, NULL); + if (!ret) { + printf("Creating default UEFI variables failed\n"); + return -1; + } + } + + /* non-loratile variables */ + if (efi_nv_var_htab.table) + return 0; + + for (prio = 0; prio < ARRAY_SIZE(env_locations); prio++) { + loc = env_get_location(ENVOP_EFI, prio); + drv = _env_driver_lookup(loc); + if (!drv) + continue; + + if (drv->efi_load && drv->efi_save) + break; + } + if (!drv || prio == ARRAY_SIZE(env_locations)) { + printf("No driver for UEFI storage is available\n"); + return -1; + } + + gd->env_efi_prio = prio; + + ret = drv->efi_load(); + if (ret) { + printf("Loading UEFI non-volatile variables failed\n"); + return -1; + } + + /* FIXME: init needed here? */ + if (!efi_nv_var_htab.table) { + ret = himport_r(&efi_nv_var_htab, NULL, 0, '\0', 0, 0, 0, NULL); + if (!ret) { + printf("Creating default UEFI non-volatile variables failed\n"); + return -1; + } + + return 0; + } + + return 0; +} +#endif /* CONFIG_EFI_LOADER */ diff --git a/env/fat.c b/env/fat.c index 7f74c64dfe7e..e2b050d4553d 100644 --- a/env/fat.c +++ b/env/fat.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,110 @@ err_env_relocate: } #endif /* LOADENV */ +#ifdef CONFIG_EFI_LOADER +#if 1 +extern int efi_variable_import(const char *buf, int check); +extern int efi_variable_export(env_t *env_out); +#endif +static int env_fat_efi_save(void) +{ + env_t __aligned(ARCH_DMA_MINALIGN) env_new; + struct blk_desc *dev_desc = NULL; + disk_partition_t info; + int dev, part; + int err; + loff_t size; + + err = efi_variable_export(&env_new); + if (err) + return err; + + part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE, + CONFIG_ENV_EFI_FAT_DEVICE_AND_PART, + &dev_desc, &info, 1); + if (part < 0) + return 1; + + dev = dev_desc->devnum; + if (fat_set_blk_dev(dev_desc, &info) != 0) { + /* + * This printf is embedded in the messages from env_save that + * will calling it. The missing \n is intentional. + */ + printf("Unable to use %s %d:%d... ", + CONFIG_ENV_FAT_INTERFACE, dev, part); + return 1; + } + + err = file_fat_write(CONFIG_ENV_EFI_FAT_FILE, + (void *)&env_new, 0, sizeof(env_t), &size); + if (err < 0) { + /* + * This printf is embedded in the messages from env_save that + * will calling it. The missing \n is intentional. + */ + printf("Unable to write \"%s\" from %s%d:%d... ", + CONFIG_ENV_EFI_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, + dev, part); + return 1; + } + + return 0; +} + +static int env_fat_efi_load(void) +{ + ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_EFI_SIZE); + struct blk_desc *dev_desc = NULL; + disk_partition_t info; + int dev, part; + int err; + +#ifdef CONFIG_MMC + if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc")) + mmc_initialize(NULL); +#endif + + part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE, + CONFIG_ENV_EFI_FAT_DEVICE_AND_PART, + &dev_desc, &info, 1); + if (part < 0) + goto err_env_relocate; + + dev = dev_desc->devnum; + if (fat_set_blk_dev(dev_desc, &info) != 0) { + /* + * This printf is embedded in the messages from env_save that + * will calling it. The missing \n is intentional. + */ + printf("Unable to use %s %d:%d...\n", + CONFIG_ENV_FAT_INTERFACE, dev, part); + goto err_env_relocate; + } + + err = file_fat_read(CONFIG_ENV_EFI_FAT_FILE, buf, CONFIG_ENV_EFI_SIZE); + if (err <= 0 && (err != -ENOENT)) { + /* + * This printf is embedded in the messages from env_save that + * will calling it. The missing \n is intentional. + */ + printf("Unable to read \"%s\" from %s %d:%d...\n", + CONFIG_ENV_EFI_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, + dev, part); + goto err_env_relocate; + } + + if (err > 0) + return efi_variable_import(buf, 1); + else + return 0; + +err_env_relocate: + + return -EIO; +} +#endif /* CONFIG_EFI_LOADER */ + U_BOOT_ENV_LOCATION(fat) = { .location = ENVL_FAT, ENV_NAME("FAT") @@ -137,4 +242,8 @@ U_BOOT_ENV_LOCATION(fat) = { #ifdef CMD_SAVEENV .save = env_save_ptr(env_fat_save), #endif +#ifdef CONFIG_EFI_LOADER + .efi_load = env_fat_efi_load, + .efi_save = env_fat_efi_save, +#endif }; diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 78dcf40bff48..8c4d56c346f3 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -51,6 +51,7 @@ typedef struct global_data { unsigned long env_valid; /* Environment valid? enum env_valid */ unsigned long env_has_init; /* Bitmask of boolean of struct env_location offsets */ int env_load_prio; /* Priority of the loaded environment */ + int env_efi_prio; /* Priority of the UEFI variables */ unsigned long ram_base; /* Base address of RAM used by U-Boot */ unsigned long ram_top; /* Top address of RAM used by U-Boot */ diff --git a/include/environment.h b/include/environment.h index cd966761416e..f62399863ef9 100644 --- a/include/environment.h +++ b/include/environment.h @@ -200,6 +200,7 @@ enum env_operation { ENVOP_INIT, /* we want to call the init function */ ENVOP_LOAD, /* we want to call the load function */ ENVOP_SAVE, /* we want to call the save function */ + ENVOP_EFI, /* we want to call the efi_load/save function */ }; struct env_driver { @@ -225,6 +226,24 @@ struct env_driver { */ int (*save)(void); + /** + * efi_load() - Load UEFI non-volatile variables from storage + * + * This method is required for UEFI non-volatile variables + * + * @return 0 if OK, -ve on error + */ + int (*efi_load)(void); + + /** + * efi_save() - Save UEFI non-volatile variables to storage + * + * This method is required for UEFI non-volatile variables + * + * @return 0 if OK, -ve on error + */ + int (*efi_save)(void); + /** * init() - Set up the initial pre-relocation environment * @@ -312,6 +331,11 @@ void eth_parse_enetaddr(const char *addr, uint8_t *enetaddr); int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr); int eth_env_set_enetaddr(const char *name, const uint8_t *enetaddr); +#ifdef CONFIG_EFI_LOADER +int env_efi_load(void); +int env_efi_save(void); +#endif + #endif /* DO_DEPS_ONLY */ #endif /* _ENVIRONMENT_H_ */ -- 2.20.1