From 4e669d598468de885e5b2d555df62fb83f1a7e20 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Wed, 26 Feb 2025 16:35:45 -0600 Subject: [PATCH 01/19] xilinx: dfu: Fill directly update_info.dfu_string Directly fill update_info.dfu_string to prepare platforms to switch from using dfu_alt_info variable to dfu_string which contains description for capsule update when switch is done. Signed-off-by: Michal Simek Reviewed-by: Mattijs Korpershoek Acked-by: Ilias Apalodimas --- board/xilinx/versal/board.c | 3 +++ board/xilinx/zynq/board.c | 3 +++ board/xilinx/zynqmp/zynqmp.c | 3 +++ 3 files changed, 9 insertions(+) diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c index b4483d00ad1..2c387630a61 100644 --- a/board/xilinx/versal/board.c +++ b/board/xilinx/versal/board.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -438,5 +439,7 @@ void set_dfu_alt_info(char *interface, char *devstr) env_set("dfu_alt_info", buf); puts("DFU alt info setting: done\n"); + update_info.dfu_string = strdup(buf); + debug("Capsule DFU: %s\n", update_info.dfu_string); } #endif diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 8dbfa560423..b5754e6c0bb 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -201,5 +202,7 @@ void set_dfu_alt_info(char *interface, char *devstr) env_set("dfu_alt_info", buf); puts("DFU alt info setting: done\n"); + update_info.dfu_string = strdup(buf); + debug("Capsule DFU: %s\n", update_info.dfu_string); } #endif diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 820fb252a3f..8060d54428d 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -734,6 +735,8 @@ void set_dfu_alt_info(char *interface, char *devstr) env_set("dfu_alt_info", buf); puts("DFU alt info setting: done\n"); + update_info.dfu_string = strdup(buf); + debug("Capsule DFU: %s\n", update_info.dfu_string); } #endif From 546152624f46555b71d6478b9ecb0db67ae43ba6 Mon Sep 17 00:00:00 2001 From: Jonathan Humphreys Date: Wed, 26 Feb 2025 16:35:46 -0600 Subject: [PATCH 02/19] efi_firmware: set EFI capsule dfu_alt_info env explicitly The current implementation of EFI capsule update uses set_dfu_alt_info() to set the dfu_alt_info environment variable with the settings it requires. However, set_dfu_alt_info() is doing this for all DFU operations, even those unrelated to capsule update. Thus other uses of DFU, such as DFU boot which sets its own value for the dfu_alt_info environment variable, will have that setting overwritten with the capsule update setting. Similarly, any user defined value for the dfu_alt_info environment variable would get overwritten when any DFU operation was performed, including simply performing a "dfu 0 list" command. The solution is stop using the set_dfu_alt_info() mechanism to set the dfu_alt_info environment variable and instead explicitly set it to the capsule update's setting just before performing the capsule update's DFU operation, and then restore the environment variable back to its original value. This patch implements the explicit setting and restoring of the dfu_alt_info environment variable as part of the EFI capsule update operation. The fix is fully implemented in a subsequent patch that removes the capsule update dfu_alt_info support in set_dfu_alt_info(). Signed-off-by: Jonathan Humphreys Reviewed-by: Mattijs Korpershoek Reviewed-by: Ilias Apalodimas --- lib/efi_loader/efi_firmware.c | 51 ++++++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index 5a754c9cd03..0ffaf5c8f72 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -649,8 +649,10 @@ efi_status_t EFIAPI efi_firmware_fit_set_image( efi_status_t (*progress)(efi_uintn_t completion), u16 **abort_reason) { + int ret; efi_status_t status; struct fmp_state state = { 0 }; + char *orig_dfu_env; EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image, image_size, vendor_code, progress, abort_reason); @@ -663,7 +665,28 @@ efi_status_t EFIAPI efi_firmware_fit_set_image( if (status != EFI_SUCCESS) return EFI_EXIT(status); - if (fit_update(image)) + orig_dfu_env = env_get("dfu_alt_info"); + if (orig_dfu_env) { + orig_dfu_env = strdup(orig_dfu_env); + if (!orig_dfu_env) { + log_err("strdup() failed!\n"); + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + } + } + if (env_set("dfu_alt_info", update_info.dfu_string)) { + log_err("Unable to set env variable \"dfu_alt_info\"!\n"); + free(orig_dfu_env); + return EFI_EXIT(EFI_DEVICE_ERROR); + } + + ret = fit_update(image); + + if (env_set("dfu_alt_info", orig_dfu_env)) + log_warning("Unable to restore env variable \"dfu_alt_info\". Further DFU operations may fail!\n"); + + free(orig_dfu_env); + + if (ret) return EFI_EXIT(EFI_DEVICE_ERROR); efi_firmware_set_fmp_state_var(&state, image_index); @@ -717,6 +740,7 @@ efi_status_t EFIAPI efi_firmware_raw_set_image( u8 dfu_alt_num; efi_status_t status; struct fmp_state state = { 0 }; + char *orig_dfu_env; EFI_ENTRY("%p %d %p %zu %p %p %p\n", this, image_index, image, image_size, vendor_code, progress, abort_reason); @@ -747,8 +771,29 @@ efi_status_t EFIAPI efi_firmware_raw_set_image( } } - if (dfu_write_by_alt(dfu_alt_num, (void *)image, image_size, - NULL, NULL)) + orig_dfu_env = env_get("dfu_alt_info"); + if (orig_dfu_env) { + orig_dfu_env = strdup(orig_dfu_env); + if (!orig_dfu_env) { + log_err("strdup() failed!\n"); + return EFI_EXIT(EFI_OUT_OF_RESOURCES); + } + } + if (env_set("dfu_alt_info", update_info.dfu_string)) { + log_err("Unable to set env variable \"dfu_alt_info\"!\n"); + free(orig_dfu_env); + return EFI_EXIT(EFI_DEVICE_ERROR); + } + + ret = dfu_write_by_alt(dfu_alt_num, (void *)image, image_size, + NULL, NULL); + + if (env_set("dfu_alt_info", orig_dfu_env)) + log_warning("Unable to restore env variable \"dfu_alt_info\". Further DFU operations may fail!\n"); + + free(orig_dfu_env); + + if (ret) return EFI_EXIT(EFI_DEVICE_ERROR); efi_firmware_set_fmp_state_var(&state, image_index); From 6f7fb8d29f26e8d67bde9717f4679e2df45724bc Mon Sep 17 00:00:00 2001 From: Jonathan Humphreys Date: Wed, 26 Feb 2025 16:35:47 -0600 Subject: [PATCH 03/19] board: remove capsule update support in set_dfu_alt_info() Now that capsule update sets the dfu_alt_info environment variable explicitly, there is no need to support it in the set_dfu_alt_info() function. Decouple SET_DFU_ALT_INFO from EFI_CAPSULE_FIRMWARE_FIT and EFI_CAPSULE_FIRMWARE_RAW. For many boards, this was the only use of set_dfu_alt_info() so remove the function entirely. Fixes: a9e6f01a941f ("efi: Define set_dfu_alt_info() for boards with UEFI capsule update enabled") Signed-off-by: Jonathan Humphreys Signed-off-by: Michal Simek Reviewed-by: Mattijs Korpershoek Reviewed-by: Neil Armstrong # for board/libre-computer/* Reviewed-by: Ilias Apalodimas Reviewed-by: Wadim Egorov # for --- board/beagle/beagleboneai64/beagleboneai64.c | 8 -------- board/beagle/beagleplay/beagleplay.c | 8 -------- board/libre-computer/aml-a311d-cc/aml-a311d-cc.c | 2 -- board/libre-computer/aml-s805x-ac/aml-s805x-ac.c | 2 -- board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c | 2 -- board/phytec/common/k3/board.c | 8 -------- board/ti/am62px/evm.c | 8 -------- board/ti/am62x/evm.c | 8 -------- board/ti/am64x/evm.c | 8 -------- board/ti/j721e/evm.c | 8 -------- board/ti/j784s4/evm.c | 8 -------- board/xilinx/common/board.h | 3 +++ board/xilinx/versal/board.c | 13 ++++--------- board/xilinx/zynq/board.c | 13 ++++--------- board/xilinx/zynqmp/zynqmp.c | 13 ++++--------- lib/efi_loader/Kconfig | 2 -- lib/efi_loader/efi_firmware.c | 5 ----- 17 files changed, 15 insertions(+), 104 deletions(-) diff --git a/board/beagle/beagleboneai64/beagleboneai64.c b/board/beagle/beagleboneai64/beagleboneai64.c index e8d07f1f95f..99eb8972cf3 100644 --- a/board/beagle/beagleboneai64/beagleboneai64.c +++ b/board/beagle/beagleboneai64/beagleboneai64.c @@ -45,14 +45,6 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - int board_init(void) { return 0; diff --git a/board/beagle/beagleplay/beagleplay.c b/board/beagle/beagleplay/beagleplay.c index fae69b37585..78635810585 100644 --- a/board/beagle/beagleplay/beagleplay.c +++ b/board/beagle/beagleplay/beagleplay.c @@ -41,14 +41,6 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - int board_init(void) { return 0; diff --git a/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c b/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c index 294f78858a7..b3b78bfd0ea 100644 --- a/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c +++ b/board/libre-computer/aml-a311d-cc/aml-a311d-cc.c @@ -31,8 +31,6 @@ void set_dfu_alt_info(char *interface, char *devstr) { if (interface && strcmp(interface, "ram") == 0) env_set("dfu_alt_info", "fitimage ram 0x08080000 0x4000000"); - else if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); } #endif diff --git a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c index 1ec9a5b401e..daece299848 100644 --- a/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c +++ b/board/libre-computer/aml-s805x-ac/aml-s805x-ac.c @@ -38,8 +38,6 @@ void set_dfu_alt_info(char *interface, char *devstr) { if (interface && strcmp(interface, "ram") == 0) env_set("dfu_alt_info", "fitimage ram 0x08080000 0x4000000"); - else if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); } #endif diff --git a/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c b/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c index b552035ee03..09a69b090ab 100644 --- a/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c +++ b/board/libre-computer/aml-s905d3-cc/aml-s905d3-cc.c @@ -31,8 +31,6 @@ void set_dfu_alt_info(char *interface, char *devstr) { if (interface && strcmp(interface, "ram") == 0) env_set("dfu_alt_info", "fitimage ram 0x08080000 0x4000000"); - else if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); } #endif diff --git a/board/phytec/common/k3/board.c b/board/phytec/common/k3/board.c index 7d2146d5727..828973a8e28 100644 --- a/board/phytec/common/k3/board.c +++ b/board/phytec/common/k3/board.c @@ -82,14 +82,6 @@ static void configure_capsule_updates(void) } #endif -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - #if IS_ENABLED(CONFIG_ENV_IS_IN_FAT) || IS_ENABLED(CONFIG_ENV_IS_IN_MMC) int mmc_get_env_dev(void) { diff --git a/board/ti/am62px/evm.c b/board/ti/am62px/evm.c index 75359fa1614..379d1a5b316 100644 --- a/board/ti/am62px/evm.c +++ b/board/ti/am62px/evm.c @@ -41,14 +41,6 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - int board_init(void) { return 0; diff --git a/board/ti/am62x/evm.c b/board/ti/am62x/evm.c index 279ceba9554..3051a0a27a1 100644 --- a/board/ti/am62x/evm.c +++ b/board/ti/am62x/evm.c @@ -74,14 +74,6 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - int board_init(void) { return 0; diff --git a/board/ti/am64x/evm.c b/board/ti/am64x/evm.c index 6a17737d266..35fd30dbceb 100644 --- a/board/ti/am64x/evm.c +++ b/board/ti/am64x/evm.c @@ -54,14 +54,6 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - int board_init(void) { return 0; diff --git a/board/ti/j721e/evm.c b/board/ti/j721e/evm.c index 1fa78ff7b30..0525f6e6f97 100644 --- a/board/ti/j721e/evm.c +++ b/board/ti/j721e/evm.c @@ -65,14 +65,6 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - int board_init(void) { return 0; diff --git a/board/ti/j784s4/evm.c b/board/ti/j784s4/evm.c index d317f3eccbb..c6e46b7ee0e 100644 --- a/board/ti/j784s4/evm.c +++ b/board/ti/j784s4/evm.c @@ -40,14 +40,6 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; -#if IS_ENABLED(CONFIG_SET_DFU_ALT_INFO) -void set_dfu_alt_info(char *interface, char *devstr) -{ - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) - env_set("dfu_alt_info", update_info.dfu_string); -} -#endif - int board_init(void) { return 0; diff --git a/board/xilinx/common/board.h b/board/xilinx/common/board.h index 64d657673e9..cb86c4c5b91 100644 --- a/board/xilinx/common/board.h +++ b/board/xilinx/common/board.h @@ -18,4 +18,7 @@ bool board_detection(void); char *soc_name_decode(void); bool soc_detection(void); + +void configure_capsule_updates(void); + #endif /* BOARD_XILINX_COMMON_BOARD_H */ diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c index 2c387630a61..05530736751 100644 --- a/board/xilinx/versal/board.c +++ b/board/xilinx/versal/board.c @@ -281,6 +281,9 @@ int board_late_init(void) { int ret; + if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) + configure_capsule_updates(); + if (!(gd->flags & GD_FLG_ENV_DEFAULT)) { debug("Saved variables - Skipping\n"); return 0; @@ -357,8 +360,6 @@ enum env_location env_get_location(enum env_operation op, int prio) } #endif -#if defined(CONFIG_SET_DFU_ALT_INFO) - #define DFU_ALT_BUF_LEN SZ_1K static void mtd_found_part(u32 *base, u32 *size) @@ -386,7 +387,7 @@ static void mtd_found_part(u32 *base, u32 *size) } } -void set_dfu_alt_info(char *interface, char *devstr) +void configure_capsule_updates(void) { int bootseq = 0, len = 0; u32 multiboot = versal_multi_boot(); @@ -394,9 +395,6 @@ void set_dfu_alt_info(char *interface, char *devstr) ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); - if (env_get("dfu_alt_info")) - return; - memset(buf, 0, sizeof(buf)); multiboot = env_get_hex("multiboot", multiboot); @@ -437,9 +435,6 @@ void set_dfu_alt_info(char *interface, char *devstr) return; } - env_set("dfu_alt_info", buf); - puts("DFU alt info setting: done\n"); update_info.dfu_string = strdup(buf); debug("Capsule DFU: %s\n", update_info.dfu_string); } -#endif diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index b5754e6c0bb..5efef61fa8f 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -53,6 +53,9 @@ int board_late_init(void) char *new_targets; char *env_targets; + if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) + configure_capsule_updates(); + if (!(gd->flags & GD_FLG_ENV_DEFAULT)) { debug("Saved variables - Skipping\n"); return 0; @@ -166,17 +169,12 @@ enum env_location env_get_location(enum env_operation op, int prio) } } -#if defined(CONFIG_SET_DFU_ALT_INFO) - #define DFU_ALT_BUF_LEN SZ_1K -void set_dfu_alt_info(char *interface, char *devstr) +void configure_capsule_updates(void) { ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); - if (env_get("dfu_alt_info")) - return; - memset(buf, 0, sizeof(buf)); switch ((zynq_slcr_get_boot_mode()) & ZYNQ_BM_MASK) { @@ -200,9 +198,6 @@ void set_dfu_alt_info(char *interface, char *devstr) return; } - env_set("dfu_alt_info", buf); - puts("DFU alt info setting: done\n"); update_info.dfu_string = strdup(buf); debug("Capsule DFU: %s\n", update_info.dfu_string); } -#endif diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 8060d54428d..33205d4cf1d 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -527,6 +527,9 @@ int board_late_init(void) usb_ether_init(); #endif + if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) + configure_capsule_updates(); + multiboot = multi_boot(); if (multiboot >= 0) env_set_hex("multiboot", multiboot); @@ -632,8 +635,6 @@ enum env_location env_get_location(enum env_operation op, int prio) } #endif -#if defined(CONFIG_SET_DFU_ALT_INFO) - #define DFU_ALT_BUF_LEN SZ_1K static void mtd_found_part(u32 *base, u32 *size) @@ -661,15 +662,12 @@ static void mtd_found_part(u32 *base, u32 *size) } } -void set_dfu_alt_info(char *interface, char *devstr) +void configure_capsule_updates(void) { int multiboot, bootseq = 0, len = 0; ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); - if (env_get("dfu_alt_info")) - return; - memset(buf, 0, sizeof(buf)); multiboot = multi_boot(); @@ -733,12 +731,9 @@ void set_dfu_alt_info(char *interface, char *devstr) return; } - env_set("dfu_alt_info", buf); - puts("DFU alt info setting: done\n"); update_info.dfu_string = strdup(buf); debug("Capsule DFU: %s\n", update_info.dfu_string); } -#endif #if defined(CONFIG_SPL_SPI_LOAD) unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 6130af14337..7f02a83e2a2 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -305,7 +305,6 @@ config EFI_CAPSULE_FIRMWARE_FIT depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT select UPDATE_FIT select DFU - select SET_DFU_ALT_INFO select EFI_CAPSULE_FIRMWARE help Select this option if you want to enable firmware management protocol @@ -317,7 +316,6 @@ config EFI_CAPSULE_FIRMWARE_RAW depends on SANDBOX || (!SANDBOX && !EFI_CAPSULE_FIRMWARE_FIT) select DFU_WRITE_ALT select DFU - select SET_DFU_ALT_INFO select EFI_CAPSULE_FIRMWARE help Select this option if you want to enable firmware management protocol diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c index 0ffaf5c8f72..d44dc09813e 100644 --- a/lib/efi_loader/efi_firmware.c +++ b/lib/efi_loader/efi_firmware.c @@ -56,11 +56,6 @@ struct fmp_state { u32 last_attempt_status; /* not used */ }; -__weak void set_dfu_alt_info(char *interface, char *devstr) -{ - env_set("dfu_alt_info", update_info.dfu_string); -} - /** * efi_firmware_get_image_type_id - get image_type_id * @image_index: image index From 7b269a2bd64aae7fe51f03f8e0b7d50cc9a2faee Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 6 Mar 2025 07:31:24 -0700 Subject: [PATCH 04/19] efi_loader: Install the ACPI table from the bloblist When BLOBLIST_TABLES is used, the ACPI tables are not currently added to the list of EFI tables. While we don't want to create a new memory region, we do want to tell EFI about the tables. Fix this by covering this case. At some point the non-bloblist code can likely be removed. Signed-off-by: Simon Glass Fixes: 3da59ee9579 ("efi_loader: Avoid mapping the ACPI tables twice") Signed-off-by: Patrick Rudolph --- lib/efi_loader/efi_acpi.c | 40 ++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/lib/efi_loader/efi_acpi.c b/lib/efi_loader/efi_acpi.c index 4422b31ac6a..046986a7518 100644 --- a/lib/efi_loader/efi_acpi.c +++ b/lib/efi_loader/efi_acpi.c @@ -7,6 +7,7 @@ #define LOG_CATEGORY LOGC_EFI +#include #include #include #include @@ -34,25 +35,38 @@ efi_status_t efi_acpi_register(void) * add_u_boot_and_runtime(). At some point that function could create a * more detailed map. */ - if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) - return EFI_SUCCESS; + if (IS_ENABLED(CONFIG_BLOBLIST_TABLES)) { + int size; + void *tab = bloblist_get_blob(BLOBLISTT_ACPI_TABLES, &size); - /* Mark space used for tables */ - start = ALIGN_DOWN(gd->arch.table_start, EFI_PAGE_MASK); - end = ALIGN(gd->arch.table_end, EFI_PAGE_MASK); - ret = efi_add_memory_map(start, end - start, EFI_ACPI_RECLAIM_MEMORY); - if (ret != EFI_SUCCESS) - return ret; - if (gd->arch.table_start_high) { - start = ALIGN_DOWN(gd->arch.table_start_high, EFI_PAGE_MASK); - end = ALIGN(gd->arch.table_end_high, EFI_PAGE_MASK); + if (!tab) + return EFI_NOT_FOUND; + addr = map_to_sysmem(tab); + + ret = efi_add_memory_map(addr, size, + EFI_ACPI_RECLAIM_MEMORY); + if (ret != EFI_SUCCESS) + return ret; + } else { + /* Mark space used for tables */ + start = ALIGN_DOWN(gd->arch.table_start, EFI_PAGE_MASK); + end = ALIGN(gd->arch.table_end, EFI_PAGE_MASK); ret = efi_add_memory_map(start, end - start, EFI_ACPI_RECLAIM_MEMORY); if (ret != EFI_SUCCESS) return ret; - } + if (gd->arch.table_start_high) { + start = ALIGN_DOWN(gd->arch.table_start_high, + EFI_PAGE_MASK); + end = ALIGN(gd->arch.table_end_high, EFI_PAGE_MASK); + ret = efi_add_memory_map(start, end - start, + EFI_ACPI_RECLAIM_MEMORY); + if (ret != EFI_SUCCESS) + return ret; + } - addr = gd_acpi_start(); + addr = gd_acpi_start(); + } log_debug("EFI using ACPI tables at %lx\n", addr); /* And expose them to our EFI payload */ From e8660b23f4929fc787e917f3b5f9cd1d09b93e84 Mon Sep 17 00:00:00 2001 From: Pawel Kochanowski Date: Tue, 18 Mar 2025 10:22:18 +0100 Subject: [PATCH 05/19] efi: Make FDT extra space configurable U-Boot currently reserves only 0x3000 bytes when copying the FDT in copy_fdt(), which may not be sufficient if additional nodes (such as FMAN firmware) are added later. This patch uses the exisitng SYS_FDT_PAD to reserve space for FDT fixup instead of hardcoded value. This change prevents potential corruption when resizing FDT after EFI boot, especially when firmware like FMAN requires additional space. Signed-off-by: Gabriel Nesteruk Signed-off-by: Pawel Kochanowski Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_dt_fixup.c | 2 +- lib/efi_loader/efi_helper.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index 26928cfc454..544e1aa9808 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -168,7 +168,7 @@ efi_dt_fixup(struct efi_dt_fixup_protocol *this, void *dtb, /* Check size */ required_size = fdt_off_dt_strings(dtb) + fdt_size_dt_strings(dtb) + - 0x3000; + CONFIG_SYS_FDT_PAD; total_size = fdt_totalsize(dtb); if (required_size < total_size) required_size = total_size; diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 8c32059edda..3936139ca41 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -485,7 +485,7 @@ static efi_status_t copy_fdt(void **fdtp) * needs to be expanded later. */ fdt = *fdtp; - fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000); + fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + CONFIG_SYS_FDT_PAD); fdt_size = fdt_pages << EFI_PAGE_SHIFT; ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, From 73c9a352705a29e3af6ea08c7075efeb12980f1d Mon Sep 17 00:00:00 2001 From: Adriano Cordova Date: Wed, 19 Mar 2025 11:44:59 -0300 Subject: [PATCH 06/19] efi_loader: efi_load_initrd: provide a memory mapped initrd U-Boot can pass an initrd to subsequent boot stages via the EFI_LOAD_FILE2_PROTOCOL. The current implementation only supports this functionality via the efi boot manager: the initrd is taken from the load options of the BootCurrent variable. This commit adds support for registering a memory mapped initrd, e.g. loaded from a FIT image. For now this new method takes precedence over loading the initrd from the BootCurrent variable (if both are present) because the BootCurrent variable is not cleared on exiting the boot manager. Signed-off-by: Adriano Cordova Reviewed-by: Ilias Apalodimas --- include/efi_loader.h | 2 +- lib/efi_loader/efi_bootmgr.c | 2 +- lib/efi_loader/efi_load_initrd.c | 71 +++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 5f769786786..72bee60abaf 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -667,7 +667,7 @@ efi_status_t efi_http_register(const efi_handle_t handle, struct efi_service_binding_protocol *http_service_binding); /* Called by bootefi to make the watchdog available */ efi_status_t efi_watchdog_register(void); -efi_status_t efi_initrd_register(void); +efi_status_t efi_initrd_register(struct efi_device_path *dp_initrd); efi_status_t efi_initrd_deregister(void); /* Called by bootefi to make SMBIOS tables available */ /** diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index f9534ef85ed..2791afa02a9 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -685,7 +685,7 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, /* try to register load file2 for initrd's */ if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) { - ret = efi_initrd_register(); + ret = efi_initrd_register(NULL); if (ret != EFI_SUCCESS) goto error; } diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c index fb8cc7bcbe3..b5d58943a80 100644 --- a/lib/efi_loader/efi_load_initrd.c +++ b/lib/efi_loader/efi_load_initrd.c @@ -42,6 +42,7 @@ static const struct efi_lo_dp_prefix dp_lf2_handle = { }; static efi_handle_t efi_initrd_handle; +static struct efi_device_path *efi_initrd_dp; /** * get_initrd_fp() - Get initrd device path from a FilePathList device path @@ -72,6 +73,41 @@ static efi_status_t get_initrd_fp(struct efi_device_path **initrd_fp) return EFI_SUCCESS; } +/** + * efi_initrd_from_mem() - load initial RAM disk from memory + * + * This function copies the initrd from the memory mapped device + * path pointed to by efi_initrd_dp + * + * @buffer_size: size of allocated buffer + * @buffer: buffer to load the file + * + * Return: status code + */ +static efi_status_t efi_initrd_from_mem(efi_uintn_t *buffer_size, void *buffer) +{ + efi_status_t ret = EFI_NOT_FOUND; + efi_uintn_t bs; + struct efi_device_path_memory *mdp; + + mdp = (struct efi_device_path_memory *)efi_initrd_dp; + if (!mdp) + return ret; + + bs = mdp->end_address - mdp->start_address; + + if (!buffer || *buffer_size < bs) { + ret = EFI_BUFFER_TOO_SMALL; + *buffer_size = bs; + } else { + memcpy(buffer, (void *)(uintptr_t)mdp->start_address, bs); + *buffer_size = bs; + ret = EFI_SUCCESS; + } + + return ret; +} + /** * efi_load_file2_initrd() - load initial RAM disk * @@ -118,6 +154,9 @@ efi_load_file2_initrd(struct efi_load_file_protocol *this, goto out; } + if (efi_initrd_dp) + return EFI_EXIT(efi_initrd_from_mem(buffer_size, buffer)); + ret = get_initrd_fp(&initrd_fp); if (ret != EFI_SUCCESS) goto out; @@ -209,6 +248,9 @@ efi_status_t efi_initrd_deregister(void) NULL); efi_initrd_handle = NULL; + efi_free_pool(efi_initrd_dp); + efi_initrd_dp = NULL; + return ret; } @@ -234,24 +276,31 @@ static void EFIAPI efi_initrd_return_notify(struct efi_event *event, * This function creates a new handle and installs a Linux specific vendor * device path and an EFI_LOAD_FILE2_PROTOCOL. Linux uses the device path * to identify the handle and then calls the LoadFile service of the - * EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk. + * EFI_LOAD_FILE2_PROTOCOL to read the initial RAM disk. If dp_initrd is + * not provided, the initrd will be taken from the BootCurrent variable + * + * @dp_initrd: optional device path containing an initrd * * Return: status code */ -efi_status_t efi_initrd_register(void) +efi_status_t efi_initrd_register(struct efi_device_path *dp_initrd) { efi_status_t ret; struct efi_event *event; - /* - * Allow the user to continue if Boot#### file path is not set for - * an initrd - */ - ret = check_initrd(); - if (ret == EFI_INVALID_PARAMETER) - return EFI_SUCCESS; - if (ret != EFI_SUCCESS) - return ret; + if (dp_initrd) { + efi_initrd_dp = dp_initrd; + } else { + /* + * Allow the user to continue if Boot#### file path is not set for + * an initrd + */ + ret = check_initrd(); + if (ret == EFI_INVALID_PARAMETER) + return EFI_SUCCESS; + if (ret != EFI_SUCCESS) + return ret; + } ret = efi_install_multiple_protocol_interfaces(&efi_initrd_handle, /* initramfs */ From 36835a9105cf14a72556731e54300f8225190b17 Mon Sep 17 00:00:00 2001 From: Adriano Cordova Date: Wed, 19 Mar 2025 11:45:00 -0300 Subject: [PATCH 07/19] efi_loader: binary_run: register an initrd Add support to install an initrd when running an EFI binary with efi_binary_run Signed-off-by: Adriano Cordova Acked-by: Ilias Apalodimas --- boot/bootm_os.c | 3 ++- cmd/bootefi.c | 2 +- include/efi_loader.h | 2 +- lib/efi_loader/efi_bootbin.c | 20 +++++++++++++++++--- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/boot/bootm_os.c b/boot/bootm_os.c index e9522cd3299..f403f352be1 100644 --- a/boot/bootm_os.c +++ b/boot/bootm_os.c @@ -507,7 +507,8 @@ static int do_bootm_efi(int flag, struct bootm_info *bmi) ret = efi_binary_run(image_buf, images->os.image_len, images->ft_len - ? images->ft_addr : EFI_FDT_USE_INTERNAL); + ? images->ft_addr : EFI_FDT_USE_INTERNAL, + NULL, 0); return ret; } diff --git a/cmd/bootefi.c b/cmd/bootefi.c index c1454ffb948..dce8285b047 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -211,7 +211,7 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, } } - ret = efi_binary_run(image_buf, size, fdt); + ret = efi_binary_run(image_buf, size, fdt, NULL, 0); if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; diff --git a/include/efi_loader.h b/include/efi_loader.h index 72bee60abaf..144b749278a 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -600,7 +600,7 @@ efi_status_t efi_install_fdt(void *fdt); /* Execute loaded UEFI image */ efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options); /* Run loaded UEFI image with given fdt */ -efi_status_t efi_binary_run(void *image, size_t size, void *fdt); +efi_status_t efi_binary_run(void *image, size_t size, void *fdt, void *initrd, size_t initrd_sz); /** * efi_bootflow_run() - Run a bootflow containing an EFI application diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c index deafb2ce1c2..2cf972343a4 100644 --- a/lib/efi_loader/efi_bootbin.c +++ b/lib/efi_loader/efi_bootbin.c @@ -204,6 +204,8 @@ out: * @image: memory address of the UEFI image * @size: size of the UEFI image * @fdt: device-tree + * @initrd: initrd + * @initrd_sz: initrd size * @dp_dev: EFI device-path * @dp_img: EFI image-path * @@ -213,10 +215,12 @@ out: * Return: status code */ static efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt, + void *initrd, size_t initd_sz, struct efi_device_path *dp_dev, struct efi_device_path *dp_img) { efi_status_t ret; + struct efi_device_path *dp_initrd; /* Initialize EFI drivers */ ret = efi_init_obj_list(); @@ -230,6 +234,14 @@ static efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt, if (ret != EFI_SUCCESS) return ret; + dp_initrd = efi_dp_from_mem(EFI_LOADER_DATA, (uintptr_t)initrd, initd_sz); + if (!dp_initrd) + return EFI_OUT_OF_RESOURCES; + + ret = efi_initrd_register(dp_initrd); + if (ret != EFI_SUCCESS) + return ret; + return efi_run_image(image, size, dp_dev, dp_img); } @@ -239,13 +251,15 @@ static efi_status_t efi_binary_run_dp(void *image, size_t size, void *fdt, * @image: memory address of the UEFI image * @size: size of the UEFI image * @fdt: device-tree + * @initrd: initrd + * @initrd_sz: initrd size * * Execute an EFI binary image loaded at @image. * @size may be zero if the binary is loaded with U-Boot load command. * * Return: status code */ -efi_status_t efi_binary_run(void *image, size_t size, void *fdt) +efi_status_t efi_binary_run(void *image, size_t size, void *fdt, void *initrd, size_t initrd_sz) { efi_handle_t mem_handle = NULL; struct efi_device_path *file_path = NULL; @@ -273,7 +287,7 @@ efi_status_t efi_binary_run(void *image, size_t size, void *fdt) log_debug("Loaded from disk\n"); } - ret = efi_binary_run_dp(image, size, fdt, bootefi_device_path, + ret = efi_binary_run_dp(image, size, fdt, initrd, initrd_sz, bootefi_device_path, bootefi_image_path); out: if (mem_handle) { @@ -355,7 +369,7 @@ efi_status_t efi_bootflow_run(struct bootflow *bflow) log_debug("Booting with external fdt\n"); fdt = map_sysmem(bflow->fdt_addr, 0); } - ret = efi_binary_run_dp(bflow->buf, bflow->size, fdt, device, image); + ret = efi_binary_run_dp(bflow->buf, bflow->size, fdt, NULL, 0, device, image); return ret; } From 3d8e1b7b2df4559fe2ae99ece13d066893f660ea Mon Sep 17 00:00:00 2001 From: Adriano Cordova Date: Wed, 19 Mar 2025 11:45:01 -0300 Subject: [PATCH 08/19] bootm: add support for initrd in do_bootm_efi Pass a pointer to a memory mapped initrd and its size to efi_binary_run. The EFI stack will register an EFI_LOAD_FILE2_PROTOCOL for the next boot stage to access this initrd. Signed-off-by: Adriano Cordova Reviewed-by: Ilias Apalodimas --- boot/bootm_os.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boot/bootm_os.c b/boot/bootm_os.c index f403f352be1..35a32f8c912 100644 --- a/boot/bootm_os.c +++ b/boot/bootm_os.c @@ -508,7 +508,8 @@ static int do_bootm_efi(int flag, struct bootm_info *bmi) ret = efi_binary_run(image_buf, images->os.image_len, images->ft_len ? images->ft_addr : EFI_FDT_USE_INTERNAL, - NULL, 0); + (void *)images->initrd_start, + (size_t)(images->initrd_end - images->initrd_start)); return ret; } From 70d5f6e21ee33693d2d34b8eede34c83d45663b8 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Fri, 21 Mar 2025 11:25:48 +0100 Subject: [PATCH 09/19] cmd: fwu: Dump custom fields from mdata structure The commit cb9ae40a16f0 ("tools: mkfwumdata: add logic to append vendor data to the FWU metadata") added support for adding vendor data to mdata structure but it is not visible anywhere that's why extend fwu command to dump it. Tested-by: Sughosh Ganu Reviewed-by: Sughosh Ganu Signed-off-by: Michal Simek --- cmd/Kconfig | 1 + cmd/fwu_mdata.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/cmd/Kconfig b/cmd/Kconfig index ecef664fcea..c2ce519d1e3 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -185,6 +185,7 @@ config CMD_UFETCH config CMD_FWU_METADATA bool "fwu metadata read" depends on FWU_MULTI_BANK_UPDATE + imply HEXDUMP if FWU_MDATA_V2 help Command to read the metadata and dump it's contents diff --git a/cmd/fwu_mdata.c b/cmd/fwu_mdata.c index 9c048d69a13..5b5a2e4d1cd 100644 --- a/cmd/fwu_mdata.c +++ b/cmd/fwu_mdata.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,30 @@ static void print_mdata(struct fwu_data *data) img_info->accepted == 0x1 ? "yes" : "no"); } } + + if (data->version == 2) { + struct fwu_mdata *mdata = data->fwu_mdata; + struct fwu_fw_store_desc *desc; + void *end; + u32 diff; + + /* + * fwu_mdata defines only header that's why taking it as array + * which exactly point to image description location + */ + desc = (struct fwu_fw_store_desc *)&mdata[1]; + + /* Number of entries is taken from for loop - variable i */ + end = &desc->img_entry[i]; + debug("mdata %p, desc %p, end %p\n", mdata, desc, end); + + diff = data->metadata_size - ((void *)end - (void *)mdata); + if (diff) { + printf("Custom fields covered by CRC len: 0x%x\n", diff); + print_hex_dump_bytes("CUSTOM ", DUMP_PREFIX_OFFSET, + end, diff); + } + } } int do_fwu_mdata_read(struct cmd_tbl *cmdtp, int flag, From 85403c46e681653ccc0a31755b51b13c8ac53714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Kohlschu=CC=88tter?= Date: Sun, 23 Mar 2025 20:03:03 +0100 Subject: [PATCH 10/19] efi: Fix efiboot for payloads loaded from memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling bootefi on an address that was loaded from memory (e.g., cramfs or SPI flash via "sf read", etc.), currently results in the EFI binary not being able to access the EFI image device path. For example, iPXE would fail with an error "EFI could not get loaded image's device path: Error 0x7f39e082 (https://ipxe.org/7f39e082)". This is due to an incomplete special-case in efi_binary_run, where a new device path was created but not used in all required places. Fix the in-memory special case, set the "bootefi_device_path" to the generated "file_path". iPXE will now boot, and report the device path as "/MemoryMapped(0x0,0xSTART,0xLEN)" Signed-off-by: Christian Kohlschütter Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_bootbin.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/efi_loader/efi_bootbin.c b/lib/efi_loader/efi_bootbin.c index 2cf972343a4..d0f7da309ce 100644 --- a/lib/efi_loader/efi_bootbin.c +++ b/lib/efi_loader/efi_bootbin.c @@ -283,6 +283,9 @@ efi_status_t efi_binary_run(void *image, size_t size, void *fdt, void *initrd, s file_path, NULL); if (ret != EFI_SUCCESS) goto out; + + bootefi_device_path = file_path; + bootefi_image_path = NULL; } else { log_debug("Loaded from disk\n"); } From 742aa8b0396dfeb39e60c88988b7db3d9694a09d Mon Sep 17 00:00:00 2001 From: Varadarajan Narayanan Date: Wed, 26 Mar 2025 11:16:53 +0530 Subject: [PATCH 11/19] efi_loader: Handle GD_FLG_SKIP_RELOC If the EFI runtime services pointers are relocated even though relocation is skipped, it corrupts some other data resulting in some unexpected behaviour. In this specific case, it overwrote some page table entries resulting in the device memory address range's mappings getting removed. Eventually, after the completion of efi_runtime_relocate(), when a driver tries to access its device's registers it crashes since the mappings are absent. Signed-off-by: Varadarajan Narayanan Reviewed-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- common/board_r.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/board_r.c b/common/board_r.c index 8d69db1875d..f12e0c848e7 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -169,7 +169,8 @@ static int initr_reloc_global_data(void) */ efi_save_gd(); - efi_runtime_relocate(gd->relocaddr, NULL); + if (!(gd->flags & GD_FLG_SKIP_RELOC)) + efi_runtime_relocate(gd->relocaddr, NULL); #endif /* From f5e0f2198ec1226b4fd0121439facc30cb886a2a Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Fri, 28 Mar 2025 14:58:18 +0200 Subject: [PATCH 12/19] efi_loader: Print extra information from the bootmgr Instead of just printing the label, add information for the Device path as well so it's easier to see if we are booting from disk, network etc Signed-off-by: Ilias Apalodimas --- lib/efi_loader/efi_bootmgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 2791afa02a9..c0df5cb9acd 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -690,7 +690,7 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle, goto error; } - log_info("Booting: %ls\n", lo.label); + log_info("Booting: Label: %ls Device path: %pD\n", lo.label, lo.file_path); /* Ignore the optional data in auto-generated boot options */ if (size >= sizeof(efi_guid_t) && From 2dc04803b05ff189619d46acd137a47bedaf6193 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Stehl=C3=A9?= Date: Tue, 1 Apr 2025 13:15:00 +0200 Subject: [PATCH 13/19] efi_loader: handle malloc() errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new_packagelist() function of the HII Protocols implementation is calling malloc() without checking its return code; fix this. Signed-off-by: Vincent Stehlé Cc: Heinrich Schuchardt Cc: Ilias Apalodimas Cc: Tom Rini Reviewed-by: Ilias Apalodimas --- lib/efi_loader/efi_hii.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/efi_loader/efi_hii.c b/lib/efi_loader/efi_hii.c index 44235970a7c..330d7c5830b 100644 --- a/lib/efi_loader/efi_hii.c +++ b/lib/efi_loader/efi_hii.c @@ -343,6 +343,9 @@ static struct efi_hii_packagelist *new_packagelist(void) struct efi_hii_packagelist *hii; hii = malloc(sizeof(*hii)); + if (!hii) + return NULL; + list_add_tail(&hii->link, &efi_package_lists); hii->max_string_id = 0; INIT_LIST_HEAD(&hii->string_tables); From fd58c275f6ba524101ba0990e53f5a11ac390bd0 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Tue, 1 Apr 2025 14:27:25 +0300 Subject: [PATCH 14/19] efi_loader: Move public cert for capsules to .rodata commit ddf67daac39d ("efi_capsule: Move signature from DTB to .rodata") was reverted in commit 47a25e81d35c ("Revert "efi_capsule: Move signature from DTB to .rodata"") because that's what U-Boot was usually doing -- using the DT to store configuration and data. Some of the discussions can be found here [0]. (Ab)using the device tree to store random data isn't ideal though. On top of that with new features introduced over the years, keeping the certificates in the DT has proven to be problematic. One of the reasons is that platforms might send U-Boot a DTB from the previous stage loader using a transfer list which won't contain the signatures since other loaders are not aware of internal U-Boot ABIs. On top of that QEMU creates the DTB on the fly, so adding the capsule certificate there does not work and requires users to dump it and re-create it injecting the public keys. Now that we have proper memory permissions for arm64, move the certificate to .rodata and read it from there. [0] https://lore.kernel.org/u-boot/CAPnjgZ2uM=n8Qo-a=DUkx5VW5Bzp5Xy8=Wgmrw8ESqUBK00YJQ@mail.gmail.com/ Signed-off-by: Ilias Apalodimas Tested-by: Jonathan Humphreys # on TI sk-am62p-lp Tested-by: Neil Armstrong # on AML-A311D-CC Tested-by: Raymond Mao --- Makefile | 2 +- include/asm-generic/sections.h | 2 ++ lib/efi_loader/Makefile | 18 +++++++++++++++ lib/efi_loader/capsule_esl.dtsi.in | 11 --------- lib/efi_loader/efi_capsule.c | 37 ++++++++---------------------- lib/efi_loader/efi_capsule_key.S | 17 ++++++++++++++ scripts/Makefile.lib | 27 ---------------------- 7 files changed, 47 insertions(+), 67 deletions(-) delete mode 100644 lib/efi_loader/capsule_esl.dtsi.in create mode 100644 lib/efi_loader/efi_capsule_key.S diff --git a/Makefile b/Makefile index e83672b1823..bb9ef67ddc8 100644 --- a/Makefile +++ b/Makefile @@ -2231,7 +2231,7 @@ CLEAN_FILES += include/autoconf.mk* include/bmp_logo.h include/bmp_logo_data.h \ itb.fit.fit itb.fit.itb itb.map spl.map mkimage-out.rom.mkimage \ mkimage.rom.mkimage mkimage-in-simple-bin* rom.map simple-bin* \ idbloader-spi.img lib/efi_loader/helloworld_efi.S *.itb \ - Test* capsule*.*.efi-capsule capsule*.map + Test* capsule*.*.efi-capsule capsule*.map capsule_esl_file # Directories & files removed with 'make mrproper' MRPROPER_DIRS += include/config include/generated spl tpl vpl \ diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 024b1adde27..d59787948fd 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -28,6 +28,8 @@ extern char __efi_helloworld_begin[]; extern char __efi_helloworld_end[]; extern char __efi_var_file_begin[]; extern char __efi_var_file_end[]; +extern char __efi_capsule_sig_begin[]; +extern char __efi_capsule_sig_end[]; /* Private data used by of-platdata devices/uclasses */ extern char __priv_data_start[], __priv_data_end[]; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 2a0b4172bd7..dc291214895 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -29,6 +29,7 @@ obj-y += efi_boottime.o obj-y += efi_helper.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o +obj-$(CONFIG_EFI_CAPSULE_AUTHENTICATE) += efi_capsule_key.o obj-y += efi_console.o obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o @@ -73,6 +74,23 @@ obj-$(CONFIG_EFI_ECPT) += efi_conformance.o EFI_VAR_SEED_FILE := $(subst $\",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) +ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) +capsule_crt_path=($(subst $(quote),,$(CONFIG_EFI_CAPSULE_CRT_FILE))) +capsule_crt_full=$(srctree)/$(subst $(quote),,$(CONFIG_EFI_CAPSULE_CRT_FILE)) +quiet_cmd_capsule_esl_gen = CAPSULE_ESL_GEN $@ +cmd_capsule_esl_gen = cert-to-efi-sig-list $(capsule_crt_full) $@ +$(srctree)/capsule_esl_file: FORCE + @if [ ! -e "$(capsule_crt_full)" ]; then \ + echo "ERROR: path $(capsule_crt_full) is invalid." >&2; \ + echo "EFI CONFIG_EFI_CAPSULE_CRT_FILE must be specified when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled." >&2; \ + exit 1; \ + fi + $(call cmd,capsule_esl_gen) + +$(obj)/efi_capsule.o: $(srctree)/capsule_esl_file FORCE +asflags-y += -DCAPSULE_ESL_PATH=\"$(srctree)/capsule_esl_file\" +endif + # Set the C flags to add and remove for each app $(foreach f,$(apps-y),\ $(eval CFLAGS_$(f).o := $(CFLAGS_EFI) -Os -ffreestanding)\ diff --git a/lib/efi_loader/capsule_esl.dtsi.in b/lib/efi_loader/capsule_esl.dtsi.in deleted file mode 100644 index bc7db836faa..00000000000 --- a/lib/efi_loader/capsule_esl.dtsi.in +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Devicetree file with the public key EFI Signature List(ESL) - * node. This file is used to generate the dtsi file to be - * included into the DTB. - */ -/ { - signature { - capsule-key = /incbin/("ESL_BIN_FILE"); - }; -}; diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index f8a4a7c6ef4..1aa52ac7bb6 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -284,33 +285,12 @@ out: } #if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE) -int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len) +static int efi_get_public_key_data(const void **pkey, efi_uintn_t *pkey_len) { - const void *fdt_blob = gd->fdt_blob; - const void *blob; - const char *cnode_name = "capsule-key"; - const char *snode_name = "signature"; - int sig_node; - int len; + const void *blob = __efi_capsule_sig_begin; + const int len = __efi_capsule_sig_end - __efi_capsule_sig_begin; - sig_node = fdt_subnode_offset(fdt_blob, 0, snode_name); - if (sig_node < 0) { - log_err("Unable to get signature node offset\n"); - - return -FDT_ERR_NOTFOUND; - } - - blob = fdt_getprop(fdt_blob, sig_node, cnode_name, &len); - - if (!blob || len < 0) { - log_err("Unable to get capsule-key value\n"); - *pkey = NULL; - *pkey_len = 0; - - return -FDT_ERR_NOTFOUND; - } - - *pkey = (void *)blob; + *pkey = blob; *pkey_len = len; return 0; @@ -321,7 +301,8 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s { u8 *buf; int ret; - void *fdt_pkey, *pkey; + void *pkey; + const void *stored_pkey; efi_uintn_t pkey_len; uint64_t monotonic_count; struct efi_signature_store *truststore; @@ -373,7 +354,7 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s goto out; } - ret = efi_get_public_key_data(&fdt_pkey, &pkey_len); + ret = efi_get_public_key_data(&stored_pkey, &pkey_len); if (ret < 0) goto out; @@ -381,7 +362,7 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s if (!pkey) goto out; - memcpy(pkey, fdt_pkey, pkey_len); + memcpy(pkey, stored_pkey, pkey_len); truststore = efi_build_signature_store(pkey, pkey_len); if (!truststore) goto out; diff --git a/lib/efi_loader/efi_capsule_key.S b/lib/efi_loader/efi_capsule_key.S new file mode 100644 index 00000000000..80cefbe16ae --- /dev/null +++ b/lib/efi_loader/efi_capsule_key.S @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * .esl cert for capsule authentication + * + * Copyright (c) 2021, Ilias Apalodimas + */ + +#include + +.section .rodata.capsule_key.init,"a" +.balign 16 +.global __efi_capsule_sig_begin +__efi_capsule_sig_begin: +.incbin CAPSULE_ESL_PATH +__efi_capsule_sig_end: +.global __efi_capsule_sig_end +.balign 16 diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 275c308154b..83fd5ff6c31 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -377,35 +377,8 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ ; \ sed "s:$(pre-tmp):$(<):" $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) -capsule_esl_input_file=$(srctree)/lib/efi_loader/capsule_esl.dtsi.in -capsule_crt_file=$(subst $(quote),,$(CONFIG_EFI_CAPSULE_CRT_FILE)) -capsule_esl_dtsi=.capsule_esl.dtsi - -quiet_cmd_capsule_esl_gen = CAPSULE_ESL_GEN $@ -cmd_capsule_esl_gen = cert-to-efi-sig-list $< $@ - -$(obj)/capsule_esl_file: $(capsule_crt_file) FORCE -ifeq ($(CONFIG_EFI_CAPSULE_CRT_FILE),"") - $(error "CONFIG_EFI_CAPSULE_CRT_FILE is empty, EFI capsule authentication \ - public key must be specified when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled") -else - $(call cmd,capsule_esl_gen) -endif - -quiet_cmd_capsule_dtsi_gen = CAPSULE_DTSI_GEN $@ -cmd_capsule_dtsi_gen = \ - $(shell sed "s:ESL_BIN_FILE:$(abspath $<):" $(capsule_esl_input_file) > $@) - -$(obj)/$(capsule_esl_dtsi): $(obj)/capsule_esl_file FORCE - $(call cmd,capsule_dtsi_gen) - dtsi_include_list_deps := $(addprefix $(u_boot_dtsi_loc),$(subst $(quote),,$(dtsi_include_list))) -ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE -dtsi_include_list += $(capsule_esl_dtsi) -dtsi_include_list_deps += $(obj)/$(capsule_esl_dtsi) -endif - ifneq ($(CHECK_DTBS),) DT_CHECKER ?= dt-validate DT_CHECKER_FLAGS ?= $(if $(DT_SCHEMA_FILES),-l $(DT_SCHEMA_FILES),-m) From 00cf654b29e62feddae01e4c47c7ec38932c5b7b Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Tue, 1 Apr 2025 14:27:26 +0300 Subject: [PATCH 15/19] doc: Update authenticated capsules documentation Now that we moved out the capsule signature from the DTB, remove the relevant documentation. Signed-off-by: Ilias Apalodimas --- doc/develop/uefi/uefi.rst | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index 48d6110b2ad..3ca22b572a9 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -597,21 +597,6 @@ and used by the steps highlighted below. [--fit | --raw | --guid -4. Insert the signature list into a device tree in the following format:: - - { - signature { - capsule-key = [ ]; - } - ... - } - -You can perform step-4 through the Kconfig symbol -CONFIG_EFI_CAPSULE_CRT_FILE. This symbol points to the signing key -generated in step-2. As part of U-Boot build, the ESL certificate file will -be generated from the signing key and automatically get embedded into the -platform's dtb. - Anti-rollback Protection ************************ From 93f3f143d6c24b103f8c7f6ef29dc5ebf7738974 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 7 Apr 2025 08:44:23 +0200 Subject: [PATCH 16/19] acpi: select CONFIG_BLOBLIST Since commit 53d5a221632e ("emulation: Use bloblist to hold tables") `make qemu-riscv64_smode_defconfig acpi.config && make` fails with qfw_acpi.c:146:(.text.evt_write_acpi_tables+0xc): undefined reference to `bloblist_add' Build with bloblist support. Fixes: 53d5a221632e ("emulation: Use bloblist to hold tables") Reviewed-by: Ilias Apalodimas Reviewed-by: Tom Rini Signed-off-by: Heinrich Schuchardt --- lib/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Kconfig b/lib/Kconfig index 17954461114..ac34ec45bb1 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -317,6 +317,7 @@ config SPL_ACPI config GENERATE_ACPI_TABLE bool "Generate an ACPI (Advanced Configuration and Power Interface) table" depends on ACPI + select BLOBLIST select QFW if QEMU help The Advanced Configuration and Power Interface (ACPI) specification From 253af704c5e44c76c1d2847e86ed9707e079ec71 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 7 Apr 2025 08:44:24 +0200 Subject: [PATCH 17/19] smbios: select CONFIG_BLOBLIST Since commit 53d5a221632e ("emulation: Use bloblist to hold tables") `make qemu-riscv64_smode_defconfig acpi.config && make` fails with drivers/misc/qfw_smbios.c:93:(.text.qfw_evt_write_smbios_tables+0xe): undefined reference to `bloblist_add' Build with bloblist support. Fixes: 53d5a221632e ("emulation: Use bloblist to hold tables") Reviewed-by: Ilias Apalodimas Reviewed-by: Tom Rini Signed-off-by: Heinrich Schuchardt --- drivers/misc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 834e0285097..0911d2fc0cc 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -576,6 +576,7 @@ config QFW_SMBIOS bool default y depends on QFW && SMBIOS && !SANDBOX && !SYSINFO_SMBIOS + select BLOBLIST help Hidden option to read SMBIOS tables from QEMU. From d8dcfeb778082530616d43a15c44baabc59b9dee Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 7 Apr 2025 08:59:24 +0200 Subject: [PATCH 18/19] doc/buildman: typo 'require' %s/require/required/ Signed-off-by: Heinrich Schuchardt --- tools/buildman/buildman.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/buildman/buildman.rst b/tools/buildman/buildman.rst index 924564b5700..07ecc5c110c 100644 --- a/tools/buildman/buildman.rst +++ b/tools/buildman/buildman.rst @@ -247,7 +247,7 @@ Setting up section is ignored. If more than one line is provided, only the last one is taken. -#. Make sure you have the require Python pre-requisites +#. Make sure you have the required Python pre-requisites Buildman uses multiprocessing, Queue, shutil, StringIO, ConfigParser and urllib2. These should normally be available, but if you get an error like From a73b854700abcf680379497c32b92aa39fed6270 Mon Sep 17 00:00:00 2001 From: Bryan Brattlof Date: Tue, 8 Apr 2025 01:06:58 -0500 Subject: [PATCH 19/19] efi_selftest: remove un-needed NULL checks Because we've already returned early in the event 'handle' is NULL we don't need these extra not NULL checks. Remove them Signed-off-by: Bryan Brattlof Reviewed-by: Heinrich Schuchardt --- lib/efi_selftest/efi_selftest_hii.c | 84 +++++++++++++---------------- 1 file changed, 36 insertions(+), 48 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_hii.c b/lib/efi_selftest/efi_selftest_hii.c index c363df466dc..228dc296950 100644 --- a/lib/efi_selftest/efi_selftest_hii.c +++ b/lib/efi_selftest/efi_selftest_hii.c @@ -609,14 +609,12 @@ static int test_hii_database_get_package_list_handle(void) result = EFI_ST_SUCCESS; out: - if (handle) { - ret = hii_database_protocol->remove_package_list( - hii_database_protocol, handle); - if (ret != EFI_SUCCESS) { - efi_st_error("remove_package_list returned %u\n", - (unsigned int)ret); - return EFI_ST_FAILURE; - } + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; } return result; @@ -711,14 +709,12 @@ static int test_hii_string_new_string(void) result = EFI_ST_SUCCESS; out: - if (handle) { - ret = hii_database_protocol->remove_package_list( - hii_database_protocol, handle); - if (ret != EFI_SUCCESS) { - efi_st_error("remove_package_list returned %u\n", - (unsigned int)ret); - return EFI_ST_FAILURE; - } + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; } return result; @@ -792,14 +788,12 @@ static int test_hii_string_get_string(void) result = EFI_ST_SUCCESS; out: - if (handle) { - ret = hii_database_protocol->remove_package_list( - hii_database_protocol, handle); - if (ret != EFI_SUCCESS) { - efi_st_error("remove_package_list returned %u\n", - (unsigned int)ret); - return EFI_ST_FAILURE; - } + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; } return result; @@ -851,14 +845,12 @@ static int test_hii_string_set_string(void) result = EFI_ST_SUCCESS; out: - if (handle) { - ret = hii_database_protocol->remove_package_list( - hii_database_protocol, handle); - if (ret != EFI_SUCCESS) { - efi_st_error("remove_package_list returned %u\n", - (unsigned int)ret); - return EFI_ST_FAILURE; - } + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; } return result; @@ -918,14 +910,12 @@ static int test_hii_string_get_languages(void) result = EFI_ST_SUCCESS; out: - if (handle) { - ret = hii_database_protocol->remove_package_list( - hii_database_protocol, handle); - if (ret != EFI_SUCCESS) { - efi_st_error("remove_package_list returned %u\n", - (unsigned int)ret); - return EFI_ST_FAILURE; - } + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; } return result; @@ -991,14 +981,12 @@ static int test_hii_string_get_secondary_languages(void) result = EFI_ST_SUCCESS; out: - if (handle) { - ret = hii_database_protocol->remove_package_list( - hii_database_protocol, handle); - if (ret != EFI_SUCCESS) { - efi_st_error("remove_package_list returned %u\n", - (unsigned int)ret); - return EFI_ST_FAILURE; - } + ret = hii_database_protocol->remove_package_list( + hii_database_protocol, handle); + if (ret != EFI_SUCCESS) { + efi_st_error("remove_package_list returned %u\n", + (unsigned int)ret); + return EFI_ST_FAILURE; } return result;