From 05e2cade01df4461569a07c1d109d5acae14e1fa Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:39 +0900 Subject: [PATCH 1/9] cmd: bootefi: unfold do_bootefi_image() Unfold do_bootefi_image() into do_bootefi() in order to make it easier to re-organize do_bootefi() in the next commit. Signed-off-by: AKASHI Takahiro --- cmd/bootefi.c | 103 +++++++++++++++++++------------------------------- 1 file changed, 38 insertions(+), 65 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 2ed29ad6bb8..2eb7164ab72 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -437,58 +437,6 @@ static int do_efibootmgr(void) return CMD_RET_SUCCESS; } -/** - * do_bootefi_image() - execute EFI binary - * - * Set up memory image for the binary to be loaded, prepare device path, and - * then call do_bootefi_exec() to execute it. - * - * @image_opt: string with image start address - * @size_opt: string with image size or NULL - * Return: status code - */ -static int do_bootefi_image(const char *image_opt, const char *size_opt) -{ - void *image_buf; - unsigned long addr, size; - efi_status_t ret; - -#ifdef CONFIG_CMD_BOOTEFI_HELLO - if (!strcmp(image_opt, "hello")) { - image_buf = __efi_helloworld_begin; - size = __efi_helloworld_end - __efi_helloworld_begin; - efi_clear_bootdev(); - } else -#endif - { - addr = strtoul(image_opt, NULL, 16); - /* Check that a numeric value was passed */ - if (!addr) - return CMD_RET_USAGE; - image_buf = map_sysmem(addr, 0); - - if (size_opt) { - size = strtoul(size_opt, NULL, 16); - if (!size) - return CMD_RET_USAGE; - efi_clear_bootdev(); - } else { - if (image_buf != image_addr) { - log_err("No UEFI binary known at %s\n", - image_opt); - return CMD_RET_FAILURE; - } - size = image_size; - } - } - 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 * @@ -660,8 +608,9 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { efi_status_t ret; - char *img_addr, *img_size, *str_copy, *pos; - void *fdt; + char *p; + void *fdt, *image_buf; + unsigned long addr, size; if (argc < 2) return CMD_RET_USAGE; @@ -696,18 +645,42 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, if (!strcmp(argv[1], "selftest")) return do_efi_selftest(); #endif - str_copy = strdup(argv[1]); - if (!str_copy) { - log_err("Out of memory\n"); - return CMD_RET_FAILURE; - } - pos = str_copy; - img_addr = strsep(&pos, ":"); - img_size = strsep(&pos, ":"); - ret = do_bootefi_image(img_addr, img_size); - free(str_copy); - return ret; +#ifdef CONFIG_CMD_BOOTEFI_HELLO + if (!strcmp(argv[1], "hello")) { + image_buf = __efi_helloworld_begin; + size = __efi_helloworld_end - __efi_helloworld_begin; + efi_clear_bootdev(); + } else +#endif + { + addr = strtoul(argv[1], NULL, 16); + /* Check that a numeric value was passed */ + if (!addr) + return CMD_RET_USAGE; + image_buf = map_sysmem(addr, 0); + + p = strchr(argv[1], ':'); + if (p) { + size = strtoul(++p, NULL, 16); + if (!size) + return CMD_RET_USAGE; + efi_clear_bootdev(); + } else { + if (image_buf != image_addr) { + log_err("No UEFI binary known at %s\n", + argv[1]); + return CMD_RET_FAILURE; + } + size = image_size; + } + } + ret = efi_run_image(image_buf, size); + + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; } U_BOOT_LONGHELP(bootefi, From 296faf4f7ef15a3f9d5920b8dd247b4744e3e255 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:40 +0900 Subject: [PATCH 2/9] cmd: bootefi: re-organize do_bootefi() Replicate some code and re-organize do_bootefi() into three cases, which will be carved out as independent functions in the next two commits. Signed-off-by: AKASHI Takahiro --- cmd/Kconfig | 14 ++++++-- cmd/bootefi.c | 84 ++++++++++++++++++++++++++++++-------------- include/efi_loader.h | 2 -- 3 files changed, 69 insertions(+), 31 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index 748b959961d..b21a30c08b4 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -362,9 +362,19 @@ config CMD_BOOTEFI help Boot an EFI image from memory. +if CMD_BOOTEFI +config CMD_BOOTEFI_BINARY + bool "Allow booting an EFI binary directly" + depends on BOOTEFI_BOOTMGR + default y + help + Select this option to enable direct execution of binary at 'bootefi'. + This subcommand will allow you to load the UEFI binary using + other U-Boot commands or external methods and then run it. + config CMD_BOOTEFI_BOOTMGR bool "UEFI Boot Manager command" - depends on BOOTEFI_BOOTMGR && CMD_BOOTEFI + depends on BOOTEFI_BOOTMGR default y help Select this option to enable the 'bootmgr' subcommand of 'bootefi'. @@ -373,7 +383,6 @@ config CMD_BOOTEFI_BOOTMGR config CMD_BOOTEFI_HELLO_COMPILE bool "Compile a standard EFI hello world binary for testing" - depends on CMD_BOOTEFI && !CPU_V7M default y help This compiles a standard EFI hello world application with U-Boot so @@ -395,6 +404,7 @@ config CMD_BOOTEFI_HELLO up EFI support on a new architecture. source lib/efi_selftest/Kconfig +endif config CMD_BOOTMENU bool "bootmenu" diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 2eb7164ab72..49cddfbcef1 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -503,7 +503,6 @@ out: return (ret != EFI_SUCCESS) ? ret : ret2; } -#ifdef CONFIG_CMD_BOOTEFI_SELFTEST static efi_status_t bootefi_run_prepare(const char *load_options_path, struct efi_device_path *device_path, struct efi_device_path *image_path, @@ -593,7 +592,6 @@ static int do_efi_selftest(void) return ret != EFI_SUCCESS; } -#endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ /** * do_bootefi() - execute `bootefi` command @@ -615,14 +613,6 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, if (argc < 2) return CMD_RET_USAGE; - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } - if (argc > 2) { uintptr_t fdt_addr; @@ -631,29 +621,54 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, } else { fdt = EFI_FDT_USE_INTERNAL; } - ret = efi_install_fdt(fdt); - if (ret == EFI_INVALID_PARAMETER) - return CMD_RET_USAGE; - else if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { - if (!strcmp(argv[1], "bootmgr")) - return do_efibootmgr(); + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR) && + !strcmp(argv[1], "bootmgr")) { + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt); + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + return do_efibootmgr(); } -#ifdef CONFIG_CMD_BOOTEFI_SELFTEST - if (!strcmp(argv[1], "selftest")) - return do_efi_selftest(); -#endif -#ifdef CONFIG_CMD_BOOTEFI_HELLO - if (!strcmp(argv[1], "hello")) { + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_SELFTEST) && + !strcmp(argv[1], "selftest")) { + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt); + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + return do_efi_selftest(); + } + + if (!IS_ENABLED(CONFIG_CMD_BOOTEFI_BINARY)) + return CMD_RET_SUCCESS; + + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_HELLO) && + !strcmp(argv[1], "hello")) { image_buf = __efi_helloworld_begin; size = __efi_helloworld_end - __efi_helloworld_begin; efi_clear_bootdev(); - } else -#endif - { + } else { addr = strtoul(argv[1], NULL, 16); /* Check that a numeric value was passed */ if (!addr) @@ -675,6 +690,21 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, size = image_size; } } + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt); + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + ret = efi_run_image(image_buf, size); if (ret != EFI_SUCCESS) diff --git a/include/efi_loader.h b/include/efi_loader.h index 664dae28f88..44436d34628 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -879,14 +879,12 @@ efi_status_t __efi_runtime EFIAPI efi_get_time( efi_status_t __efi_runtime EFIAPI efi_set_time(struct efi_time *time); -#ifdef CONFIG_CMD_BOOTEFI_SELFTEST /* * Entry point for the tests of the EFI API. * It is called by 'bootefi selftest' */ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, struct efi_system_table *systab); -#endif efi_status_t EFIAPI efi_get_variable(u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, From c3530aec141cc0621be7cdd2a3b54d7394655d16 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:41 +0900 Subject: [PATCH 3/9] cmd: bootefi: carve out EFI boot manager interface Carve EFI boot manager related code out of do_bootefi_image() in order to move boot manager specific code into library directory in the later commit. Signed-off-by: AKASHI Takahiro --- cmd/bootefi.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 49cddfbcef1..785ef23e922 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -413,28 +413,40 @@ out: } /** - * do_efibootmgr() - execute EFI boot manager + * efi_bootmgr_run() - execute EFI boot manager + * fdt: Flat device tree + * + * Invoke EFI boot manager and execute a binary depending on + * boot options. If @fdt is not NULL, it will be passed to + * the executed binary. * * Return: status code */ -static int do_efibootmgr(void) +static efi_status_t efi_bootmgr_run(void *fdt) { efi_handle_t handle; - efi_status_t ret; void *load_options; + efi_status_t ret; + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt); + if (ret != EFI_SUCCESS) + return ret; ret = efi_bootmgr_load(&handle, &load_options); if (ret != EFI_SUCCESS) { log_notice("EFI boot manager: Cannot load any image\n"); - return CMD_RET_FAILURE; + return ret; } - ret = do_bootefi_exec(handle, load_options); - - if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - - return CMD_RET_SUCCESS; + return do_bootefi_exec(handle, load_options); } /** @@ -624,21 +636,14 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR) && !strcmp(argv[1], "bootmgr")) { - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } + ret = efi_bootmgr_run(fdt); - ret = efi_install_fdt(fdt); if (ret == EFI_INVALID_PARAMETER) return CMD_RET_USAGE; - else if (ret != EFI_SUCCESS) + else if (ret) return CMD_RET_FAILURE; - return do_efibootmgr(); + return CMD_RET_SUCCESS; } if (IS_ENABLED(CONFIG_CMD_BOOTEFI_SELFTEST) && From 5c129fe5f53d40f6fb2223b5a02784ed4c81e5e7 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:42 +0900 Subject: [PATCH 4/9] cmd: bootefi: carve out binary execution interface Carve binary execution code out of do_bootefi_image() in order to move binary-execution specific code into library directory in the later commit. Signed-off-by: AKASHI Takahiro --- cmd/bootefi.c | 46 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 785ef23e922..83f28e0bc71 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -515,6 +515,36 @@ out: return (ret != EFI_SUCCESS) ? ret : ret2; } +/** + * efi_binary_run() - run loaded UEFI image + * + * @image: memory address of the UEFI image + * @size: size of the UEFI image + * + * 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 + */ +static efi_status_t efi_binary_run(void *image, size_t size, void *fdt) +{ + efi_status_t ret; + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return ret; + } + + ret = efi_install_fdt(fdt); + if (ret != EFI_SUCCESS) + return ret; + + return efi_run_image(image, size); +} + static efi_status_t bootefi_run_prepare(const char *load_options_path, struct efi_device_path *device_path, struct efi_device_path *image_path, @@ -696,23 +726,11 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, } } - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } + ret = efi_binary_run(image_buf, size, fdt); - ret = efi_install_fdt(fdt); if (ret == EFI_INVALID_PARAMETER) return CMD_RET_USAGE; - else if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - - ret = efi_run_image(image_buf, size); - - if (ret != EFI_SUCCESS) + else if (ret) return CMD_RET_FAILURE; return CMD_RET_SUCCESS; From d07e7be7ea4b35960730661c130dea5234d38101 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:43 +0900 Subject: [PATCH 5/9] cmd: bootefi: localize global device paths for efi_selftest Device paths allocated in bootefi_test_prepare() will be immediately consumed by do_efi_selftest() and there is no need to keep them for later use. Introduce test-specific varialbles to make it easier to move other bootmgr functions into library directory in the next commit. Signed-off-by: AKASHI Takahiro --- cmd/bootefi.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 83f28e0bc71..69977b2af0e 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -29,6 +29,8 @@ DECLARE_GLOBAL_DATA_PTR; +static struct efi_device_path *test_image_path; +static struct efi_device_path *test_device_path; static struct efi_device_path *bootefi_image_path; static struct efi_device_path *bootefi_device_path; static void *image_addr; @@ -586,23 +588,26 @@ static efi_status_t bootefi_test_prepare efi_status_t ret; /* Construct a dummy device path */ - bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0); - if (!bootefi_device_path) + test_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0); + if (!test_device_path) return EFI_OUT_OF_RESOURCES; - bootefi_image_path = efi_dp_from_file(NULL, path); - if (!bootefi_image_path) { + test_image_path = efi_dp_from_file(NULL, path); + if (!test_image_path) { ret = EFI_OUT_OF_RESOURCES; goto failure; } - ret = bootefi_run_prepare(load_options_path, bootefi_device_path, - bootefi_image_path, image_objp, + ret = bootefi_run_prepare(load_options_path, test_device_path, + test_image_path, image_objp, loaded_image_infop); if (ret == EFI_SUCCESS) return ret; failure: + efi_free_pool(test_device_path); + efi_free_pool(test_image_path); + /* TODO: not sure calling clear function is necessary */ efi_clear_bootdev(); return ret; } @@ -627,6 +632,8 @@ static int do_efi_selftest(void) ret = EFI_CALL(efi_selftest(&image_obj->header, &systab)); efi_restore_gd(); free(loaded_image_info->load_options); + efi_free_pool(test_device_path); + efi_free_pool(test_image_path); if (ret != EFI_SUCCESS) efi_delete_handle(&image_obj->header); else From 0bef4b0123f236db048c31e1800e50a3ade7bbb7 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:44 +0900 Subject: [PATCH 6/9] cmd: bootefi: move library interfaces under lib/efi_loader In the prior commits, interfaces for executing EFI binary and boot manager were carved out. Move them under efi_loader directory so that they can be called from other places without depending on bootefi command. Only efi_selftest-related code will be left in bootefi.c. Signed-off-by: AKASHI Takahiro --- cmd/bootefi.c | 539 +---------------------------------- include/efi_loader.h | 10 + lib/efi_loader/efi_bootmgr.c | 530 ++++++++++++++++++++++++++++++++++ 3 files changed, 551 insertions(+), 528 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 69977b2af0e..9cf9027bf40 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -7,545 +7,22 @@ #define LOG_CATEGORY LOGC_EFI -#include -#include -#include #include -#include +#include #include -#include -#include -#include -#include +#include #include #include -#include -#include -#include #include -#include +#include #include -#include +#include +#include DECLARE_GLOBAL_DATA_PTR; static struct efi_device_path *test_image_path; static struct efi_device_path *test_device_path; -static struct efi_device_path *bootefi_image_path; -static struct efi_device_path *bootefi_device_path; -static void *image_addr; -static size_t image_size; - -/** - * efi_get_image_parameters() - return image parameters - * - * @img_addr: address of loaded image in memory - * @img_size: size of loaded image - */ -void efi_get_image_parameters(void **img_addr, size_t *img_size) -{ - *img_addr = image_addr; - *img_size = image_size; -} - -/** - * efi_clear_bootdev() - clear boot device - */ -static void efi_clear_bootdev(void) -{ - efi_free_pool(bootefi_device_path); - efi_free_pool(bootefi_image_path); - bootefi_device_path = NULL; - bootefi_image_path = NULL; - image_addr = NULL; - image_size = 0; -} - -/** - * efi_set_bootdev() - set boot device - * - * This function is called when a file is loaded, e.g. via the 'load' command. - * We use the path to this file to inform the UEFI binary about the boot device. - * - * @dev: device, e.g. "MMC" - * @devnr: number of the device, e.g. "1:2" - * @path: path to file loaded - * @buffer: buffer with file loaded - * @buffer_size: size of file loaded - */ -void efi_set_bootdev(const char *dev, const char *devnr, const char *path, - void *buffer, size_t buffer_size) -{ - struct efi_device_path *device, *image; - efi_status_t ret; - - log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev, - devnr, path, buffer, buffer_size); - - /* Forget overwritten image */ - if (buffer + buffer_size >= image_addr && - image_addr + image_size >= buffer) - efi_clear_bootdev(); - - /* Remember only PE-COFF and FIT images */ - if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) { - if (IS_ENABLED(CONFIG_FIT) && - !fit_check_format(buffer, IMAGE_SIZE_INVAL)) { - /* - * FIT images of type EFI_OS are started via command - * bootm. We should not use their boot device with the - * bootefi command. - */ - buffer = 0; - buffer_size = 0; - } else { - log_debug("- not remembering image\n"); - return; - } - } - - /* efi_set_bootdev() is typically called repeatedly, recover memory */ - efi_clear_bootdev(); - - image_addr = buffer; - image_size = buffer_size; - - ret = efi_dp_from_name(dev, devnr, path, &device, &image); - if (ret == EFI_SUCCESS) { - bootefi_device_path = device; - if (image) { - /* FIXME: image should not contain device */ - struct efi_device_path *image_tmp = image; - - efi_dp_split_file_path(image, &device, &image); - efi_free_pool(image_tmp); - } - bootefi_image_path = image; - log_debug("- boot device %pD\n", device); - if (image) - log_debug("- image %pD\n", image); - } else { - log_debug("- efi_dp_from_name() failed, err=%lx\n", ret); - efi_clear_bootdev(); - } -} - -/** - * efi_env_set_load_options() - set load options from environment variable - * - * @handle: the image handle - * @env_var: name of the environment variable - * @load_options: pointer to load options (output) - * Return: status code - */ -static efi_status_t efi_env_set_load_options(efi_handle_t handle, - const char *env_var, - u16 **load_options) -{ - const char *env = env_get(env_var); - size_t size; - u16 *pos; - efi_status_t ret; - - *load_options = NULL; - if (!env) - return EFI_SUCCESS; - size = sizeof(u16) * (utf8_utf16_strlen(env) + 1); - pos = calloc(size, 1); - if (!pos) - return EFI_OUT_OF_RESOURCES; - *load_options = pos; - utf8_utf16_strcpy(&pos, env); - ret = efi_set_load_options(handle, size, *load_options); - if (ret != EFI_SUCCESS) { - free(*load_options); - *load_options = NULL; - } - return ret; -} - -#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) - -/** - * copy_fdt() - Copy the device tree to a new location available to EFI - * - * The FDT is copied to a suitable location within the EFI memory map. - * Additional 12 KiB are added to the space in case the device tree needs to be - * expanded later with fdt_open_into(). - * - * @fdtp: On entry a pointer to the flattened device tree. - * On exit a pointer to the copy of the flattened device tree. - * FDT start - * Return: status code - */ -static efi_status_t copy_fdt(void **fdtp) -{ - unsigned long fdt_ram_start = -1L, fdt_pages; - efi_status_t ret = 0; - void *fdt, *new_fdt; - u64 new_fdt_addr; - uint fdt_size; - int i; - - for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - u64 ram_start = gd->bd->bi_dram[i].start; - u64 ram_size = gd->bd->bi_dram[i].size; - - if (!ram_size) - continue; - - if (ram_start < fdt_ram_start) - fdt_ram_start = ram_start; - } - - /* - * Give us at least 12 KiB of breathing room in case the device tree - * needs to be expanded later. - */ - fdt = *fdtp; - fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000); - fdt_size = fdt_pages << EFI_PAGE_SHIFT; - - ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, - EFI_ACPI_RECLAIM_MEMORY, fdt_pages, - &new_fdt_addr); - if (ret != EFI_SUCCESS) { - log_err("ERROR: Failed to reserve space for FDT\n"); - goto done; - } - new_fdt = (void *)(uintptr_t)new_fdt_addr; - memcpy(new_fdt, fdt, fdt_totalsize(fdt)); - fdt_set_totalsize(new_fdt, fdt_size); - - *fdtp = (void *)(uintptr_t)new_fdt_addr; -done: - return ret; -} - -/** - * get_config_table() - get configuration table - * - * @guid: GUID of the configuration table - * Return: pointer to configuration table or NULL - */ -static void *get_config_table(const efi_guid_t *guid) -{ - size_t i; - - for (i = 0; i < systab.nr_tables; i++) { - if (!guidcmp(guid, &systab.tables[i].guid)) - return systab.tables[i].table; - } - return NULL; -} - -#endif /* !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) */ - -/** - * efi_install_fdt() - install device tree - * - * If fdt is not EFI_FDT_USE_INTERNAL, 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 fdt_addr or as - * fallback fdtcontroladdr will be used. - * - * On architectures using ACPI tables device trees shall not be installed as - * configuration table. - * - * @fdt: address of device tree or EFI_FDT_USE_INTERNAL to use the - * 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 - */ -efi_status_t efi_install_fdt(void *fdt) -{ - /* - * 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) { - log_warning("WARNING: Can't have ACPI table and device tree - ignoring DT.\n"); - return EFI_SUCCESS; - } -#else - struct bootm_headers img = { 0 }; - efi_status_t ret; - - if (fdt == EFI_FDT_USE_INTERNAL) { - const char *fdt_opt; - uintptr_t fdt_addr; - - /* Look for device tree that is already installed */ - if (get_config_table(&efi_guid_fdt)) - return EFI_SUCCESS; - /* Check if there is a hardware device tree */ - fdt_opt = env_get("fdt_addr"); - /* Use our own device tree as fallback */ - if (!fdt_opt) { - fdt_opt = env_get("fdtcontroladdr"); - if (!fdt_opt) { - log_err("ERROR: need device tree\n"); - return EFI_NOT_FOUND; - } - } - fdt_addr = hextoul(fdt_opt, NULL); - if (!fdt_addr) { - log_err("ERROR: invalid $fdt_addr or $fdtcontroladdr\n"); - return EFI_LOAD_ERROR; - } - fdt = map_sysmem(fdt_addr, 0); - } - - /* Install device tree */ - if (fdt_check_header(fdt)) { - log_err("ERROR: invalid device tree\n"); - return EFI_LOAD_ERROR; - } - - /* Prepare device tree for payload */ - ret = copy_fdt(&fdt); - if (ret) { - log_err("ERROR: out of memory\n"); - return EFI_OUT_OF_RESOURCES; - } - - if (image_setup_libfdt(&img, fdt, NULL)) { - log_err("ERROR: failed to process device tree\n"); - return EFI_LOAD_ERROR; - } - - /* Create memory reservations as indicated by the device tree */ - efi_carve_out_dt_rsv(fdt); - - efi_try_purge_kaslr_seed(fdt); - - if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) { - ret = efi_tcg2_measure_dtb(fdt); - if (ret == EFI_SECURITY_VIOLATION) { - log_err("ERROR: failed to measure DTB\n"); - return ret; - } - } - - /* Install device tree as UEFI table */ - ret = efi_install_configuration_table(&efi_guid_fdt, fdt); - if (ret != EFI_SUCCESS) { - log_err("ERROR: failed to install device tree\n"); - return ret; - } -#endif /* GENERATE_ACPI_TABLE */ - - return EFI_SUCCESS; -} - -/** - * do_bootefi_exec() - execute EFI binary - * - * The image indicated by @handle is started. When it returns the allocated - * memory for the @load_options is freed. - * - * @handle: handle of loaded image - * @load_options: load options - * Return: status code - * - * Load the EFI binary into a newly assigned memory unwinding the relocation - * information, install the loaded image protocol, and call the binary. - */ -static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options) -{ - efi_status_t ret; - efi_uintn_t exit_data_size = 0; - u16 *exit_data = NULL; - struct efi_event *evt; - - /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */ - switch_to_non_secure_mode(); - - /* - * The UEFI standard requires that the watchdog timer is set to five - * minutes when invoking an EFI boot option. - * - * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A - * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer - */ - ret = efi_set_watchdog(300); - if (ret != EFI_SUCCESS) { - log_err("ERROR: Failed to set watchdog timer\n"); - goto out; - } - - /* Call our payload! */ - ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data)); - if (ret != EFI_SUCCESS) { - log_err("## Application failed, r = %lu\n", - ret & ~EFI_ERROR_MASK); - if (exit_data) { - log_err("## %ls\n", exit_data); - efi_free_pool(exit_data); - } - } - - efi_restore_gd(); - -out: - free(load_options); - - if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) { - if (efi_initrd_deregister() != EFI_SUCCESS) - log_err("Failed to remove loadfile2 for initrd\n"); - } - - /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */ - list_for_each_entry(evt, &efi_events, link) { - if (evt->group && - !guidcmp(evt->group, - &efi_guid_event_group_return_to_efibootmgr)) { - efi_signal_event(evt); - EFI_CALL(systab.boottime->close_event(evt)); - break; - } - } - - /* Control is returned to U-Boot, disable EFI watchdog */ - efi_set_watchdog(0); - - return ret; -} - -/** - * efi_bootmgr_run() - execute EFI boot manager - * fdt: Flat device tree - * - * Invoke EFI boot manager and execute a binary depending on - * boot options. If @fdt is not NULL, it will be passed to - * the executed binary. - * - * Return: status code - */ -static efi_status_t efi_bootmgr_run(void *fdt) -{ - efi_handle_t handle; - void *load_options; - efi_status_t ret; - - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } - - ret = efi_install_fdt(fdt); - if (ret != EFI_SUCCESS) - return ret; - - ret = efi_bootmgr_load(&handle, &load_options); - if (ret != EFI_SUCCESS) { - log_notice("EFI boot manager: Cannot load any image\n"); - return ret; - } - - return do_bootefi_exec(handle, load_options); -} - -/** - * 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; - struct efi_device_path *msg_path; - efi_status_t ret, ret2; - u16 *load_options; - - if (!bootefi_device_path || !bootefi_image_path) { - log_debug("Not loaded from disk\n"); - /* - * 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)source_buffer, - source_size); - /* - * Make sure that device for device_path exist - * in load_image(). Otherwise, shell and grub will fail. - */ - ret = efi_install_multiple_protocol_interfaces(&mem_handle, - &efi_guid_device_path, - file_path, NULL); - if (ret != EFI_SUCCESS) - goto out; - msg_path = file_path; - } else { - file_path = efi_dp_append(bootefi_device_path, - bootefi_image_path); - msg_path = bootefi_image_path; - log_debug("Loaded from disk\n"); - } - - log_info("Booting %pD\n", msg_path); - - ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer, - source_size, &handle)); - if (ret != EFI_SUCCESS) { - log_err("Loading image failed\n"); - goto out; - } - - /* Transfer environment variable as load options */ - ret = efi_env_set_load_options(handle, "bootargs", &load_options); - if (ret != EFI_SUCCESS) - goto out; - - ret = do_bootefi_exec(handle, load_options); - -out: - ret2 = efi_uninstall_multiple_protocol_interfaces(mem_handle, - &efi_guid_device_path, - file_path, NULL); - efi_free_pool(file_path); - return (ret != EFI_SUCCESS) ? ret : ret2; -} - -/** - * efi_binary_run() - run loaded UEFI image - * - * @image: memory address of the UEFI image - * @size: size of the UEFI image - * - * 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 - */ -static efi_status_t efi_binary_run(void *image, size_t size, void *fdt) -{ - efi_status_t ret; - - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return ret; - } - - ret = efi_install_fdt(fdt); - if (ret != EFI_SUCCESS) - return ret; - - return efi_run_image(image, size); -} static efi_status_t bootefi_run_prepare(const char *load_options_path, struct efi_device_path *device_path, @@ -658,6 +135,8 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, char *p; void *fdt, *image_buf; unsigned long addr, size; + void *image_addr; + size_t image_size; if (argc < 2) return CMD_RET_USAGE; @@ -709,6 +188,7 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, !strcmp(argv[1], "hello")) { image_buf = __efi_helloworld_begin; size = __efi_helloworld_end - __efi_helloworld_begin; + /* TODO: not sure calling clear function is necessary */ efi_clear_bootdev(); } else { addr = strtoul(argv[1], NULL, 16); @@ -724,6 +204,9 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, return CMD_RET_USAGE; efi_clear_bootdev(); } else { + /* Image should be already loaded */ + efi_get_image_parameters(&image_addr, &image_size); + if (image_buf != image_addr) { log_err("No UEFI binary known at %s\n", argv[1]); diff --git a/include/efi_loader.h b/include/efi_loader.h index 44436d34628..34e7fbbf184 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -90,6 +90,8 @@ efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len); * back to u-boot world */ void efi_restore_gd(void); +/* Call this to unset the current device name */ +void efi_clear_bootdev(void); /* Call this to set the current device name */ void efi_set_bootdev(const char *dev, const char *devnr, const char *path, void *buffer, size_t buffer_size); @@ -114,6 +116,7 @@ static inline efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len) /* No loader configured, stub out EFI_ENTRY */ static inline void efi_restore_gd(void) { } +static inline void efi_clear_bootdev(void) { } static inline void efi_set_bootdev(const char *dev, const char *devnr, const char *path, void *buffer, size_t buffer_size) { } @@ -527,14 +530,21 @@ efi_status_t efi_bootmgr_get_unused_bootoption(u16 *buf, efi_status_t efi_bootmgr_update_media_device_boot_option(void); /* Delete selected boot option */ efi_status_t efi_bootmgr_delete_boot_option(u16 boot_index); +/* Invoke EFI boot manager */ +efi_status_t efi_bootmgr_run(void *fdt); /* search the boot option index in BootOrder */ bool efi_search_bootorder(u16 *bootorder, efi_uintn_t num, u32 target, u32 *index); /* Set up console modes */ void efi_setup_console_size(void); +/* Set up load options from environment variable */ +efi_status_t efi_env_set_load_options(efi_handle_t handle, const char *env_var, + u16 **load_options); /* Install device tree */ efi_status_t efi_install_fdt(void *fdt); /* Run loaded UEFI image */ efi_status_t efi_run_image(void *source_buffer, efi_uintn_t source_size); +/* Run loaded UEFI image with given fdt */ +efi_status_t efi_binary_run(void *image, size_t size, void *fdt); /* Initialize variable services */ efi_status_t efi_init_variables(void); /* Notify ExitBootServices() is called */ diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 48153bd5ffb..56d97f23827 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -3,6 +3,8 @@ * EFI boot manager * * Copyright (c) 2017 Rob Clark + * For the code moved from cmd/bootefi.c + * Copyright (c) 2016 Alexander Graf */ #define LOG_CATEGORY LOGC_EFI @@ -20,6 +22,17 @@ #include #include +/* TODO: temporarily added here; clean up later */ +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + static const struct efi_boot_services *bs; static const struct efi_runtime_services *rs; @@ -1115,3 +1128,520 @@ out: return EFI_SUCCESS; return ret; } + +static struct efi_device_path *bootefi_image_path; +static struct efi_device_path *bootefi_device_path; +static void *image_addr; +static size_t image_size; + +/** + * efi_get_image_parameters() - return image parameters + * + * @img_addr: address of loaded image in memory + * @img_size: size of loaded image + */ +void efi_get_image_parameters(void **img_addr, size_t *img_size) +{ + *img_addr = image_addr; + *img_size = image_size; +} + +/** + * efi_clear_bootdev() - clear boot device + */ +void efi_clear_bootdev(void) +{ + efi_free_pool(bootefi_device_path); + efi_free_pool(bootefi_image_path); + bootefi_device_path = NULL; + bootefi_image_path = NULL; + image_addr = NULL; + image_size = 0; +} + +/** + * efi_set_bootdev() - set boot device + * + * This function is called when a file is loaded, e.g. via the 'load' command. + * We use the path to this file to inform the UEFI binary about the boot device. + * + * @dev: device, e.g. "MMC" + * @devnr: number of the device, e.g. "1:2" + * @path: path to file loaded + * @buffer: buffer with file loaded + * @buffer_size: size of file loaded + */ +void efi_set_bootdev(const char *dev, const char *devnr, const char *path, + void *buffer, size_t buffer_size) +{ + struct efi_device_path *device, *image; + efi_status_t ret; + + log_debug("dev=%s, devnr=%s, path=%s, buffer=%p, size=%zx\n", dev, + devnr, path, buffer, buffer_size); + + /* Forget overwritten image */ + if (buffer + buffer_size >= image_addr && + image_addr + image_size >= buffer) + efi_clear_bootdev(); + + /* Remember only PE-COFF and FIT images */ + if (efi_check_pe(buffer, buffer_size, NULL) != EFI_SUCCESS) { + if (IS_ENABLED(CONFIG_FIT) && + !fit_check_format(buffer, IMAGE_SIZE_INVAL)) { + /* + * FIT images of type EFI_OS are started via command + * bootm. We should not use their boot device with the + * bootefi command. + */ + buffer = 0; + buffer_size = 0; + } else { + log_debug("- not remembering image\n"); + return; + } + } + + /* efi_set_bootdev() is typically called repeatedly, recover memory */ + efi_clear_bootdev(); + + image_addr = buffer; + image_size = buffer_size; + + ret = efi_dp_from_name(dev, devnr, path, &device, &image); + if (ret == EFI_SUCCESS) { + bootefi_device_path = device; + if (image) { + /* FIXME: image should not contain device */ + struct efi_device_path *image_tmp = image; + + efi_dp_split_file_path(image, &device, &image); + efi_free_pool(image_tmp); + } + bootefi_image_path = image; + log_debug("- boot device %pD\n", device); + if (image) + log_debug("- image %pD\n", image); + } else { + log_debug("- efi_dp_from_name() failed, err=%lx\n", ret); + efi_clear_bootdev(); + } +} + +/** + * efi_env_set_load_options() - set load options from environment variable + * + * @handle: the image handle + * @env_var: name of the environment variable + * @load_options: pointer to load options (output) + * Return: status code + */ +efi_status_t efi_env_set_load_options(efi_handle_t handle, + const char *env_var, + u16 **load_options) +{ + const char *env = env_get(env_var); + size_t size; + u16 *pos; + efi_status_t ret; + + *load_options = NULL; + if (!env) + return EFI_SUCCESS; + size = sizeof(u16) * (utf8_utf16_strlen(env) + 1); + pos = calloc(size, 1); + if (!pos) + return EFI_OUT_OF_RESOURCES; + *load_options = pos; + utf8_utf16_strcpy(&pos, env); + ret = efi_set_load_options(handle, size, *load_options); + if (ret != EFI_SUCCESS) { + free(*load_options); + *load_options = NULL; + } + return ret; +} + +#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) + +/** + * copy_fdt() - Copy the device tree to a new location available to EFI + * + * The FDT is copied to a suitable location within the EFI memory map. + * Additional 12 KiB are added to the space in case the device tree needs to be + * expanded later with fdt_open_into(). + * + * @fdtp: On entry a pointer to the flattened device tree. + * On exit a pointer to the copy of the flattened device tree. + * FDT start + * Return: status code + */ +static efi_status_t copy_fdt(void **fdtp) +{ + unsigned long fdt_ram_start = -1L, fdt_pages; + efi_status_t ret = 0; + void *fdt, *new_fdt; + u64 new_fdt_addr; + uint fdt_size; + int i; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + u64 ram_start = gd->bd->bi_dram[i].start; + u64 ram_size = gd->bd->bi_dram[i].size; + + if (!ram_size) + continue; + + if (ram_start < fdt_ram_start) + fdt_ram_start = ram_start; + } + + /* + * Give us at least 12 KiB of breathing room in case the device tree + * needs to be expanded later. + */ + fdt = *fdtp; + fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000); + fdt_size = fdt_pages << EFI_PAGE_SHIFT; + + ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_ACPI_RECLAIM_MEMORY, fdt_pages, + &new_fdt_addr); + if (ret != EFI_SUCCESS) { + log_err("ERROR: Failed to reserve space for FDT\n"); + goto done; + } + new_fdt = (void *)(uintptr_t)new_fdt_addr; + memcpy(new_fdt, fdt, fdt_totalsize(fdt)); + fdt_set_totalsize(new_fdt, fdt_size); + + *fdtp = (void *)(uintptr_t)new_fdt_addr; +done: + return ret; +} + +/** + * get_config_table() - get configuration table + * + * @guid: GUID of the configuration table + * Return: pointer to configuration table or NULL + */ +static void *get_config_table(const efi_guid_t *guid) +{ + size_t i; + + for (i = 0; i < systab.nr_tables; i++) { + if (!guidcmp(guid, &systab.tables[i].guid)) + return systab.tables[i].table; + } + return NULL; +} + +#endif /* !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) */ + +/** + * efi_install_fdt() - install device tree + * + * If fdt is not EFI_FDT_USE_INTERNAL, the device tree located at that memory + * address will be installed as configuration table, otherwise the device + * tree located 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: address of device tree or EFI_FDT_USE_INTERNAL to use + * 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 + */ +efi_status_t efi_install_fdt(void *fdt) +{ + /* + * 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) { + log_warning("WARNING: Can't have ACPI table and device tree - ignoring DT.\n"); + return EFI_SUCCESS; + } +#else + struct bootm_headers img = { 0 }; + efi_status_t ret; + + if (fdt == EFI_FDT_USE_INTERNAL) { + const char *fdt_opt; + uintptr_t fdt_addr; + + /* Look for device tree that is already installed */ + if (get_config_table(&efi_guid_fdt)) + return EFI_SUCCESS; + /* Check if there is a hardware device tree */ + fdt_opt = env_get("fdt_addr"); + /* Use our own device tree as fallback */ + if (!fdt_opt) { + fdt_opt = env_get("fdtcontroladdr"); + if (!fdt_opt) { + log_err("ERROR: need device tree\n"); + return EFI_NOT_FOUND; + } + } + fdt_addr = hextoul(fdt_opt, NULL); + if (!fdt_addr) { + log_err("ERROR: invalid $fdt_addr or $fdtcontroladdr\n"); + return EFI_LOAD_ERROR; + } + fdt = map_sysmem(fdt_addr, 0); + } + + /* Install device tree */ + if (fdt_check_header(fdt)) { + log_err("ERROR: invalid device tree\n"); + return EFI_LOAD_ERROR; + } + + /* Prepare device tree for payload */ + ret = copy_fdt(&fdt); + if (ret) { + log_err("ERROR: out of memory\n"); + return EFI_OUT_OF_RESOURCES; + } + + if (image_setup_libfdt(&img, fdt, NULL)) { + log_err("ERROR: failed to process device tree\n"); + return EFI_LOAD_ERROR; + } + + /* Create memory reservations as indicated by the device tree */ + efi_carve_out_dt_rsv(fdt); + + efi_try_purge_kaslr_seed(fdt); + + if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) { + ret = efi_tcg2_measure_dtb(fdt); + if (ret == EFI_SECURITY_VIOLATION) { + log_err("ERROR: failed to measure DTB\n"); + return ret; + } + } + + /* Install device tree as UEFI table */ + ret = efi_install_configuration_table(&efi_guid_fdt, fdt); + if (ret != EFI_SUCCESS) { + log_err("ERROR: failed to install device tree\n"); + return ret; + } +#endif /* GENERATE_ACPI_TABLE */ + + return EFI_SUCCESS; +} + +/** + * do_bootefi_exec() - execute EFI binary + * + * The image indicated by @handle is started. When it returns the allocated + * memory for the @load_options is freed. + * + * @handle: handle of loaded image + * @load_options: load options + * Return: status code + * + * Load the EFI binary into a newly assigned memory unwinding the relocation + * information, install the loaded image protocol, and call the binary. + */ +static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options) +{ + efi_status_t ret; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; + struct efi_event *evt; + + /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */ + switch_to_non_secure_mode(); + + /* + * The UEFI standard requires that the watchdog timer is set to five + * minutes when invoking an EFI boot option. + * + * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A + * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer + */ + ret = efi_set_watchdog(300); + if (ret != EFI_SUCCESS) { + log_err("ERROR: Failed to set watchdog timer\n"); + goto out; + } + + /* Call our payload! */ + ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data)); + if (ret != EFI_SUCCESS) { + log_err("## Application failed, r = %lu\n", + ret & ~EFI_ERROR_MASK); + if (exit_data) { + log_err("## %ls\n", exit_data); + efi_free_pool(exit_data); + } + } + + efi_restore_gd(); + +out: + free(load_options); + + if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) { + if (efi_initrd_deregister() != EFI_SUCCESS) + log_err("Failed to remove loadfile2 for initrd\n"); + } + + /* Notify EFI_EVENT_GROUP_RETURN_TO_EFIBOOTMGR event group. */ + list_for_each_entry(evt, &efi_events, link) { + if (evt->group && + !guidcmp(evt->group, + &efi_guid_event_group_return_to_efibootmgr)) { + efi_signal_event(evt); + EFI_CALL(systab.boottime->close_event(evt)); + break; + } + } + + /* Control is returned to U-Boot, disable EFI watchdog */ + efi_set_watchdog(0); + + return ret; +} + +/** + * efi_bootmgr_run() - execute EFI boot manager + * @fdt: Flat device tree + * + * Invoke EFI boot manager and execute a binary depending on + * boot options. If @fdt is not NULL, it will be passed to + * the executed binary. + * + * Return: status code + */ +efi_status_t efi_bootmgr_run(void *fdt) +{ + efi_handle_t handle; + void *load_options; + efi_status_t ret; + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt); + if (ret != EFI_SUCCESS) + return ret; + + ret = efi_bootmgr_load(&handle, &load_options); + if (ret != EFI_SUCCESS) { + log_notice("EFI boot manager: Cannot load any image\n"); + return ret; + } + + return do_bootefi_exec(handle, load_options); +} + +/** + * 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; + struct efi_device_path *msg_path; + efi_status_t ret, ret2; + u16 *load_options; + + if (!bootefi_device_path || !bootefi_image_path) { + log_debug("Not loaded from disk\n"); + /* + * 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)source_buffer, + source_size); + /* + * Make sure that device for device_path exist + * in load_image(). Otherwise, shell and grub will fail. + */ + ret = efi_install_multiple_protocol_interfaces(&mem_handle, + &efi_guid_device_path, + file_path, NULL); + if (ret != EFI_SUCCESS) + goto out; + msg_path = file_path; + } else { + file_path = efi_dp_append(bootefi_device_path, + bootefi_image_path); + msg_path = bootefi_image_path; + log_debug("Loaded from disk\n"); + } + + log_info("Booting %pD\n", msg_path); + + ret = EFI_CALL(efi_load_image(false, efi_root, file_path, source_buffer, + source_size, &handle)); + if (ret != EFI_SUCCESS) { + log_err("Loading image failed\n"); + goto out; + } + + /* Transfer environment variable as load options */ + ret = efi_env_set_load_options(handle, "bootargs", &load_options); + if (ret != EFI_SUCCESS) + goto out; + + ret = do_bootefi_exec(handle, load_options); + +out: + ret2 = efi_uninstall_multiple_protocol_interfaces(mem_handle, + &efi_guid_device_path, + file_path, NULL); + efi_free_pool(file_path); + return (ret != EFI_SUCCESS) ? ret : ret2; +} + +/** + * efi_binary_run() - run loaded UEFI image + * + * @image: memory address of the UEFI image + * @size: size of the UEFI image + * @fdt: device-tree + * + * 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 ret; + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + log_err("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return -1; + } + + ret = efi_install_fdt(fdt); + if (ret != EFI_SUCCESS) + return ret; + + return efi_run_image(image, size); +} From 01adf0a408e34a24f7471ff67f3defdeec4c56f3 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:45 +0900 Subject: [PATCH 7/9] cmd: efidebug: ease efi configuration dependency Now it is clear that the command actually depends on interfaces, not "bootefi bootmgr" command. Signed-off-by: AKASHI Takahiro --- cmd/efidebug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 78ef16f4cb5..e10fbf891a4 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1410,7 +1410,7 @@ static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, } static struct cmd_tbl cmd_efidebug_test_sub[] = { -#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR +#ifdef CONFIG_BOOTEFI_BOOTMGR U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr, "", ""), #endif @@ -1604,7 +1604,7 @@ U_BOOT_LONGHELP(efidebug, " - show UEFI memory map\n" "efidebug tables\n" " - show UEFI configuration tables\n" -#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR +#ifdef CONFIG_BOOTEFI_BOOTMGR "efidebug test bootmgr\n" " - run simple bootmgr for test\n" #endif From 7017fc54a5bccd95bebaf371bfa3098fcf84068a Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 21 Nov 2023 10:29:46 +0900 Subject: [PATCH 8/9] bootmeth: use efi_loader interfaces instead of bootefi command Now that efi_loader subsystem provides interfaces that are equivalent with bootefi command, we can replace command invocations with APIs. Signed-off-by: AKASHI Takahiro --- boot/Kconfig | 4 ++-- boot/Makefile | 2 +- boot/bootm_os.c | 38 +++++++++++--------------------------- boot/bootmeth_efi.c | 8 +------- boot/bootmeth_efi_mgr.c | 2 +- cmd/Kconfig | 2 +- test/boot/bootflow.c | 2 +- 7 files changed, 18 insertions(+), 40 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index b438002059c..987ca731411 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -523,7 +523,7 @@ config BOOTMETH_EXTLINUX_PXE config BOOTMETH_EFILOADER bool "Bootdev support for EFI boot" - depends on CMD_BOOTEFI + depends on BOOTEFI_BOOTMGR default y help Enables support for EFI boot using bootdevs. This makes the @@ -558,7 +558,7 @@ config BOOTMETH_DISTRO select BOOTMETH_SCRIPT if CMDLINE # E.g. Armbian uses scripts select BOOTMETH_EXTLINUX # E.g. Debian uses these select BOOTMETH_EXTLINUX_PXE if CMD_PXE && CMD_NET && DM_ETH - select BOOTMETH_EFILOADER if CMD_BOOTEFI # E.g. Ubuntu uses this + select BOOTMETH_EFILOADER if BOOTEFI_BOOTMGR # E.g. Ubuntu uses this config SPL_BOOTMETH_VBE bool "Bootdev support for Verified Boot for Embedded (SPL)" diff --git a/boot/Makefile b/boot/Makefile index de0eafed14b..a90ebea5a86 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -34,7 +34,7 @@ obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_CROS) += bootm.o bootm_os.o bootmeth_cros.o obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_SANDBOX) += bootmeth_sandbox.o obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_SCRIPT) += bootmeth_script.o ifdef CONFIG_$(SPL_TPL_)BOOTSTD_FULL -obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += bootmeth_efi_mgr.o +obj-$(CONFIG_BOOTEFI_BOOTMGR) += bootmeth_efi_mgr.o obj-$(CONFIG_$(SPL_TPL_)EXPO) += bootflow_menu.o obj-$(CONFIG_$(SPL_TPL_)BOOTSTD) += bootflow_menu.o obj-$(CONFIG_$(SPL_TPL_)CEDIT) += cedit.o diff --git a/boot/bootm_os.c b/boot/bootm_os.c index b92422171a8..dc4046ad082 100644 --- a/boot/bootm_os.c +++ b/boot/bootm_os.c @@ -476,43 +476,27 @@ static int do_bootm_tee(int flag, int argc, char *const argv[], static int do_bootm_efi(int flag, int argc, char *const argv[], struct bootm_headers *images) { - efi_status_t efi_ret; + int ret; void *image_buf; if (flag != BOOTM_STATE_OS_GO) return 0; - /* Initialize EFI drivers */ - efi_ret = efi_init_obj_list(); - if (efi_ret != EFI_SUCCESS) { - printf("## Failed to initialize UEFI sub-system: r = %lu\n", - efi_ret & ~EFI_ERROR_MASK); - return 1; - } - - /* Install device tree */ - efi_ret = efi_install_fdt(images->ft_len - ? images->ft_addr : EFI_FDT_USE_INTERNAL); - if (efi_ret != EFI_SUCCESS) { - printf("## Failed to install device tree: r = %lu\n", - efi_ret & ~EFI_ERROR_MASK); - return 1; - } - - /* Run EFI image */ - printf("## Transferring control to EFI (at address %08lx) ...\n", - images->ep); - bootstage_mark(BOOTSTAGE_ID_RUN_OS); - /* We expect to return */ images->os.type = IH_TYPE_STANDALONE; image_buf = map_sysmem(images->ep, images->os.image_len); - efi_ret = efi_run_image(image_buf, images->os.image_len); - if (efi_ret != EFI_SUCCESS) - return 1; - return 0; + /* Run EFI image */ + printf("## Transferring control to EFI (at address %08lx) ...\n", + images->ep); + bootstage_mark(BOOTSTAGE_ID_RUN_OS); + + ret = efi_binary_run(image_buf, images->os.image_len, + images->ft_len + ? images->ft_addr : EFI_FDT_USE_INTERNAL); + + return ret; } #endif diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index 9ba7734911e..d46bff51d8a 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -413,7 +413,6 @@ static int distro_efi_read_bootflow(struct udevice *dev, struct bootflow *bflow) static int distro_efi_boot(struct udevice *dev, struct bootflow *bflow) { ulong kernel, fdt; - char cmd[50]; int ret; kernel = env_get_hex("kernel_addr_r", 0); @@ -442,12 +441,7 @@ static int distro_efi_boot(struct udevice *dev, struct bootflow *bflow) fdt = env_get_hex("fdt_addr_r", 0); } - /* - * At some point we can add a real interface to bootefi so we can call - * this directly. For now, go through the CLI, like distro boot. - */ - snprintf(cmd, sizeof(cmd), "bootefi %lx %lx", kernel, fdt); - if (run_command(cmd, 0)) + if (efi_binary_run(map_sysmem(kernel, 0), 0, map_sysmem(fdt, 0))) return log_msg_ret("run", -EINVAL); return 0; diff --git a/boot/bootmeth_efi_mgr.c b/boot/bootmeth_efi_mgr.c index 6428c096d7f..ed29d7ef021 100644 --- a/boot/bootmeth_efi_mgr.c +++ b/boot/bootmeth_efi_mgr.c @@ -87,7 +87,7 @@ static int efi_mgr_boot(struct udevice *dev, struct bootflow *bflow) int ret; /* Booting is handled by the 'bootefi bootmgr' command */ - ret = run_command("bootefi bootmgr", 0); + ret = efi_bootmgr_run(EFI_FDT_USE_INTERNAL); return 0; } diff --git a/cmd/Kconfig b/cmd/Kconfig index b21a30c08b4..24bfbe50572 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -273,7 +273,7 @@ config CMD_BOOTMETH config BOOTM_EFI bool "Support booting UEFI FIT images" - depends on CMD_BOOTEFI && CMD_BOOTM && FIT + depends on BOOTEFI_BOOTMGR && CMD_BOOTM && FIT default y help Support booting UEFI FIT images via the bootm command. diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 597f624d036..f3e5a839da4 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -374,7 +374,7 @@ static int bootflow_system(struct unit_test_state *uts) { struct udevice *bootstd, *dev; - if (!IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) + if (!IS_ENABLED(CONFIG_BOOTEFI_BOOTMGR)) return -EAGAIN; ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); ut_assertok(device_bind(bootstd, DM_DRIVER_GET(bootmeth_efi_mgr), From 291ab919355df5ee28183546049d5fbdb2777d2d Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Sat, 2 Dec 2023 14:33:14 -0500 Subject: [PATCH 9/9] doc: Replace examples of MD5 and SHA1 with SHA256 Both SHA1 and (especially) MD5 are no longer as safe as they once were for cryptographic use. Replaces examples which use them with examples using SHA256 instead. This will provide more-secure defaults for users who use documentation examples as a base for their own use. This is not too necessary for non-verified-boot scenarios (since someone could just replace the checksum), but I wanted to be complete. Signed-off-by: Sean Anderson Reviewed-by: Peter Robinson Reviewed-by: Simon Glass Reviewed-by: Tom Rini --- doc/chromium/files/chromebook_jerry.its | 4 +- doc/chromium/files/nyan-big.its | 4 +- doc/usage/cmd/imxtract.rst | 6 +- doc/usage/fit/beaglebone_vboot.rst | 74 ++++++++++++------------ doc/usage/fit/howto.rst | 40 ++++++------- doc/usage/fit/kernel.rst | 6 +- doc/usage/fit/kernel_fdt.rst | 4 +- doc/usage/fit/kernel_fdts_compressed.rst | 6 +- doc/usage/fit/multi-with-fpga.rst | 6 +- doc/usage/fit/multi-with-loadables.rst | 8 +-- doc/usage/fit/multi.rst | 12 ++-- doc/usage/fit/sign-configs.rst | 6 +- doc/usage/fit/sign-images.rst | 4 +- doc/usage/fit/signature.rst | 22 +++---- doc/usage/fit/update3.rst | 6 +- doc/usage/fit/update_uboot.rst | 2 +- doc/usage/fit/x86-fit-boot.rst | 8 +-- 17 files changed, 109 insertions(+), 109 deletions(-) diff --git a/doc/chromium/files/chromebook_jerry.its b/doc/chromium/files/chromebook_jerry.its index 7505a20535b..02e5e1340f3 100644 --- a/doc/chromium/files/chromebook_jerry.its +++ b/doc/chromium/files/chromebook_jerry.its @@ -15,7 +15,7 @@ load = <0>; entry = <0>; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; @@ -26,7 +26,7 @@ arch = "arm"; compression = "none"; hash-1{ - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/chromium/files/nyan-big.its b/doc/chromium/files/nyan-big.its index bd412915e95..60bdffbb829 100644 --- a/doc/chromium/files/nyan-big.its +++ b/doc/chromium/files/nyan-big.its @@ -15,7 +15,7 @@ load = <0>; entry = <0>; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; @@ -26,7 +26,7 @@ arch = "arm"; compression = "none"; hash-1{ - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/cmd/imxtract.rst b/doc/usage/cmd/imxtract.rst index eb64b1cefab..16be60b4aab 100644 --- a/doc/usage/cmd/imxtract.rst +++ b/doc/usage/cmd/imxtract.rst @@ -45,14 +45,14 @@ Examples With verify=no incorrect hashes, signatures, or check sums don't stop the extraction. But correct hashes are still indicated in the output -(here: md5, sha1). +(here: sha256, sha512). .. code-block:: console => setenv verify no => imxtract $loadaddr kernel-1 $kernel_addr_r ## Copying 'kernel-1' subimage from FIT image at 40200000 ... - md5+ sha1+ Loading part 0 ... OK + sha256+ sha512+ Loading part 0 ... OK => With verify=yes incorrect hashes, signatures, or check sums stop the extraction. @@ -62,7 +62,7 @@ With verify=yes incorrect hashes, signatures, or check sums stop the extraction. => setenv verify yes => imxtract $loadaddr kernel-1 $kernel_addr_r ## Copying 'kernel-1' subimage from FIT image at 40200000 ... - md5 error! + sha256 error! Bad hash value for 'hash-1' hash node in 'kernel-1' image node Bad Data Hash => diff --git a/doc/usage/fit/beaglebone_vboot.rst b/doc/usage/fit/beaglebone_vboot.rst index a102be187bd..cd6bb141910 100644 --- a/doc/usage/fit/beaglebone_vboot.rst +++ b/doc/usage/fit/beaglebone_vboot.rst @@ -145,7 +145,7 @@ Put this into a file in that directory called sign.its:: load = <0x80008000>; entry = <0x80008000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; fdt-1 { @@ -155,7 +155,7 @@ Put this into a file in that directory called sign.its:: arch = "arm"; compression = "none"; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; }; @@ -165,7 +165,7 @@ Put this into a file in that directory called sign.its:: kernel = "kernel"; fdt = "fdt-1"; signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; key-name-hint = "dev"; sign-images = "fdt", "kernel"; }; @@ -227,8 +227,8 @@ You should see something like this:: OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 + Hash algo: sha256 + Hash value: 51b2adf9c1016ed46f424d85dcc6c34c46a20b9bee7227e06a6b6320ca5d35c1 Image 1 (fdt-1) Description: beaglebone-black Created: Sun Jun 1 12:50:30 2014 @@ -236,8 +236,8 @@ You should see something like this:: Compression: uncompressed Data Size: 31547 Bytes = 30.81 kB = 0.03 MB Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d + Hash algo: sha256 + Hash value: 807d5842a04132261ba092373bd40c78991bc7ce173d1175cd976ec37858e7cd Default Configuration: 'conf-1' Configuration 0 (conf-1) Description: unavailable @@ -255,11 +255,11 @@ You can also run fit_check_sign to check it:: which results in:: - Verifying Hash Integrity ... sha1,rsa2048:dev+ + Verifying Hash Integrity ... sha256,rsa2048:dev+ ## Loading kernel from FIT Image at 7fc6ee469000 ... Using 'conf-1' configuration Verifying Hash Integrity ... - sha1,rsa2048:dev+ + sha256,rsa2048:dev+ OK Trying 'kernel' kernel subimage @@ -272,10 +272,10 @@ which results in:: OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 + Hash algo: sha256 + Hash value: 51b2adf9c1016ed46f424d85dcc6c34c46a20b9bee7227e06a6b6320ca5d35c1 Verifying Hash Integrity ... - sha1+ + sha256+ OK Unimplemented compression type 4 @@ -288,10 +288,10 @@ which results in:: Compression: uncompressed Data Size: 31547 Bytes = 30.81 kB = 0.03 MB Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d + Hash algo: sha256 + Hash value: 807d5842a04132261ba092373bd40c78991bc7ce173d1175cd976ec37858e7cd Verifying Hash Integrity ... - sha1+ + sha256+ OK Loading Flat Device Tree ... OK @@ -303,14 +303,14 @@ which results in:: Signature check OK -At the top, you see "sha1,rsa2048:dev+". This means that it checked an RSA key -of size 2048 bits using SHA1 as the hash algorithm. The key name checked was +At the top, you see "sha256,rsa2048:dev+". This means that it checked an RSA key +of size 2048 bits using SHA256 as the hash algorithm. The key name checked was 'dev' and the '+' means that it verified. If it showed '-' that would be bad. Once the configuration is verified it is then possible to rely on the hashes in each image referenced by that configuration. So fit_check_sign goes on to load each of the images. We have a kernel and an FDT but no ramkdisk. In each -case fit_check_sign checks the hash and prints sha1+ meaning that the SHA1 +case fit_check_sign checks the hash and prints sha256+ meaning that the SHA256 hash verified. This means that none of the images has been tampered with. There is a test in test/vboot which uses U-Boot's sandbox build to verify that @@ -328,11 +328,11 @@ This tells us that the kernel starts at byte offset 168 (decimal) in image.fit and extends for about 7MB. Try changing a byte at 0x2000 (say) and run fit_check_sign again. You should see something like:: - Verifying Hash Integrity ... sha1,rsa2048:dev+ + Verifying Hash Integrity ... sha256,rsa2048:dev+ ## Loading kernel from FIT Image at 7f5a39571000 ... Using 'conf-1' configuration Verifying Hash Integrity ... - sha1,rsa2048:dev+ + sha256,rsa2048:dev+ OK Trying 'kernel' kernel subimage @@ -345,10 +345,10 @@ fit_check_sign again. You should see something like:: OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 + Hash algo: sha256 + Hash value: 51b2adf9c1016ed46f424d85dcc6c34c46a20b9bee7227e06a6b6320ca5d35c1 Verifying Hash Integrity ... - sha1 error + sha256 error Bad hash value for 'hash-1' hash node in 'kernel' image node Bad Data Hash @@ -361,10 +361,10 @@ fit_check_sign again. You should see something like:: Compression: uncompressed Data Size: 31547 Bytes = 30.81 kB = 0.03 MB Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d + Hash algo: sha256 + Hash value: 807d5842a04132261ba092373bd40c78991bc7ce173d1175cd976ec37858e7cd Verifying Hash Integrity ... - sha1+ + sha256+ OK Loading Flat Device Tree ... OK @@ -419,13 +419,13 @@ need to change the hash to match. Let's simulate that by changing a byte of the hash:: fdtget -tx image.fit /images/kernel/hash-1 value - c9436464 6427e10f 423837e5 59898ef0 2c97b988 - fdtput -tx image.fit /images/kernel/hash-1 value c9436464 6427e10f 423837e5 59898ef0 2c97b981 + 51b2adf9 c1016ed4 6f424d85 dcc6c34c 46a20b9b ee7227e0 6a6b6320 ca5d35c1 + fdtput -tx image.fit /images/kernel/hash-1 value 51b2adf9 c1016ed4 6f424d85 dcc6c34c 46a20b9b ee7227e0 6a6b6320 ca5d35c8 Now check it again:: $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb - Verifying Hash Integrity ... sha1,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13 + Verifying Hash Integrity ... sha256,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13 rsa_verify_with_keynode: RSA failed to verify: -13 - Failed to verify required signature 'key-dev' @@ -446,7 +446,7 @@ running the mkimage link again. Then:: fdtput -p image.fit /configurations/conf-1/signature-1 value fred $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb Verifying Hash Integrity ... - - sha1,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13 + sha256,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13 rsa_verify_with_keynode: RSA failed to verify: -13 - Failed to verify required signature 'key-dev' @@ -528,7 +528,7 @@ You should then see something like this:: U-Boot# bootm 82000000 ## Loading kernel from FIT Image at 82000000 ... Using 'conf-1' configuration - Verifying Hash Integrity ... sha1,rsa2048:dev+ OK + Verifying Hash Integrity ... sha256,rsa2048:dev+ OK Trying 'kernel' kernel subimage Description: unavailable Created: 2014-06-01 19:32:54 UTC @@ -540,9 +540,9 @@ You should then see something like this:: OS: Linux Load Address: 0x80008000 Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 - Verifying Hash Integrity ... sha1+ OK + Hash algo: sha256 + Hash value: 51b2adf9c1016ed46f424d85dcc6c34c46a20b9bee7227e06a6b6320ca5d35c1 + Verifying Hash Integrity ... sha256+ OK ## Loading fdt from FIT Image at 82000000 ... Using 'conf-1' configuration Trying 'fdt-1' fdt subimage @@ -553,9 +553,9 @@ You should then see something like this:: Data Start: 0x8276e2ec Data Size: 31547 Bytes = 30.8 KiB Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d - Verifying Hash Integrity ... sha1+ OK + Hash algo: sha256 + Hash value: 807d5842a04132261ba092373bd40c78991bc7ce173d1175cd976ec37858e7cd + Verifying Hash Integrity ... sha256+ OK Booting using the fdt blob at 0x8276e2ec Uncompressing Kernel Image ... OK Loading Device Tree to 8fff5000, end 8ffffb3a ... OK diff --git a/doc/usage/fit/howto.rst b/doc/usage/fit/howto.rst index def12a70f7b..b5097d4460b 100644 --- a/doc/usage/fit/howto.rst +++ b/doc/usage/fit/howto.rst @@ -8,7 +8,7 @@ Overview The new uImage format allows more flexibility in handling images of various types (kernel, ramdisk, etc.), it also enhances integrity protection of images -with sha1 and md5 checksums. +with cryptographic checksums. Two auxiliary tools are needed on the development host system in order to create an uImage in the new format: mkimage and dtc, although only one @@ -99,7 +99,7 @@ started by ATF where SPL is loading U-Boot (as loadables) and ATF (as firmware). load = <0x8 0x8000000>; entry = <0x8 0x8000000>; hash { - algo = "md5"; + algo = "sha256"; }; }; atf { @@ -112,7 +112,7 @@ started by ATF where SPL is loading U-Boot (as loadables) and ATF (as firmware). load = <0xfffea000>; entry = <0xfffea000>; hash { - algo = "md5"; + algo = "sha256"; }; }; fdt_1 { @@ -123,7 +123,7 @@ started by ATF where SPL is loading U-Boot (as loadables) and ATF (as firmware). compression = "none"; load = <0x100000>; hash { - algo = "md5"; + algo = "sha256"; }; }; }; @@ -190,8 +190,8 @@ its contents: Entry Point: 0x00000000 Hash algo: crc32 Hash value: 2ae2bb40 - Hash algo: sha1 - Hash value: 3c200f34e2c226ddc789240cca0c59fc54a67cf4 + Hash algo: sha256 + Hash value: c22f6bb5a3f96942507a37e7d6a9333ebdc7da57971bc4c082113fe082fdc40f Default Configuration: 'config-1' Configuration 0 (config-1) Description: Boot Linux kernel @@ -236,8 +236,8 @@ specific to the new image format). Entry Point: 0x00000000 Hash algo: crc32 Hash value: 2ae2bb40 - Hash algo: sha1 - Hash value: 3c200f34e2c226ddc789240cca0c59fc54a67cf4 + Hash algo: sha256 + Hash value: c22f6bb5a3f96942507a37e7d6a9333ebdc7da57971bc4c082113fe082fdc40f Default Configuration: 'config-1' Configuration 0 (config-1) Description: Boot Linux kernel @@ -258,8 +258,8 @@ specific to the new image format). Entry Point: 0x00000000 Hash algo: crc32 Hash value: 2ae2bb40 - Hash algo: sha1 - Hash value: 3c200f34e2c226ddc789240cca0c59fc54a67cf4 + Hash algo: sha256 + Hash value: c22f6bb5a3f96942507a37e7d6a9333ebdc7da57971bc4c082113fe082fdc40f Verifying Hash Integrity ... crc32+ sha1+ OK Uncompressing Kernel Image ... OK Memory BAT mapping: BAT2=256Mb, BAT3=0Mb, residual: 0Mb @@ -302,8 +302,8 @@ modified to take the files from some other location if needed): Entry Point: 0x00000000 Hash algo: crc32 Hash value: 2c0cc807 - Hash algo: sha1 - Hash value: 264b59935470e42c418744f83935d44cdf59a3bb + Hash algo: sha256 + Hash value: a3e9e18b793873827d27c97edfbca67c404a1972d9f36cf48e73ff85d69a422c Image 1 (fdt-1) Description: Flattened Device Tree blob Type: Flat Device Tree @@ -312,8 +312,8 @@ modified to take the files from some other location if needed): Architecture: PowerPC Hash algo: crc32 Hash value: 0d655d71 - Hash algo: sha1 - Hash value: 25ab4e15cd4b8a5144610394560d9c318ce52def + Hash algo: sha256 + Hash value: e9b9a40c5e2e12213ac819e7ccad7271ef43eb5edf9b421f0fa0b4b51bfdb214 Default Configuration: 'conf-1' Configuration 0 (conf-1) Description: Boot Linux kernel with FDT blob @@ -353,8 +353,8 @@ inspected and booted: Entry Point: 0x00000000 Hash algo: crc32 Hash value: 2c0cc807 - Hash algo: sha1 - Hash value: 264b59935470e42c418744f83935d44cdf59a3bb + Hash algo: sha256 + Hash value: a3e9e18b793873827d27c97edfbca67c404a1972d9f36cf48e73ff85d69a422c Image 1 (fdt-1) Description: Flattened Device Tree blob Type: Flat Device Tree @@ -364,8 +364,8 @@ inspected and booted: Architecture: PowerPC Hash algo: crc32 Hash value: 0d655d71 - Hash algo: sha1 - Hash value: 25ab4e15cd4b8a5144610394560d9c318ce52def + Hash algo: sha256 + Hash value: e9b9a40c5e2e12213ac819e7ccad7271ef43eb5edf9b421f0fa0b4b51bfdb214 Default Configuration: 'conf-1' Configuration 0 (conf-1) Description: Boot Linux kernel with FDT blob @@ -387,7 +387,7 @@ inspected and booted: Hash algo: crc32 Hash value: 2c0cc807 Hash algo: sha1 - Hash value: 264b59935470e42c418744f83935d44cdf59a3bb + Hash value: a3e9e18b793873827d27c97edfbca67c404a1972d9f36cf48e73ff85d69a422c Verifying Hash Integrity ... crc32+ sha1+ OK Uncompressing Kernel Image ... OK ## Flattened Device Tree from FIT Image at 00900000 @@ -402,7 +402,7 @@ inspected and booted: Hash algo: crc32 Hash value: 0d655d71 Hash algo: sha1 - Hash value: 25ab4e15cd4b8a5144610394560d9c318ce52def + Hash value: e9b9a40c5e2e12213ac819e7ccad7271ef43eb5edf9b421f0fa0b4b51bfdb214 Verifying Hash Integrity ... crc32+ sha1+ OK Booting using the fdt blob at 0xa0abdc Loading Device Tree to 007fc000, end 007fffff ... OK diff --git a/doc/usage/fit/kernel.rst b/doc/usage/fit/kernel.rst index 012a81efead..e56017985b2 100644 --- a/doc/usage/fit/kernel.rst +++ b/doc/usage/fit/kernel.rst @@ -25,7 +25,7 @@ Single kernel algo = "crc32"; }; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; }; @@ -59,7 +59,7 @@ For x86 a setup node is also required: see x86-fit-boot:: load = <0x01000000>; entry = <0x00000000>; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; @@ -73,7 +73,7 @@ For x86 a setup node is also required: see x86-fit-boot:: load = <0x00090000>; entry = <0x00090000>; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/kernel_fdt.rst b/doc/usage/fit/kernel_fdt.rst index 8eee13af780..9cc26fb7831 100644 --- a/doc/usage/fit/kernel_fdt.rst +++ b/doc/usage/fit/kernel_fdt.rst @@ -25,7 +25,7 @@ Single kernel and FDT blob algo = "crc32"; }; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; fdt-1 { @@ -38,7 +38,7 @@ Single kernel and FDT blob algo = "crc32"; }; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/kernel_fdts_compressed.rst b/doc/usage/fit/kernel_fdts_compressed.rst index 0b169c7c27c..b57871da58b 100644 --- a/doc/usage/fit/kernel_fdts_compressed.rst +++ b/doc/usage/fit/kernel_fdts_compressed.rst @@ -28,7 +28,7 @@ string to match directly. algo = "crc32"; }; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; fdt@1 { @@ -41,7 +41,7 @@ string to match directly. algo = "crc32"; }; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; fdt@2 { @@ -54,7 +54,7 @@ string to match directly. algo = "crc32"; }; hash-2 { - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/multi-with-fpga.rst b/doc/usage/fit/multi-with-fpga.rst index 28d7d5d2626..4c7f1bebd5a 100644 --- a/doc/usage/fit/multi-with-fpga.rst +++ b/doc/usage/fit/multi-with-fpga.rst @@ -20,7 +20,7 @@ This example makes use of the 'loadables' field:: compression = "none"; load = <0x10000000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; }; @@ -33,7 +33,7 @@ This example makes use of the 'loadables' field:: load = <0x30000000>; compatible = "u-boot,fpga-legacy" hash-1 { - algo = "md5"; + algo = "sha256"; }; }; @@ -47,7 +47,7 @@ This example makes use of the 'loadables' field:: load = <0x8000>; entry = <0x8000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/multi-with-loadables.rst b/doc/usage/fit/multi-with-loadables.rst index a0241df96ca..7849cb544f1 100644 --- a/doc/usage/fit/multi-with-loadables.rst +++ b/doc/usage/fit/multi-with-loadables.rst @@ -22,7 +22,7 @@ This example makes use of the 'loadables' field:: load = <0xa0000000>; entry = <0xa0000000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; }; @@ -34,7 +34,7 @@ This example makes use of the 'loadables' field:: compression = "none"; load = <0xb0000000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; }; @@ -46,7 +46,7 @@ This example makes use of the 'loadables' field:: compression = "none"; load = <0xb0400000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; }; @@ -60,7 +60,7 @@ This example makes use of the 'loadables' field:: load = <0xa0000000>; entry = <0xa0000000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/multi.rst b/doc/usage/fit/multi.rst index 2e6ae58c409..e68752b2ad0 100644 --- a/doc/usage/fit/multi.rst +++ b/doc/usage/fit/multi.rst @@ -22,10 +22,10 @@ Multiple kernels, ramdisks and FDT blobs load = <00000000>; entry = <00000000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; hash-2 { - algo = "sha1"; + algo = "sha512"; }; }; @@ -39,7 +39,7 @@ Multiple kernels, ramdisks and FDT blobs load = <00000000>; entry = <00000000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; @@ -53,7 +53,7 @@ Multiple kernels, ramdisks and FDT blobs load = <00000000>; entry = <00000000>; hash-1 { - algo = "md5"; + algo = "sha256"; }; }; @@ -67,7 +67,7 @@ Multiple kernels, ramdisks and FDT blobs load = <00000000>; entry = <00000000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; @@ -104,7 +104,7 @@ Multiple kernels, ramdisks and FDT blobs compression = "none"; load = <00700000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; diff --git a/doc/usage/fit/sign-configs.rst b/doc/usage/fit/sign-configs.rst index 6a3df8f2c5b..6d98d44430c 100644 --- a/doc/usage/fit/sign-configs.rst +++ b/doc/usage/fit/sign-configs.rst @@ -22,7 +22,7 @@ Signed configurations entry = <0x8>; kernel-version = <1>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; fdt-1 { @@ -33,7 +33,7 @@ Signed configurations compression = "none"; fdt-version = <1>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; }; @@ -43,7 +43,7 @@ Signed configurations kernel = "kernel"; fdt = "fdt-1"; signature { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; key-name-hint = "dev"; sign-images = "fdt", "kernel"; }; diff --git a/doc/usage/fit/sign-images.rst b/doc/usage/fit/sign-images.rst index 7d54d702c97..ca7d10fab83 100644 --- a/doc/usage/fit/sign-images.rst +++ b/doc/usage/fit/sign-images.rst @@ -22,7 +22,7 @@ Signed Images entry = <0x8>; kernel-version = <1>; signature { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; key-name-hint = "dev"; }; }; @@ -34,7 +34,7 @@ Signed Images compression = "none"; fdt-version = <1>; signature { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; key-name-hint = "dev"; }; }; diff --git a/doc/usage/fit/signature.rst b/doc/usage/fit/signature.rst index 0804bffd1ed..39edba14630 100644 --- a/doc/usage/fit/signature.rst +++ b/doc/usage/fit/signature.rst @@ -93,7 +93,7 @@ Public keys should be stored as sub-nodes in a /signature node. Required properties are: algo - Algorithm name (e.g. "sha1,rsa2048" or "sha256,ecdsa256") + Algorithm name (e.g. "sha256,rsa2048" or "sha512,ecdsa256") Optional properties are: @@ -219,28 +219,28 @@ As an example, consider this FIT:: kernel-1 { data = signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...kernel signature 1...> }; }; kernel-2 { data = signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...kernel signature 2...> }; }; fdt-1 { data = ; signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...fdt signature 1...> }; }; fdt-2 { data = ; signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...fdt signature 2...> }; }; @@ -291,28 +291,28 @@ So the above example is adjusted to look like this:: kernel-1 { data = hash-1 { - algo = "sha1"; + algo = "sha256"; value = <...kernel hash 1...> }; }; kernel-2 { data = hash-1 { - algo = "sha1"; + algo = "sha256"; value = <...kernel hash 2...> }; }; fdt-1 { data = ; hash-1 { - algo = "sha1"; + algo = "sha256"; value = <...fdt hash 1...> }; }; fdt-2 { data = ; hash-1 { - algo = "sha1"; + algo = "sha256"; value = <...fdt hash 2...> }; }; @@ -323,7 +323,7 @@ So the above example is adjusted to look like this:: kernel = "kernel-1"; fdt = "fdt-1"; signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...conf 1 signature...>; }; }; @@ -331,7 +331,7 @@ So the above example is adjusted to look like this:: kernel = "kernel-2"; fdt = "fdt-2"; signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...conf 1 signature...>; }; }; diff --git a/doc/usage/fit/update3.rst b/doc/usage/fit/update3.rst index 4ff3950c01e..24235801470 100644 --- a/doc/usage/fit/update3.rst +++ b/doc/usage/fit/update3.rst @@ -19,7 +19,7 @@ Automatic software update: multiple files type = "firmware"; load = ; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; update-2 { @@ -29,7 +29,7 @@ Automatic software update: multiple files type = "firmware"; load = ; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; @@ -40,7 +40,7 @@ Automatic software update: multiple files type = "firmware"; load = ; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/update_uboot.rst b/doc/usage/fit/update_uboot.rst index a9288ee6367..811d008d13d 100644 --- a/doc/usage/fit/update_uboot.rst +++ b/doc/usage/fit/update_uboot.rst @@ -21,7 +21,7 @@ Make sure the flashing addresses ('load' prop) is correct for your board! type = "firmware"; load = <0xFFFC0000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/x86-fit-boot.rst b/doc/usage/fit/x86-fit-boot.rst index 93b73bb9019..9e3e32204d5 100644 --- a/doc/usage/fit/x86-fit-boot.rst +++ b/doc/usage/fit/x86-fit-boot.rst @@ -207,16 +207,16 @@ You can take a look at the resulting fit file if you like:: OS: Linux Load Address: 0x01000000 Entry Point: 0x00000000 - Hash algo: sha1 - Hash value: 446b5163ebfe0fb6ee20cbb7a8501b263cd92392 + Hash algo: sha256 + Hash value: 4bbf49981ade163ed089f8525236fedfe44508e9b02a21a48294a96a1518107b Image 1 (setup) Description: Linux setup.bin Created: Tue Oct 7 10:57:24 2014 Type: x86 setup.bin Compression: uncompressed Data Size: 12912 Bytes = 12.61 kB = 0.01 MB - Hash algo: sha1 - Hash value: a1f2099cf47ff9816236cd534c77af86e713faad + Hash algo: sha256 + Hash value: 6aa50c2e0392cb119cdf0971dce8339f100608ed3757c8200b0e39e889e432d2 Default Configuration: 'config-1' Configuration 0 (config-1) Description: Boot Linux kernel