diff options
28 files changed, 771 insertions, 729 deletions
diff --git a/boot/Kconfig b/boot/Kconfig index b438002..987ca73 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 de0eafe..a90ebea 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 b924221..dc4046a 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; - } + /* We expect to return */ + images->os.type = IH_TYPE_STANDALONE; - /* 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; - } + image_buf = map_sysmem(images->ep, images->os.image_len); /* 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; + ret = efi_binary_run(image_buf, images->os.image_len, + images->ft_len + ? images->ft_addr : EFI_FDT_USE_INTERNAL); - 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; + return ret; } #endif diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index 9ba7734..d46bff5 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 6428c09..ed29d7e 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 748b959..24bfbe5 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. @@ -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 2ed29ad..9cf9027 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -7,555 +7,23 @@ #define LOG_CATEGORY LOGC_EFI -#include <common.h> -#include <bootm.h> -#include <charset.h> #include <command.h> -#include <dm.h> +#include <efi.h> #include <efi_loader.h> -#include <efi_selftest.h> -#include <env.h> -#include <errno.h> -#include <image.h> +#include <exports.h> #include <log.h> #include <malloc.h> -#include <asm/global_data.h> -#include <linux/libfdt.h> -#include <linux/libfdt_env.h> #include <mapmem.h> -#include <memalign.h> +#include <vsprintf.h> #include <asm-generic/sections.h> -#include <linux/linkage.h> +#include <asm/global_data.h> +#include <linux/string.h> DECLARE_GLOBAL_DATA_PTR; -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; -} - -/** - * do_efibootmgr() - execute EFI boot manager - * - * Return: status code - */ -static int do_efibootmgr(void) -{ - efi_handle_t handle; - efi_status_t ret; - void *load_options; - - 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; - } - - ret = do_bootefi_exec(handle, load_options); - - if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - - 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; +static struct efi_device_path *test_image_path; +static struct efi_device_path *test_device_path; - 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; - 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; -} - -#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, @@ -597,23 +65,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; } @@ -638,6 +109,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 @@ -645,7 +118,6 @@ static int do_efi_selftest(void) return ret != EFI_SUCCESS; } -#endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ /** * do_bootefi() - execute `bootefi` command @@ -660,20 +132,15 @@ 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; + void *image_addr; + size_t image_size; 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; @@ -682,32 +149,81 @@ 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")) { + ret = efi_bootmgr_run(fdt); + + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; } -#ifdef CONFIG_CMD_BOOTEFI_SELFTEST - if (!strcmp(argv[1], "selftest")) + + 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(); -#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; + 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; + /* TODO: not sure calling clear function is necessary */ + efi_clear_bootdev(); + } else { + 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 { + /* 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]); + return CMD_RET_FAILURE; + } + size = image_size; + } + } + + ret = efi_binary_run(image_buf, size, fdt); + + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; } U_BOOT_LONGHELP(bootefi, diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 78ef16f..e10fbf8 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 diff --git a/doc/chromium/files/chromebook_jerry.its b/doc/chromium/files/chromebook_jerry.its index 7505a20..02e5e13 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 bd41291..60bdffb 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 eb64b1c..16be60b 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 a102be1..cd6bb14 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 def12a7..b5097d4 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 012a81e..e560179 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 8eee13a..9cc26fb 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 0b169c7..b57871d 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 28d7d5d..4c7f1be 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 a0241df..7849cb5 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 2e6ae58..e68752b 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 6a3df8f..6d98d44 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 7d54d70..ca7d10f 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 0804bff..39edba1 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 = <data for kernel1> signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...kernel signature 1...> }; }; kernel-2 { data = <data for kernel2> signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...kernel signature 2...> }; }; fdt-1 { data = <data for fdt1>; signature-1 { - algo = "sha1,rsa2048"; + algo = "sha256,rsa2048"; value = <...fdt signature 1...> }; }; fdt-2 { data = <data for fdt2>; 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 = <data for kernel1> hash-1 { - algo = "sha1"; + algo = "sha256"; value = <...kernel hash 1...> }; }; kernel-2 { data = <data for kernel2> hash-1 { - algo = "sha1"; + algo = "sha256"; value = <...kernel hash 2...> }; }; fdt-1 { data = <data for fdt1>; hash-1 { - algo = "sha1"; + algo = "sha256"; value = <...fdt hash 1...> }; }; fdt-2 { data = <data for fdt2>; 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 4ff3950..2423580 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 = <FF700000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; update-2 { @@ -29,7 +29,7 @@ Automatic software update: multiple files type = "firmware"; load = <FF8E0000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; @@ -40,7 +40,7 @@ Automatic software update: multiple files type = "firmware"; load = <FFAC0000>; hash-1 { - algo = "sha1"; + algo = "sha256"; }; }; }; diff --git a/doc/usage/fit/update_uboot.rst b/doc/usage/fit/update_uboot.rst index a9288ee..811d008 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 93b73bb..9e3e322 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 diff --git a/include/efi_loader.h b/include/efi_loader.h index 664dae2..34e7fbb 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 */ @@ -879,14 +889,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, diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 48153bd..56d97f2 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 <efi_variable.h> #include <asm/unaligned.h> +/* TODO: temporarily added here; clean up later */ +#include <bootm.h> +#include <efi_selftest.h> +#include <env.h> +#include <mapmem.h> +#include <asm/global_data.h> +#include <linux/libfdt.h> +#include <linux/libfdt_env.h> + +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); +} diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 597f624..f3e5a83 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), |