
In this patch, do_bootefi() and do_bootefi_exec() will be reworked, without any functional change so that load_image() API as well as start_image() are used in the implementation.
Signed-off-by: AKASHI Takahiro takahiro.akashi@linaro.org --- cmd/bootefi.c | 252 ++++++++++++++++++++++------------ lib/efi_loader/efi_boottime.c | 14 +- 2 files changed, 170 insertions(+), 96 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 1470122af266..00cacbdd4231 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -236,6 +236,7 @@ static int efi_process_fdt(const char *fdt_opt) * do_bootefi_exec() - execute EFI binary * * @efi: address of the binary + * @efi_size: size of the binary * @device_path: path of the device from which the binary was loaded * @image_path: device path of the binary * Return: status code @@ -243,15 +244,16 @@ static int efi_process_fdt(const char *fdt_opt) * 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(void *efi, +static efi_status_t do_bootefi_exec(void *efi, efi_uintn_t efi_size, struct efi_device_path *device_path, struct efi_device_path *image_path) { - efi_handle_t mem_handle = NULL; + efi_handle_t mem_handle = NULL, handle; struct efi_device_path *memdp = NULL; - efi_status_t ret; + struct efi_device_path *file_path = NULL; struct efi_loaded_image_obj *image_obj = NULL; struct efi_loaded_image *loaded_image_info = NULL; + efi_status_t ret;
/* * Special case for efi payload not loaded from disk, such as @@ -260,36 +262,42 @@ static efi_status_t do_bootefi_exec(void *efi, */ if (!device_path && !image_path) { printf("WARNING: using memory device/image path, this may confuse some payloads!\n"); - /* actual addresses filled in after efi_load_pe() */ + /* actual addresses filled in after efi_load_image() */ memdp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0); - device_path = image_path = memdp; + file_path = memdp; /* append(memdp, NULL) */ /* - * Grub expects that the device path of the loaded image is - * installed on a handle. + * Make sure that device for device_path exist + * in load_image(). Otherwise, shell and grub will fail. */ ret = efi_create_handle(&mem_handle); - if (ret != EFI_SUCCESS) + if (ret != EFI_SUCCESS) { + efi_free_pool(memdp); return ret; /* TODO: leaks device_path */ + } ret = efi_add_protocol(mem_handle, &efi_guid_device_path, - device_path); + memdp); if (ret != EFI_SUCCESS) goto err_add_protocol; } else { assert(device_path && image_path); + file_path = efi_dp_append(device_path, image_path); }
- ret = efi_setup_loaded_image(device_path, image_path, &image_obj, - &loaded_image_info); - if (ret) + ret = EFI_CALL(efi_load_image(false, (void *)0x1 /* FIXME */, file_path, + efi, efi_size, &handle)); + if (ret != EFI_SUCCESS) goto err_prepare;
/* Transfer environment variable as load options */ - set_load_options(loaded_image_info, "bootargs"); - - /* Load the EFI payload */ - ret = efi_load_pe(image_obj, efi, loaded_image_info); + ret = EFI_CALL(systab.boottime->open_protocol( + handle, + &efi_guid_loaded_image, + (void **)&loaded_image_info, + NULL, NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)); if (ret != EFI_SUCCESS) goto err_prepare; + set_load_options(loaded_image_info, "bootargs");
if (memdp) { struct efi_device_path_memory *mdp = (void *)memdp; @@ -304,41 +312,154 @@ static efi_status_t do_bootefi_exec(void *efi, "{ro,boot}(blob)0000000000000000");
/* Call our payload! */ + image_obj = container_of(handle, struct efi_loaded_image_obj, header); debug("%s: Jumping to 0x%p\n", __func__, image_obj->entry); - ret = EFI_CALL(efi_start_image(&image_obj->header, NULL, NULL)); + ret = EFI_CALL(efi_start_image(handle, NULL, NULL));
err_prepare: - /* image has returned, loaded-image obj goes *poof*: */ efi_restore_gd(); free(loaded_image_info->load_options); - efi_delete_handle(&image_obj->header); + ret = EFI_CALL(efi_unload_image(handle));
err_add_protocol: if (mem_handle) efi_delete_handle(mem_handle); + if (device_path) + efi_free_pool(file_path);
return ret; }
-static int do_bootefi_bootmgr_exec(void) +/** + * do_efibootmgr() - execute EFI Boot Manager + * + * @fdt_opt: string of fdt start address + * Return: status code + * + * Execute EFI Boot Manager + */ +static int do_efibootmgr(const char *fdt_opt) +{ + void *image_buf; + efi_uintn_t buf_size; + struct efi_device_path *device_path, *image_path; + unsigned long addr; + efi_status_t r; + int ret; + + /* Allow unaligned memory access */ + allow_unaligned(); + + switch_to_non_secure_mode(); + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot set up EFI drivers, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_process_fdt(fdt_opt); + if (ret != EFI_SUCCESS) + return ret; + + r = efi_bootmgr_load(&device_path, &image_path, &image_buf, &buf_size); + if (r != EFI_SUCCESS) + return CMD_RET_FAILURE; + + addr = map_to_sysmem(image_buf); + + printf("## Starting EFI application at %08lx ...\n", addr); + r = do_bootefi_exec(image_buf, buf_size, device_path, image_path); + printf("## Application terminated, r = %lu\n", r & ~EFI_ERROR_MASK); + + if (r != EFI_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; +} + +/* + * do_boot_efi() - execute EFI binary from command line + * + * @image_opt: string of image start address + * @fdt_opt: string of fdt start address + * Return: status code + * + * Set up memory image for the binary to be loaded, prepare + * device path and then call do_bootefi_exec() to execute it. + */ +static int do_boot_efi(const char *image_opt, const char *fdt_opt) { - struct efi_device_path *device_path, *file_path; - void *addr; + void *image_buf; + struct efi_device_path *device_path, *image_path; + const char *saddr; + unsigned long addr, size; + const char *size_str; efi_status_t r;
- addr = efi_bootmgr_load(&device_path, &file_path); - if (!addr) - return 1; + /* Allow unaligned memory access */ + allow_unaligned();
- printf("## Starting EFI application at %p ...\n", addr); - r = do_bootefi_exec(addr, device_path, file_path); - printf("## Application terminated, r = %lu\n", - r & ~EFI_ERROR_MASK); + switch_to_non_secure_mode();
+ /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot set up EFI drivers, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + r = efi_process_fdt(fdt_opt); if (r != EFI_SUCCESS) - return 1; + return r;
- return 0; +#ifdef CONFIG_CMD_BOOTEFI_HELLO + if (!strcmp(image_opt, "hello")) { + saddr = env_get("loadaddr"); + size = __efi_helloworld_end - __efi_helloworld_begin; + + if (saddr) + addr = simple_strtoul(saddr, NULL, 16); + else + addr = CONFIG_SYS_LOAD_ADDR; + + image_buf = map_sysmem(addr, size); + memcpy(image_buf, __efi_helloworld_begin, size); + + device_path = NULL; + image_path = NULL; + } else +#endif + { + saddr = image_opt; + size_str = env_get("filesize"); + if (size_str) + size = simple_strtoul(size_str, NULL, 16); + else + size = 0; + + addr = simple_strtoul(saddr, NULL, 16); + /* Check that a numeric value was passed */ + if (!addr && *saddr != '0') + return CMD_RET_USAGE; + + image_buf = map_sysmem(addr, size); + + device_path = bootefi_device_path; + image_path = bootefi_image_path; + } + + printf("## Starting EFI application at %08lx ...\n", addr); + r = do_bootefi_exec(image_buf, size, device_path, image_path); + printf("## Application terminated, r = %lu\n", r & ~EFI_ERROR_MASK); + + if (r != EFI_SUCCESS) + return CMD_RET_FAILURE; + + return CMD_RET_SUCCESS; }
#ifdef CONFIG_CMD_BOOTEFI_SELFTEST @@ -468,69 +589,17 @@ static int do_efi_selftest(const char *fdt_opt) /* Interpreter command to boot an arbitrary EFI image from memory */ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - unsigned long addr; - char *saddr; - efi_status_t r; - unsigned long fdt_addr; - if (argc < 2) return CMD_RET_USAGE; + + if (!strcmp(argv[1], "bootmgr")) + return do_efibootmgr(argc > 2 ? argv[2] : NULL); #ifdef CONFIG_CMD_BOOTEFI_SELFTEST else if (!strcmp(argv[1], "selftest")) return do_efi_selftest(argc > 2 ? argv[2] : NULL); #endif
- /* Allow unaligned memory access */ - allow_unaligned(); - - switch_to_non_secure_mode(); - - /* Initialize EFI drivers */ - r = efi_init_obj_list(); - if (r != EFI_SUCCESS) { - printf("Error: Cannot set up EFI drivers, r = %lu\n", - r & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } - - ret = fdt_process_fdt(argc > 2 ? argv[2] : NULL); - if (ret != EFI_SUCCESS) - return ret; - -#ifdef CONFIG_CMD_BOOTEFI_HELLO - if (!strcmp(argv[1], "hello")) { - ulong size = __efi_helloworld_end - __efi_helloworld_begin; - - saddr = env_get("loadaddr"); - if (saddr) - addr = simple_strtoul(saddr, NULL, 16); - else - addr = CONFIG_SYS_LOAD_ADDR; - memcpy(map_sysmem(addr, size), __efi_helloworld_begin, size); - } else -#endif - if (!strcmp(argv[1], "bootmgr")) { - return do_bootefi_bootmgr_exec(); - } else { - saddr = argv[1]; - - addr = simple_strtoul(saddr, NULL, 16); - /* Check that a numeric value was passed */ - if (!addr && *saddr != '0') - return CMD_RET_USAGE; - - } - - printf("## Starting EFI application at %08lx ...\n", addr); - r = do_bootefi_exec(map_sysmem(addr, 0), bootefi_device_path, - bootefi_image_path); - printf("## Application terminated, r = %lu\n", - r & ~EFI_ERROR_MASK); - - if (r != EFI_SUCCESS) - return 1; - else - return 0; + return do_boot_efi(argv[1], argc > 2 ? argv[2] : NULL); }
#ifdef CONFIG_SYS_LONGHELP @@ -549,7 +618,7 @@ static char bootefi_help_text[] = " Use environment variable efi_selftest to select a single test.\n" " Use 'setenv efi_selftest list' to enumerate all tests.\n" #endif - "bootefi bootmgr [fdt addr]\n" + "bootefi bootmgr [fdt address]\n" " - load and boot EFI payload based on BootOrder/BootXXXX variables.\n" "\n" " If specified, the device tree located at <fdt address> gets\n" @@ -574,6 +643,13 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path) 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; } else { bootefi_device_path = NULL; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c6991d353497..0011a226a3be 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1703,11 +1703,6 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy, &source_size); if (ret != EFI_SUCCESS) goto error; - /* - * split file_path which contains both the device and - * file parts: - */ - efi_dp_split_file_path(file_path, &dp, &fp); } else { /* In this case, file_path is the "device" path, i.e. * something like a HARDWARE_DEVICE:MEMORY_MAPPED @@ -1723,10 +1718,13 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy, dest_buffer = (void *)(uintptr_t)addr; memcpy(dest_buffer, source_buffer, source_size); source_buffer = dest_buffer; - - dp = file_path; - fp = NULL; } + /* + * split file_path which contains both the device and + * file parts: + */ + efi_dp_split_file_path(file_path, &dp, &fp); + ret = efi_setup_loaded_image(dp, fp, image_obj, &info); if (ret != EFI_SUCCESS) goto error_invalid_image;