From dec88e41e022ac06c0054ca48807db0d95f917f6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 20 Apr 2019 07:39:11 +0200 Subject: efi_loader: consistent naming of protocol GUIDs We should consistently use the same name for protocol GUIDs as defined in the UEFI specification. Not adhering to this rule has led to duplicate definitions for the EFI_LOADED_IMAGE_PROTOCOL_GUID. Adjust misnamed protocol GUIDs. Adjust the text for the graphics output protocol in the output of the `efidebug dh` command. Signed-off-by: Heinrich Schuchardt --- cmd/efidebug.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'cmd') diff --git a/cmd/efidebug.c b/cmd/efidebug.c index db96682c5a..4bf91ed248 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -185,7 +185,7 @@ static const struct { } guid_list[] = { { "Device Path", - DEVICE_PATH_GUID, + EFI_DEVICE_PATH_PROTOCOL_GUID, }, { "Device Path To Text", @@ -217,7 +217,7 @@ static const struct { }, { "Block IO", - BLOCK_IO_GUID, + EFI_BLOCK_IO_PROTOCOL_GUID, }, { "Simple File System", @@ -225,11 +225,11 @@ static const struct { }, { "Loaded Image", - LOADED_IMAGE_PROTOCOL_GUID, + EFI_LOADED_IMAGE_PROTOCOL_GUID, }, { - "GOP", - EFI_GOP_GUID, + "Graphics Output", + EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, }, }; -- cgit v1.2.3 From 391bc8a9388dd0d36a24932954e17b32bc1a8598 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 20 Apr 2019 07:57:28 +0200 Subject: efi_loader: more short texts for protocols in efidebug The `efidebug dh` command shows handles and the installed protocols. For most of the protocols implemented by U-Boot a short text was shown. But for some only the GUID was displayed. Provide the missing short texts for the following protocols: HII String, HII Database, HII Config Routing, Simple Network, PXE Base Code. Signed-off-by: Heinrich Schuchardt --- cmd/efidebug.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'cmd') diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 4bf91ed248..a40c4f4be2 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -231,6 +231,26 @@ static const struct { "Graphics Output", EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID, }, + { + "HII String", + EFI_HII_STRING_PROTOCOL_GUID, + }, + { + "HII Database", + EFI_HII_DATABASE_PROTOCOL_GUID, + }, + { + "HII Config Routing", + EFI_HII_CONFIG_ROUTING_PROTOCOL_GUID, + }, + { + "Simple Network", + EFI_SIMPLE_NETWORK_PROTOCOL_GUID, + }, + { + "PXE Base Code", + EFI_PXE_BASE_CODE_PROTOCOL_GUID, + }, }; /** -- cgit v1.2.3 From defa7b8edd1f41ec255d16d6d95b29db44d2a7d8 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:28 +0900 Subject: cmd: bootefi: rework set_load_options() set_load_options() can fail, so it should return error code to stop invoking an image. In addition, set_load_options() now takes a handle, instead of loaded_image_info, to utilize efi_load_image() in a later patch. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 15ee4af456..d8ca4ed703 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -39,29 +39,49 @@ void __weak allow_unaligned(void) /* * Set the load options of an image from an environment variable. * - * @loaded_image_info: the image - * @env_var: name of the environment variable + * @handle: the image handle + * @env_var: name of the environment variable + * Return: status code */ -static void set_load_options(struct efi_loaded_image *loaded_image_info, - const char *env_var) +static efi_status_t set_load_options(efi_handle_t handle, const char *env_var) { + struct efi_loaded_image *loaded_image_info; size_t size; const char *env = env_get(env_var); u16 *pos; + efi_status_t ret; + + ret = EFI_CALL(systab.boottime->open_protocol( + handle, + &efi_guid_loaded_image, + (void **)&loaded_image_info, + efi_root, NULL, + EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)); + if (ret != EFI_SUCCESS) + return EFI_INVALID_PARAMETER; loaded_image_info->load_options = NULL; loaded_image_info->load_options_size = 0; if (!env) - return; + goto out; + size = utf8_utf16_strlen(env) + 1; loaded_image_info->load_options = calloc(size, sizeof(u16)); if (!loaded_image_info->load_options) { printf("ERROR: Out of memory\n"); - return; + EFI_CALL(systab.boottime->close_protocol(handle, + &efi_guid_loaded_image, + efi_root, NULL)); + return EFI_OUT_OF_RESOURCES; } pos = loaded_image_info->load_options; utf8_utf16_strcpy(&pos, env); loaded_image_info->load_options_size = size * 2; + +out: + return EFI_CALL(systab.boottime->close_protocol(handle, + &efi_guid_loaded_image, + efi_root, NULL)); } /** @@ -212,9 +232,7 @@ static efi_status_t bootefi_run_prepare(const char *load_options_path, return ret; /* Transfer environment variable as load options */ - set_load_options(*loaded_image_infop, load_options_path); - - return 0; + return set_load_options((efi_handle_t)*image_objp, load_options_path); } /** -- cgit v1.2.3 From e878e6a7da54e33da4c265ae8e4456ea2a9b2ee1 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:29 +0900 Subject: cmd: bootefi: carve out fdt handling from do_bootefi() This is a preparatory patch for reworking do_bootefi() in later patch. Carve out a function to handle the installation of the device tree as a configuration table in system table. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 54 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 16 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index d8ca4ed703..fb6703ce84 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -218,6 +218,38 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) return ret; } +/** + * efi_process_fdt() - process fdt passed by a command argument + * @fdt_opt: pointer to argument + * Return: status code + * + * If specified, fdt will be installed as configuration table, + * otherwise no fdt will be passed. + */ +static efi_status_t efi_process_fdt(const char *fdt_opt) +{ + unsigned long fdt_addr; + efi_status_t ret; + + if (fdt_opt) { + fdt_addr = simple_strtoul(fdt_opt, NULL, 16); + if (!fdt_addr && *fdt_opt != '0') + return EFI_INVALID_PARAMETER; + + /* Install device tree */ + ret = efi_install_fdt(fdt_addr); + if (ret != EFI_SUCCESS) { + printf("ERROR: failed to install device tree\n"); + return ret; + } + } else { + /* Remove device tree. EFI_NOT_FOUND can be ignored here */ + efi_install_configuration_table(&efi_guid_fdt, NULL); + } + + return EFI_SUCCESS; +} + static efi_status_t bootefi_run_prepare(const char *load_options_path, struct efi_device_path *device_path, struct efi_device_path *image_path, @@ -407,7 +439,6 @@ 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; /* Allow unaligned memory access */ allow_unaligned(); @@ -425,21 +456,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (argc < 2) return CMD_RET_USAGE; - if (argc > 2) { - fdt_addr = simple_strtoul(argv[2], NULL, 16); - if (!fdt_addr && *argv[2] != '0') - return CMD_RET_USAGE; - /* Install device tree */ - r = efi_install_fdt(fdt_addr); - if (r != EFI_SUCCESS) { - printf("ERROR: failed to install device tree\n"); - return CMD_RET_FAILURE; - } - } else { - /* Remove device tree. EFI_NOT_FOUND can be ignored here */ - efi_install_configuration_table(&efi_guid_fdt, NULL); - printf("WARNING: booting without device tree\n"); - } + r = efi_process_fdt(argc > 2 ? argv[2] : NULL); + if (r == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (r != EFI_SUCCESS) + return CMD_RET_FAILURE; + #ifdef CONFIG_CMD_BOOTEFI_HELLO if (!strcmp(argv[1], "hello")) { ulong size = __efi_helloworld_end - __efi_helloworld_begin; -- cgit v1.2.3 From 3ffc52fd23cb50ea27db7eabf81d95348798db90 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:30 +0900 Subject: cmd: bootefi: merge efi_install_fdt() and efi_process_fdt() This is a preparatory patch for reworking do_bootefi() in later patch. For simplicity, merge two functions. Signed-off-by: AKASHI Takahiro Return error code of efi_install_configuration_table() when aborting from efi_install_fdt(). Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 65 +++++++++++++++++++++++++---------------------------------- 1 file changed, 27 insertions(+), 38 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index fb6703ce84..c97c8aaa25 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -185,59 +185,48 @@ static void efi_carve_out_dt_rsv(void *fdt) } } -static efi_status_t efi_install_fdt(ulong fdt_addr) -{ - bootm_headers_t img = { 0 }; - efi_status_t ret; - void *fdt; - - fdt = map_sysmem(fdt_addr, 0); - if (fdt_check_header(fdt)) { - printf("ERROR: invalid device tree\n"); - return EFI_INVALID_PARAMETER; - } - - /* Create memory reservation as indicated by the device tree */ - efi_carve_out_dt_rsv(fdt); - - /* Prepare fdt for payload */ - ret = copy_fdt(&fdt); - if (ret) - return ret; - - if (image_setup_libfdt(&img, fdt, 0, NULL)) { - printf("ERROR: failed to process device tree\n"); - return EFI_LOAD_ERROR; - } - - /* Link to it in the efi tables */ - ret = efi_install_configuration_table(&efi_guid_fdt, fdt); - if (ret != EFI_SUCCESS) - return EFI_OUT_OF_RESOURCES; - - return ret; -} - /** - * efi_process_fdt() - process fdt passed by a command argument + * efi_install_fdt() - install fdt passed by a command argument * @fdt_opt: pointer to argument * Return: status code * * If specified, fdt will be installed as configuration table, * otherwise no fdt will be passed. */ -static efi_status_t efi_process_fdt(const char *fdt_opt) +static efi_status_t efi_install_fdt(const char *fdt_opt) { unsigned long fdt_addr; + void *fdt; + bootm_headers_t img = { 0 }; efi_status_t ret; if (fdt_opt) { + /* Install device tree */ fdt_addr = simple_strtoul(fdt_opt, NULL, 16); if (!fdt_addr && *fdt_opt != '0') return EFI_INVALID_PARAMETER; - /* Install device tree */ - ret = efi_install_fdt(fdt_addr); + fdt = map_sysmem(fdt_addr, 0); + if (fdt_check_header(fdt)) { + printf("ERROR: invalid device tree\n"); + return EFI_INVALID_PARAMETER; + } + + /* Create memory reservation as indicated by the device tree */ + efi_carve_out_dt_rsv(fdt); + + /* Prepare fdt for payload */ + ret = copy_fdt(&fdt); + if (ret) + return ret; + + if (image_setup_libfdt(&img, fdt, 0, NULL)) { + printf("ERROR: failed to process device tree\n"); + return EFI_LOAD_ERROR; + } + + /* Link to it in the efi tables */ + ret = efi_install_configuration_table(&efi_guid_fdt, fdt); if (ret != EFI_SUCCESS) { printf("ERROR: failed to install device tree\n"); return ret; @@ -456,7 +445,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (argc < 2) return CMD_RET_USAGE; - r = efi_process_fdt(argc > 2 ? argv[2] : NULL); + r = efi_install_fdt(argc > 2 ? argv[2] : NULL); if (r == EFI_INVALID_PARAMETER) return CMD_RET_USAGE; else if (r != EFI_SUCCESS) -- cgit v1.2.3 From 3fc2b16335721520c0c6e3f57235efa98f0519f0 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:31 +0900 Subject: cmd: bootefi: carve out efi_selftest code from do_bootefi() This is a preparatory patch for reworking do_bootefi() in later patch. Efi_selftest code is unusual in terms of execution path in do_bootefi(), which make that function complicated and hard to understand. With this patch, all efi_selftest related code will be put in a separate function. The change also includes expanding efi_run_prepare() and efi_run_finish() in do_bootefi_exec(). Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 145 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 53 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index c97c8aaa25..c73175e0ed 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -239,37 +239,6 @@ static efi_status_t efi_install_fdt(const char *fdt_opt) return EFI_SUCCESS; } -static efi_status_t bootefi_run_prepare(const char *load_options_path, - struct efi_device_path *device_path, - struct efi_device_path *image_path, - struct efi_loaded_image_obj **image_objp, - struct efi_loaded_image **loaded_image_infop) -{ - efi_status_t ret; - - ret = efi_setup_loaded_image(device_path, image_path, image_objp, - loaded_image_infop); - if (ret != EFI_SUCCESS) - return ret; - - /* Transfer environment variable as load options */ - return set_load_options((efi_handle_t)*image_objp, load_options_path); -} - -/** - * bootefi_run_finish() - finish up after running an EFI test - * - * @loaded_image_info: Pointer to a struct which holds the loaded image info - * @image_objj: Pointer to a struct which holds the loaded image object - */ -static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj, - struct efi_loaded_image *loaded_image_info) -{ - efi_restore_gd(); - free(loaded_image_info->load_options); - efi_delete_handle(&image_obj->header); -} - /** * do_bootefi_exec() - execute EFI binary * @@ -316,11 +285,16 @@ static efi_status_t do_bootefi_exec(void *efi, assert(device_path && image_path); } - ret = bootefi_run_prepare("bootargs", device_path, image_path, - &image_obj, &loaded_image_info); + ret = efi_setup_loaded_image(device_path, image_path, &image_obj, + &loaded_image_info); if (ret) goto err_prepare; + /* Transfer environment variable as load options */ + ret = set_load_options((efi_handle_t)image_obj, "bootargs"); + if (ret != EFI_SUCCESS) + goto err_prepare; + /* Load the EFI payload */ ret = efi_load_pe(image_obj, efi, loaded_image_info); if (ret != EFI_SUCCESS) @@ -344,7 +318,9 @@ static efi_status_t do_bootefi_exec(void *efi, err_prepare: /* image has returned, loaded-image obj goes *poof*: */ - bootefi_run_finish(image_obj, loaded_image_info); + efi_restore_gd(); + free(loaded_image_info->load_options); + efi_delete_handle(&image_obj->header); err_add_protocol: if (mem_handle) @@ -354,6 +330,23 @@ err_add_protocol: } #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, + struct efi_loaded_image_obj **image_objp, + struct efi_loaded_image **loaded_image_infop) +{ + efi_status_t ret; + + ret = efi_setup_loaded_image(device_path, image_path, image_objp, + loaded_image_infop); + if (ret != EFI_SUCCESS) + return ret; + + /* Transfer environment variable as load options */ + return set_load_options((efi_handle_t)*image_objp, load_options_path); +} + /** * bootefi_test_prepare() - prepare to run an EFI test * @@ -399,6 +392,64 @@ failure: return ret; } +/** + * bootefi_run_finish() - finish up after running an EFI test + * + * @loaded_image_info: Pointer to a struct which holds the loaded image info + * @image_obj: Pointer to a struct which holds the loaded image object + */ +static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj, + struct efi_loaded_image *loaded_image_info) +{ + efi_restore_gd(); + free(loaded_image_info->load_options); + efi_delete_handle(&image_obj->header); +} + +/** + * do_efi_selftest() - execute EFI Selftest + * + * @fdt_opt: string of fdt start address + * Return: status code + * + * Execute EFI Selftest + */ +static int do_efi_selftest(const char *fdt_opt) +{ + struct efi_loaded_image_obj *image_obj; + struct efi_loaded_image *loaded_image_info; + efi_status_t ret; + + /* Allow unaligned memory access */ + allow_unaligned(); + + switch_to_non_secure_mode(); + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt_opt); + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + ret = bootefi_test_prepare(&image_obj, &loaded_image_info, + "\\selftest", "efi_selftest"); + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + + /* Execute the test */ + ret = EFI_CALL(efi_selftest(&image_obj->header, &systab)); + bootefi_run_finish(image_obj, loaded_image_info); + + return ret != EFI_SUCCESS; +} #endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ static int do_bootefi_bootmgr_exec(void) @@ -429,6 +480,13 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) char *saddr; efi_status_t r; + if (argc < 2) + return CMD_RET_USAGE; +#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(); @@ -442,9 +500,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_FAILURE; } - if (argc < 2) - return CMD_RET_USAGE; - r = efi_install_fdt(argc > 2 ? argv[2] : NULL); if (r == EFI_INVALID_PARAMETER) return CMD_RET_USAGE; @@ -462,22 +517,6 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) addr = CONFIG_SYS_LOAD_ADDR; memcpy(map_sysmem(addr, size), __efi_helloworld_begin, size); } else -#endif -#ifdef CONFIG_CMD_BOOTEFI_SELFTEST - if (!strcmp(argv[1], "selftest")) { - struct efi_loaded_image_obj *image_obj; - struct efi_loaded_image *loaded_image_info; - - r = bootefi_test_prepare(&image_obj, &loaded_image_info, - "\\selftest", "efi_selftest"); - if (r != EFI_SUCCESS) - return CMD_RET_FAILURE; - - /* Execute the test */ - r = EFI_CALL(efi_selftest(&image_obj->header, &systab)); - bootefi_run_finish(image_obj, loaded_image_info); - return r != EFI_SUCCESS; - } else #endif if (!strcmp(argv[1], "bootmgr")) { return do_bootefi_bootmgr_exec(); -- cgit v1.2.3 From cc999d58e305d9dd8987fd154d592e93c8cfe3ee Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:32 +0900 Subject: cmd: bootefi: move do_bootefi_bootmgr_exec() forward This is a preparatory patch for reworking do_bootefi() in later patch. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index c73175e0ed..985ad48fde 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -329,6 +329,27 @@ err_add_protocol: return ret; } +static int do_bootefi_bootmgr_exec(void) +{ + struct efi_device_path *device_path, *file_path; + void *addr; + efi_status_t r; + + addr = efi_bootmgr_load(&device_path, &file_path); + if (!addr) + return 1; + + 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); + + if (r != EFI_SUCCESS) + return 1; + + return 0; +} + #ifdef CONFIG_CMD_BOOTEFI_SELFTEST static efi_status_t bootefi_run_prepare(const char *load_options_path, struct efi_device_path *device_path, @@ -452,27 +473,6 @@ static int do_efi_selftest(const char *fdt_opt) } #endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ -static int do_bootefi_bootmgr_exec(void) -{ - struct efi_device_path *device_path, *file_path; - void *addr; - efi_status_t r; - - addr = efi_bootmgr_load(&device_path, &file_path); - if (!addr) - return 1; - - 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); - - if (r != EFI_SUCCESS) - return 1; - - return 0; -} - /* 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[]) { -- cgit v1.2.3 From d6b21894d49e63e2d377648c530a903e05c9bcb9 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:33 +0900 Subject: cmd: bootefi: carve out bootmgr code from do_bootefi() This is a preparatory patch for reworking do_bootefi() in later patch. do_bootmgr_exec() is renamed to do_efibootmgr() as we put all the necessary code into this function. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 44 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 8 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 985ad48fde..703c27a94d 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -329,22 +329,49 @@ err_add_protocol: 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) { struct efi_device_path *device_path, *file_path; void *addr; - efi_status_t r; + efi_status_t ret; + + /* Allow unaligned memory access */ + allow_unaligned(); + + switch_to_non_secure_mode(); + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt_opt); + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; addr = efi_bootmgr_load(&device_path, &file_path); if (!addr) return 1; printf("## Starting EFI application at %p ...\n", addr); - r = do_bootefi_exec(addr, device_path, file_path); + ret = do_bootefi_exec(addr, device_path, file_path); printf("## Application terminated, r = %lu\n", - r & ~EFI_ERROR_MASK); + ret & ~EFI_ERROR_MASK); - if (r != EFI_SUCCESS) + if (ret != EFI_SUCCESS) return 1; return 0; @@ -482,6 +509,9 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 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); @@ -518,9 +548,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 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); -- cgit v1.2.3 From e2e4098e1b92fb0b86505e0011298ab5da983545 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:34 +0900 Subject: cmd: bootefi: carve out do_bootefi_image() from do_bootefi() This is a preparatory patch for reworking do_bootefi() in later patch. All the non-boot-manager-based (that is, bootefi ) code is put into one function, do_bootefi_image(). Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/bootefi.c | 122 ++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 67 insertions(+), 55 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 703c27a94d..d62e9969ac 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -377,6 +377,72 @@ static int do_efibootmgr(const char *fdt_opt) return 0; } +/* + * do_bootefi_image() - 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_bootefi_image(const char *image_opt, const char *fdt_opt) +{ + unsigned long addr; + efi_status_t ret; + + /* Allow unaligned memory access */ + allow_unaligned(); + + switch_to_non_secure_mode(); + + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(fdt_opt); + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + +#ifdef CONFIG_CMD_BOOTEFI_HELLO + if (!strcmp(image_opt, "hello")) { + char *saddr; + 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 + { + addr = simple_strtoul(image_opt, NULL, 16); + /* Check that a numeric value was passed */ + if (!addr && *image_opt != '0') + return CMD_RET_USAGE; + } + + printf("## Starting EFI application at %08lx ...\n", addr); + ret = do_bootefi_exec(map_sysmem(addr, 0), bootefi_device_path, + bootefi_image_path); + printf("## Application terminated, r = %lu\n", + ret & ~EFI_ERROR_MASK); + + if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + else + return CMD_RET_SUCCESS; +} + #ifdef CONFIG_CMD_BOOTEFI_SELFTEST static efi_status_t bootefi_run_prepare(const char *load_options_path, struct efi_device_path *device_path, @@ -503,10 +569,6 @@ 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; - if (argc < 2) return CMD_RET_USAGE; @@ -517,57 +579,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 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; - } - - r = efi_install_fdt(argc > 2 ? argv[2] : NULL); - if (r == EFI_INVALID_PARAMETER) - return CMD_RET_USAGE; - else if (r != EFI_SUCCESS) - return CMD_RET_FAILURE; - -#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 - { - 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_bootefi_image(argv[1], argc > 2 ? argv[2] : NULL); } #ifdef CONFIG_SYS_LONGHELP -- cgit v1.2.3 From 6b95b38c41a6a56d48b51b192dac7365ce0a8024 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Fri, 19 Apr 2019 12:22:35 +0900 Subject: efi_loader: rework bootmgr/bootefi using load_image API In the current implementation, bootefi command and EFI boot manager don't use load_image API, instead, use more primitive and internal functions. This will introduce duplicated code and potentially unknown bugs as well as inconsistent behaviours. With this patch, do_efibootmgr() and do_boot_efi() are completely overhauled and re-implemented using load_image API. Signed-off-by: AKASHI Takahiro Use efi_root as parent handle for the loaded image. LoadImage() should be called with BootPolicy = true by the boot manager. Avoid duplicate free_pool(). Eliminate variable memdp which is not needed after anymore due to "efi_loader: correctly split device path of loaded image". Reviewed-by: Heinrich Schuchardt Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 180 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 94 insertions(+), 86 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index d62e9969ac..be55751830 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -242,89 +242,36 @@ static efi_status_t efi_install_fdt(const char *fdt_opt) /** * do_bootefi_exec() - execute EFI binary * - * @efi: address of the binary - * @device_path: path of the device from which the binary was loaded - * @image_path: device path of the binary + * @handle: handle of loaded image * 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(void *efi, - struct efi_device_path *device_path, - struct efi_device_path *image_path) +static efi_status_t do_bootefi_exec(efi_handle_t handle) { - efi_handle_t mem_handle = NULL; - struct efi_device_path *memdp = NULL; efi_status_t ret; - struct efi_loaded_image_obj *image_obj = NULL; - struct efi_loaded_image *loaded_image_info = NULL; - - /* - * Special case for efi payload not loaded from disk, such as - * 'bootefi hello' or for example payload loaded directly into - * memory via JTAG, etc: - */ - 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() */ - memdp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, 0, 0); - device_path = image_path = memdp; - /* - * Grub expects that the device path of the loaded image is - * installed on a handle. - */ - ret = efi_create_handle(&mem_handle); - if (ret != EFI_SUCCESS) - return ret; /* TODO: leaks device_path */ - ret = efi_add_protocol(mem_handle, &efi_guid_device_path, - device_path); - if (ret != EFI_SUCCESS) - goto err_add_protocol; - } else { - assert(device_path && image_path); - } - - ret = efi_setup_loaded_image(device_path, image_path, &image_obj, - &loaded_image_info); - if (ret) - goto err_prepare; /* Transfer environment variable as load options */ - ret = set_load_options((efi_handle_t)image_obj, "bootargs"); - if (ret != EFI_SUCCESS) - goto err_prepare; - - /* Load the EFI payload */ - ret = efi_load_pe(image_obj, efi, loaded_image_info); + ret = set_load_options(handle, "bootargs"); if (ret != EFI_SUCCESS) - goto err_prepare; - - if (memdp) { - struct efi_device_path_memory *mdp = (void *)memdp; - mdp->memory_type = loaded_image_info->image_code_type; - mdp->start_address = (uintptr_t)loaded_image_info->image_base; - mdp->end_address = mdp->start_address + - loaded_image_info->image_size; - } + return ret; /* we don't support much: */ env_set("efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_OsIndicationsSupported", "{ro,boot}(blob)0000000000000000"); /* Call our payload! */ - 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); -err_add_protocol: - if (mem_handle) - efi_delete_handle(mem_handle); + /* + * FIXME: Who is responsible for + * free(loaded_image_info->load_options); + * Once efi_exit() is implemented correctly, + * handle itself doesn't exist here. + */ return ret; } @@ -339,8 +286,7 @@ err_add_protocol: */ static int do_efibootmgr(const char *fdt_opt) { - struct efi_device_path *device_path, *file_path; - void *addr; + efi_handle_t handle; efi_status_t ret; /* Allow unaligned memory access */ @@ -362,19 +308,19 @@ static int do_efibootmgr(const char *fdt_opt) else if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; - addr = efi_bootmgr_load(&device_path, &file_path); - if (!addr) - return 1; + ret = efi_bootmgr_load(&handle); + if (ret != EFI_SUCCESS) { + printf("EFI boot manager: Cannot load any image\n"); + return CMD_RET_FAILURE; + } - printf("## Starting EFI application at %p ...\n", addr); - ret = do_bootefi_exec(addr, device_path, file_path); - printf("## Application terminated, r = %lu\n", - ret & ~EFI_ERROR_MASK); + ret = do_bootefi_exec(handle); + printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); if (ret != EFI_SUCCESS) - return 1; + return CMD_RET_FAILURE; - return 0; + return CMD_RET_SUCCESS; } /* @@ -389,7 +335,12 @@ static int do_efibootmgr(const char *fdt_opt) */ static int do_bootefi_image(const char *image_opt, const char *fdt_opt) { - unsigned long addr; + void *image_buf; + struct efi_device_path *device_path, *image_path; + struct efi_device_path *file_path = NULL; + unsigned long addr, size; + const char *size_str; + efi_handle_t mem_handle = NULL, handle; efi_status_t ret; /* Allow unaligned memory access */ @@ -414,33 +365,83 @@ static int do_bootefi_image(const char *image_opt, const char *fdt_opt) #ifdef CONFIG_CMD_BOOTEFI_HELLO if (!strcmp(image_opt, "hello")) { char *saddr; - ulong size = __efi_helloworld_end - __efi_helloworld_begin; 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; - memcpy(map_sysmem(addr, size), __efi_helloworld_begin, size); + + image_buf = map_sysmem(addr, size); + memcpy(image_buf, __efi_helloworld_begin, size); + + device_path = NULL; + image_path = NULL; } else #endif { + size_str = env_get("filesize"); + if (size_str) + size = simple_strtoul(size_str, NULL, 16); + else + size = 0; + addr = simple_strtoul(image_opt, NULL, 16); /* Check that a numeric value was passed */ if (!addr && *image_opt != '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); - ret = do_bootefi_exec(map_sysmem(addr, 0), bootefi_device_path, - bootefi_image_path); - printf("## Application terminated, r = %lu\n", - ret & ~EFI_ERROR_MASK); + if (!device_path && !image_path) { + /* + * Special case for efi payload not loaded from disk, + * such as 'bootefi hello' or for example payload + * loaded directly into memory via JTAG, etc: + */ + file_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, + (uintptr_t)image_buf, size); + /* + * 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) + goto out; + + ret = efi_add_protocol(mem_handle, &efi_guid_device_path, + file_path); + if (ret != EFI_SUCCESS) + goto out; + } else { + assert(device_path && image_path); + file_path = efi_dp_append(device_path, image_path); + } + + ret = EFI_CALL(efi_load_image(false, efi_root, + file_path, image_buf, size, &handle)); + if (ret != EFI_SUCCESS) + goto out; + + ret = do_bootefi_exec(handle); + printf("## Application terminated, r = %lu\n", ret & ~EFI_ERROR_MASK); + +out: + if (mem_handle) + efi_delete_handle(mem_handle); + if (file_path) + efi_free_pool(file_path); if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; - else - return CMD_RET_SUCCESS; + + return CMD_RET_SUCCESS; } #ifdef CONFIG_CMD_BOOTEFI_SELFTEST @@ -598,7 +599,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 gets\n" @@ -623,6 +624,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; -- cgit v1.2.3 From 6182495e101f2d3da29e632632c3d6e5035fef8b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 20 Apr 2019 13:33:55 +0200 Subject: efi_loader: need either ACPI table or device tree The EBBR specification prescribes that we should have either an ACPI table or a device tree but not both. Let us enforce this condition in the `bootefi` command. If the bootefi command is called without a device tree parameter use a previously device tree or fall back to the internal device tree. The fdt unit test should not be run on boards with an ACPI table. Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 98 +++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 26 deletions(-) (limited to 'cmd') diff --git a/cmd/bootefi.c b/cmd/bootefi.c index be55751830..efaa548be4 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -84,6 +84,8 @@ out: efi_root, NULL)); } +#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) + /** * copy_fdt() - Copy the device tree to a new location available to EFI * @@ -185,6 +187,25 @@ static void efi_carve_out_dt_rsv(void *fdt) } } +/** + * 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 fdt passed by a command argument * @fdt_opt: pointer to argument @@ -195,46 +216,71 @@ static void efi_carve_out_dt_rsv(void *fdt) */ static efi_status_t efi_install_fdt(const char *fdt_opt) { + /* + * The EBBR spec requires that we have either an FDT or an ACPI table + * but not both. + */ +#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) + if (fdt_opt) { + printf("ERROR: can't have ACPI table and device tree.\n"); + return EFI_LOAD_ERROR; + } +#else unsigned long fdt_addr; void *fdt; bootm_headers_t img = { 0 }; efi_status_t ret; if (fdt_opt) { - /* Install device tree */ fdt_addr = simple_strtoul(fdt_opt, NULL, 16); - if (!fdt_addr && *fdt_opt != '0') - return EFI_INVALID_PARAMETER; - - fdt = map_sysmem(fdt_addr, 0); - if (fdt_check_header(fdt)) { - printf("ERROR: invalid device tree\n"); + if (!fdt_addr) return EFI_INVALID_PARAMETER; + } else { + /* Look for device tree that is already installed */ + if (get_config_table(&efi_guid_fdt)) + return EFI_SUCCESS; + /* Use our own device tree as default */ + fdt_opt = env_get("fdtcontroladdr"); + if (!fdt_opt) { + printf("ERROR: need device tree\n"); + return EFI_NOT_FOUND; } + fdt_addr = simple_strtoul(fdt_opt, NULL, 16); + if (!fdt_addr) { + printf("ERROR: invalid $fdtcontroladdr\n"); + return EFI_LOAD_ERROR; + } + } - /* Create memory reservation as indicated by the device tree */ - efi_carve_out_dt_rsv(fdt); + /* Install device tree */ + fdt = map_sysmem(fdt_addr, 0); + if (fdt_check_header(fdt)) { + printf("ERROR: invalid device tree\n"); + return EFI_LOAD_ERROR; + } - /* Prepare fdt for payload */ - ret = copy_fdt(&fdt); - if (ret) - return ret; + /* Create memory reservations as indicated by the device tree */ + efi_carve_out_dt_rsv(fdt); - if (image_setup_libfdt(&img, fdt, 0, NULL)) { - printf("ERROR: failed to process device tree\n"); - return EFI_LOAD_ERROR; - } + /* Prepare device tree for payload */ + ret = copy_fdt(&fdt); + if (ret) { + printf("ERROR: out of memory\n"); + return EFI_OUT_OF_RESOURCES; + } - /* Link to it in the efi tables */ - ret = efi_install_configuration_table(&efi_guid_fdt, fdt); - if (ret != EFI_SUCCESS) { - printf("ERROR: failed to install device tree\n"); - return ret; - } - } else { - /* Remove device tree. EFI_NOT_FOUND can be ignored here */ - efi_install_configuration_table(&efi_guid_fdt, NULL); + if (image_setup_libfdt(&img, fdt, 0, NULL)) { + printf("ERROR: failed to process device tree\n"); + return EFI_LOAD_ERROR; + } + + /* Install device tree as UEFI table */ + ret = efi_install_configuration_table(&efi_guid_fdt, fdt); + if (ret != EFI_SUCCESS) { + printf("ERROR: failed to install device tree\n"); + return ret; } +#endif /* GENERATE_ACPI_TABLE */ return EFI_SUCCESS; } -- cgit v1.2.3