[PATCH v2 0/4] efi_loader: prepare for FIT images

A patch series has been suggested to provide secure UEFI boot via FIT images.
This patch series exports the functions needed for the implementation.
v2: Resend the efi_install_fdt() rework patches. Export the efi_run_image() and efi_install_fdt().
Heinrich Schuchardt (4): efi_loader: pass address to efi_install_fdt() efi_loader: use hardware device tree by default efi_loader: carve out efi_run_image() efi_loader: export efi_install_fdt()
cmd/bootefi.c | 101 ++++++++++++++++++++++++++----------------- include/efi_loader.h | 7 +++ 2 files changed, 69 insertions(+), 39 deletions(-)
-- 2.24.0

As part of moving the parsing of command line arguments to do_bootefi() call efi_install_fdt() with the address of the device tree instead of a string.
If the address is EFI_FDT_USE_INTERNAL (= 0), the internal device tree is used.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- cmd/bootefi.c | 32 ++++++++++++++++++-------------- include/efi_loader.h | 3 +++ 2 files changed, 21 insertions(+), 14 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index f613cce7e2..2b190a3edd 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -196,40 +196,39 @@ static void *get_config_table(const efi_guid_t *guid) #endif /* !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) */
/** - * efi_install_fdt() - install fdt passed by a command argument + * efi_install_fdt() - install device tree * - * If fdt_opt is available, the device tree located at that memory address will + * If fdt_addr is available, the device tree located at that memory address will * will be installed as configuration table, otherwise the device tree located * at the address indicated by environment variable fdtcontroladdr will be used. * - * On architectures (x86) using ACPI tables device trees shall not be installed - * as configuration table. + * On architectures using ACPI tables device trees shall not be installed as + * configuration table. * - * @fdt_opt: pointer to argument + * @fdt_addr: address of device tree or EFI_FDT_USE_INTERNAL to use the + * internal device tree as indicated by environment variable + * fdtcontroladdr * Return: status code */ -static efi_status_t efi_install_fdt(const char *fdt_opt) +static efi_status_t efi_install_fdt(uintptr_t fdt_addr) { /* * The EBBR spec requires that we have either an FDT or an ACPI table * but not both. */ #if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) - if (fdt_opt) { + if (fdt_addr) { printf("ERROR: can't have ACPI table and device tree.\n"); return EFI_LOAD_ERROR; } #else - unsigned long fdt_addr; void *fdt; bootm_headers_t img = { 0 }; efi_status_t ret;
- if (fdt_opt) { - fdt_addr = simple_strtoul(fdt_opt, NULL, 16); - if (!fdt_addr) - return EFI_INVALID_PARAMETER; - } else { + if (fdt_addr == EFI_FDT_USE_INTERNAL) { + const char *fdt_opt; + /* Look for device tree that is already installed */ if (get_config_table(&efi_guid_fdt)) return EFI_SUCCESS; @@ -556,6 +555,7 @@ static int do_efi_selftest(void) static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { efi_status_t ret; + uintptr_t fdt_addr;
if (argc < 2) return CMD_RET_USAGE; @@ -568,7 +568,11 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_FAILURE; }
- ret = efi_install_fdt(argc > 2 ? argv[2] : NULL); + if (argc > 2) + fdt_addr = simple_strtoul(argv[2], NULL, 16); + else + fdt_addr = EFI_FDT_USE_INTERNAL; + ret = efi_install_fdt(fdt_addr); if (ret == EFI_INVALID_PARAMETER) return CMD_RET_USAGE; else if (ret != EFI_SUCCESS) diff --git a/include/efi_loader.h b/include/efi_loader.h index 16a1b258b1..3a22089329 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -34,6 +34,9 @@ static inline int guidcmp(const void *g1, const void *g2) EFI_GUID(0xbbe4e671, 0x5773, 0x4ea1, \ 0x9a, 0xab, 0x3a, 0x7d, 0xbf, 0x40, 0xc4, 0x82)
+/* Use internal device tree when starting UEFI application */ +#define EFI_FDT_USE_INTERNAL 0UL + /* Root node */ extern efi_handle_t efi_root;
-- 2.24.0

If the bootefi command is called without passing the address of a device tree, the internal device tree is used. For devices with a hardware device tree it is preferable to used the hardware device tree in this case.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- cmd/bootefi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 2b190a3edd..a3e2a05126 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -200,14 +200,16 @@ static void *get_config_table(const efi_guid_t *guid) * * If fdt_addr is available, the device tree located at that memory address will * will be installed as configuration table, otherwise the device tree located - * at the address indicated by environment variable fdtcontroladdr will be used. + * at the address indicated by environment variable fdt_addr or as fallback + * fdtcontroladdr will be used. * * On architectures using ACPI tables device trees shall not be installed as * configuration table. * * @fdt_addr: address of device tree or EFI_FDT_USE_INTERNAL to use the - * internal device tree as indicated by environment variable - * fdtcontroladdr + * the hardware device tree as indicated by environment variable + * fdt_addr or as fallback the internal device tree as indicated by + * the environment variable fdtcontroladdr * Return: status code */ static efi_status_t efi_install_fdt(uintptr_t fdt_addr) @@ -232,15 +234,19 @@ static efi_status_t efi_install_fdt(uintptr_t fdt_addr) /* Look for device tree that is already installed */ if (get_config_table(&efi_guid_fdt)) return EFI_SUCCESS; - /* Use our own device tree as default */ - fdt_opt = env_get("fdtcontroladdr"); + /* Check if there is a hardware device tree */ + fdt_opt = env_get("fdt_addr"); + /* Use our own device tree as fallback */ if (!fdt_opt) { - printf("ERROR: need device tree\n"); - return EFI_NOT_FOUND; + fdt_opt = env_get("fdtcontroladdr"); + if (!fdt_opt) { + printf("ERROR: need device tree\n"); + return EFI_NOT_FOUND; + } } fdt_addr = simple_strtoul(fdt_opt, NULL, 16); if (!fdt_addr) { - printf("ERROR: invalid $fdtcontroladdr\n"); + printf("ERROR: invalid $fdt_addr or $fdtcontroladdr\n"); return EFI_LOAD_ERROR; } } -- 2.24.0

Provide public function efi_run_imager() which can be used to run an UEFI image from memory.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- cmd/bootefi.c | 51 +++++++++++++++++++++++++++----------------- include/efi_loader.h | 2 ++ 2 files changed, 34 insertions(+), 19 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index a3e2a05126..15b4ff9515 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -360,11 +360,8 @@ static int do_efibootmgr(void) static int do_bootefi_image(const char *image_opt) { void *image_buf; - struct efi_device_path *device_path, *image_path; - struct efi_device_path *file_path = NULL; unsigned long addr, size; const char *size_str; - efi_handle_t mem_handle = NULL, handle; efi_status_t ret;
#ifdef CONFIG_CMD_BOOTEFI_HELLO @@ -382,8 +379,10 @@ static int do_bootefi_image(const char *image_opt) image_buf = map_sysmem(addr, size); memcpy(image_buf, __efi_helloworld_begin, size);
- device_path = NULL; - image_path = NULL; + efi_free_pool(bootefi_device_path); + efi_free_pool(bootefi_image_path); + bootefi_device_path = NULL; + bootefi_image_path = NULL; } else #endif { @@ -399,19 +398,37 @@ static int do_bootefi_image(const char *image_opt) return CMD_RET_USAGE;
image_buf = map_sysmem(addr, size); - - device_path = bootefi_device_path; - image_path = bootefi_image_path; } + ret = efi_run_image(image_buf, size); + + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +/** + * efi_run_image() - run loaded UEFI image + * + * @source_buffer: memory address of the UEFI image + * @source_size: size of the UEFI image + * Return: status code + */ +efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size) +{ + efi_handle_t mem_handle = NULL, handle; + struct efi_device_path *file_path = NULL; + efi_status_t ret;
- if (!device_path && !image_path) { + if (!bootefi_device_path || !bootefi_image_path) { /* * Special case for efi payload not loaded from disk, * such as 'bootefi hello' or for example payload * loaded directly into memory via JTAG, etc: */ file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, - (uintptr_t)image_buf, size); + (uintptr_t)source_buffer, + source_size); /* * Make sure that device for device_path exist * in load_image(). Otherwise, shell and grub will fail. @@ -425,12 +442,12 @@ static int do_bootefi_image(const char *image_opt) if (ret != EFI_SUCCESS) goto out; } else { - assert(device_path && image_path); - file_path = efi_dp_append(device_path, image_path); + file_path = efi_dp_append(bootefi_device_path, + bootefi_image_path); }
- ret = EFI_CALL(efi_load_image(false, efi_root, - file_path, image_buf, size, &handle)); + ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer, + source_size, &handle)); if (ret != EFI_SUCCESS) goto out;
@@ -441,11 +458,7 @@ out: efi_delete_handle(mem_handle); if (file_path) efi_free_pool(file_path); - - if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; + return ret; }
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST diff --git a/include/efi_loader.h b/include/efi_loader.h index 3a22089329..1e1fe52bc0 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -341,6 +341,8 @@ extern struct list_head efi_register_notify_events;
/* Initialize efi execution environment */ efi_status_t efi_init_obj_list(void); +/* Run loaded UEFI image */ +efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size); /* Initialize variable services */ efi_status_t efi_init_variables(void); /* Notify ExitBootServices() is called */ -- 2.24.0

Export the efi_install_fdt() function.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- cmd/bootefi.c | 2 +- include/efi_loader.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 15b4ff9515..9d9019c269 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -212,7 +212,7 @@ static void *get_config_table(const efi_guid_t *guid) * the environment variable fdtcontroladdr * Return: status code */ -static efi_status_t efi_install_fdt(uintptr_t fdt_addr) +efi_status_t efi_install_fdt(uintptr_t fdt_addr) { /* * The EBBR spec requires that we have either an FDT or an ACPI table diff --git a/include/efi_loader.h b/include/efi_loader.h index 1e1fe52bc0..ca50953272 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -341,6 +341,8 @@ extern struct list_head efi_register_notify_events;
/* Initialize efi execution environment */ efi_status_t efi_init_obj_list(void); +/* Install device tree */ +efi_status_t efi_install_fdt(uintptr_t fdt_addr); /* Run loaded UEFI image */ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size); /* Initialize variable services */ -- 2.24.0
participants (1)
-
Heinrich Schuchardt