[PATCH v2 00/18] efi: Move towards the EFI app booting EFI applications

From: Simon Glass <sjg@chromium.org> This series adds various new features to the EFI app, mostly by moving code over from the EFI loader implementation. In particular it adds support for the efidebug command (with only a subset of subcommands so far). The main approach is to make use of the system table (for both the app and the loader) instead of directly calling EFI-loader code. It also includes a few fixes, which likely have no effect but will help to avoid confusion in future. Changes in v2: - Mention the 'dh' subcommand - Mention that 'order' allows the boot order to be changed - Mention the eficonfig command and the underlying UEFI firmware Simon Glass (18): efi: Add missing break statements in dp_size() efi: Add missing break to dp_fill() efi: Update path_uefi() to avoid allowed_unaligned() efi: app: Support the efidebug command efi: app: Support efidebug memmap efi: app: Support efidebug show tables efi: app: Provide easy access to runtime services efi: Move a few helper functions into the common efi/ dir efi: Move some load-options handling into the common dir efi: Move FDT and global-variable GUIDs to common files efi: app: Implement efidebug boot dump efi: app: Find the device-path-to-text protocol on startup efi: app: Implement %pD in the app efi: Move efi_string utilities to the common directory efi: app: Use the same efi_free_pool() signature as loader efi: Move efi_load_option_dp_join() to a common file efi: app: Support efidebug boot add, rm and order efi: doc: Add documentation for efidebug command in the app cmd/Kconfig | 5 +- cmd/efidebug.c | 43 +++++++-- doc/develop/uefi/u-boot_on_efi.rst | 24 +++++ include/efi.h | 20 +++++ include/efi_loader.h | 11 --- lib/efi/Kconfig | 12 ++- lib/efi/Makefile | 3 + lib/efi/device_path.c | 20 +++-- lib/efi/helper.c | 88 +++++++++++++++++++ .../efi_load_options.c => efi/load_options.c} | 0 lib/{efi_loader/efi_string.c => efi/string.c} | 0 lib/efi_client/efi.c | 24 ++++- lib/efi_client/efi_app.c | 9 ++ lib/efi_client/efi_vars.c | 23 +++-- lib/efi_loader/Kconfig | 7 -- lib/efi_loader/Makefile | 2 - lib/efi_loader/efi_boottime.c | 7 +- lib/efi_loader/efi_helper.c | 77 ---------------- 18 files changed, 252 insertions(+), 123 deletions(-) create mode 100644 lib/efi/helper.c rename lib/{efi_loader/efi_load_options.c => efi/load_options.c} (100%) rename lib/{efi_loader/efi_string.c => efi/string.c} (100%) -- 2.43.0 base-commit: 5659b7adcb906a50d740ca68d3fc458172b9682c branch: loadq2

From: Simon Glass <sjg@chromium.org> The conversion to using a size variable was missing a break statement for the BLK case. Fix it. Signed-off-by: Simon Glass <sjg@chromium.org> Fixes: ffde1a39228 ("efi: Use variables in dp_size()") --- (no changes since v1) lib/efi/device_path.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index 4c2c0bb614f..d1fdd0fba81 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -328,7 +328,7 @@ bool efi_dp_is_multi_instance(const struct efi_device_path *dp) __maybe_unused static unsigned int dp_size(struct udevice *dev) { - uint parent_size, size; + uint parent_size, size = 0; if (!dev || !dev->driver) return sizeof(struct efi_device_path_udevice); @@ -374,6 +374,7 @@ __maybe_unused static unsigned int dp_size(struct udevice *dev) size = sizeof(struct efi_device_path_udevice); break; } + break; case UCLASS_MMC: if (IS_ENABLED(CONFIG_MMC)) size = sizeof(struct efi_device_path_sd_mmc_path); -- 2.43.0

From: Simon Glass <sjg@chromium.org> While this doesn't really affect anything in practice, it is better to deal with an incorrect use of this function (calling it with a UCLASS which is not enabled). Add a break after the UCLASS_BLK case, to help this. Signed-off-by: Simon Glass <sjg@chromium.org> Fixes: a48a8929de2 ("efi: Move most of efi_device_path into lib/efi") --- (no changes since v1) lib/efi/device_path.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index d1fdd0fba81..0926b51e987 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -529,6 +529,7 @@ __maybe_unused static void *dp_fill(void *buf, struct udevice *dev) return &dp[1]; } + break; } case UCLASS_MMC: if (IS_ENABLED(CONFIG_MMC)) { -- 2.43.0

From: Simon Glass <sjg@chromium.org> This call seems to have been added in an unrelated commit, likely to fix a bug: 046fe7b5074 ("efi_loader: efi_dp_from_file() expect UTF-8 path") With standard boot we don't need to call efi_set_bootdev(). Also this function is not available in the EFI app. So for now, add a condition, to avoid a build error in the x86 app when CONFIG_EFI_BINARY_EXEC is enabled. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) lib/efi/device_path.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index 0926b51e987..fb6653b23a3 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -741,12 +741,14 @@ static void path_to_uefi(void *uefi, const char *src) { u16 *pos = uefi; - /* - * efi_set_bootdev() calls this routine indirectly before the UEFI - * subsystem is initialized. So we cannot assume unaligned access to be - * enabled. - */ - allow_unaligned(); + if (!IS_ENABLED(CONFIG_EFI_APP)) { + /* + * efi_set_bootdev() calls this routine indirectly before the + * UEFI subsystem is initialized. So we cannot assume unaligned + * access to be enabled. + */ + allow_unaligned(); + } while (*src) { s32 code = utf8_get(&src); -- 2.43.0

From: Simon Glass <sjg@chromium.org> This command is useful for the app, so enable it. For now most of the subcommands don't work, so provide a message in that case. This seems better than silently pretending that the subcommand doesn't exist. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) cmd/Kconfig | 5 +++-- cmd/efidebug.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index b7b80cbe59f..fe9fb11ff95 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2228,8 +2228,9 @@ config CMD_CLS config CMD_EFIDEBUG bool "efidebug - display/configure UEFI environment" - depends on EFI_LOADER - select EFI_DEVICE_PATH_TO_TEXT + depends on EFI_LOADER || EFI_APP + default y if EFI_APP + select EFI_DEVICE_PATH_TO_TEXT if EFI_LOADER help Enable the 'efidebug' command which provides a subset of UEFI shell utility with simplified functionality. It will be useful diff --git a/cmd/efidebug.c b/cmd/efidebug.c index f52ba8de279..2e156fef525 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -28,6 +28,16 @@ #define BS systab.boottime +static bool app_not_supported(const char *cmd) +{ + if (!IS_ENABLED(CONFIG_EFI_APP)) + return false; + + printf("Command '%s' is not yet supported in the app\n", cmd); + + return true; +} + #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT /** * do_efi_capsule_update() - process a capsule update @@ -405,6 +415,9 @@ static int do_efi_show_drivers(struct cmd_tbl *cmdtp, int flag, u16 *driver_name, *image_path_text; efi_status_t ret; + if (app_not_supported("show_drivers")) + return CMD_RET_FAILURE; + ret = EFI_CALL(efi_locate_handle_buffer( BY_PROTOCOL, &efi_guid_driver_binding_protocol, NULL, &num, &handles)); @@ -458,6 +471,9 @@ static int do_efi_show_handles(struct cmd_tbl *cmdtp, int flag, efi_uintn_t num, count, i, j; efi_status_t ret; + if (app_not_supported("show_handles")) + return CMD_RET_FAILURE; + ret = EFI_CALL(efi_locate_handle_buffer(ALL_HANDLES, NULL, NULL, &num, &handles)); if (ret != EFI_SUCCESS) @@ -646,6 +662,9 @@ static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag, int i; efi_status_t ret; + if (app_not_supported("memmap")) + return CMD_RET_FAILURE; + ret = efi_get_memory_map_alloc(&map_size, &memmap); if (ret != EFI_SUCCESS) return CMD_RET_FAILURE; @@ -698,6 +717,9 @@ static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag, static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { + if (app_not_supported("show tables")) + return CMD_RET_FAILURE; + efi_show_tables(&systab); return CMD_RET_SUCCESS; @@ -893,6 +915,9 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag, efi_status_t ret; int r = CMD_RET_SUCCESS; + if (app_not_supported("boot add")) + return CMD_RET_FAILURE; + guid = efi_global_variable_guid; /* attributes */ @@ -1073,6 +1098,9 @@ static int do_efi_boot_rm(struct cmd_tbl *cmdtp, int flag, u16 var_name16[9]; efi_status_t ret; + if (app_not_supported("boot rm")) + return CMD_RET_FAILURE; + if (argc == 1) return CMD_RET_USAGE; @@ -1199,6 +1227,9 @@ static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag, efi_guid_t guid; efi_status_t ret; + if (app_not_supported("boot dump")) + return CMD_RET_FAILURE; + if (argc > 1) return CMD_RET_USAGE; @@ -1255,6 +1286,9 @@ static int show_efi_boot_order(void) struct efi_load_option lo; efi_status_t ret; + if (app_not_supported("show_boot_order")) + return CMD_RET_FAILURE; + size = 0; ret = efi_get_variable_int(u"BootOrder", &efi_global_variable_guid, NULL, &size, NULL, NULL); @@ -1574,6 +1608,9 @@ static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag, u64 max_variable_size; int i; + if (app_not_supported("query")) + return CMD_RET_FAILURE; + for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-bs")) attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; -- 2.43.0

From: Simon Glass <sjg@chromium.org> It is helpful to see the memory map in some cases, so enable this subcommand in the app. Unfortunately we cannot assume that desc_size is the same in the underlying EFI implementation, so use a variable for that. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) cmd/efidebug.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 2e156fef525..d93fa43b779 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -659,15 +659,24 @@ static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag, struct efi_mem_desc *memmap, *map; efi_uintn_t map_size; const char *type; - int i; - efi_status_t ret; + int desc_size, i; + efi_status_t eret; + int ret; - if (app_not_supported("memmap")) - return CMD_RET_FAILURE; + if (IS_ENABLED(CONFIG_EFI_APP)) { + uint key, version; + int size; - ret = efi_get_memory_map_alloc(&map_size, &memmap); - if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; + ret = efi_get_mmap(&memmap, &size, &key, &desc_size, &version); + if (ret) + return CMD_RET_FAILURE; + map_size = size; + } else { + eret = efi_get_memory_map_alloc(&map_size, &memmap); + if (eret) + return CMD_RET_FAILURE; + desc_size = sizeof(*map); + } printf("Type Start%.*s End%.*s Attributes\n", EFI_PHYS_ADDR_WIDTH - 5, spc, EFI_PHYS_ADDR_WIDTH - 3, spc); @@ -678,7 +687,8 @@ static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag, * This is a false positive as memmap will always be * populated by allocate_pool() above. */ - for (i = 0, map = memmap; i < map_size / sizeof(*map); map++, i++) { + for (i = 0, map = memmap; i < map_size / desc_size; + map = (void *)map + desc_size, i++) { if (map->type < ARRAY_SIZE(efi_mem_type_string)) type = efi_mem_type_string[map->type]; else -- 2.43.0

From: Simon Glass <sjg@chromium.org> It is useful to be able to see the available tables in the app, so enable this subcommand. Provide an implementation of efi_get_sys_table() that works for the EFI loader. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) cmd/efidebug.c | 5 +---- lib/efi_loader/efi_boottime.c | 5 +++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index d93fa43b779..2f1fecf494a 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -727,10 +727,7 @@ static int do_efi_show_memmap(struct cmd_tbl *cmdtp, int flag, static int do_efi_show_tables(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - if (app_not_supported("show tables")) - return CMD_RET_FAILURE; - - efi_show_tables(&systab); + efi_show_tables(efi_get_sys_table()); return CMD_RET_SUCCESS; } diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index cc711a5c52f..8ba42ec4544 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -4026,3 +4026,8 @@ efi_status_t efi_initialize_system_table(void) return ret; } + +struct efi_system_table *efi_get_sys_table(void) +{ + return &systab; +} -- 2.43.0

From: Simon Glass <sjg@chromium.org> Add a function which allows the app to obtain the runtime services without first obtaining the priv data. Make use of this in efi_vars.c Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) include/efi.h | 7 +++++++ lib/efi_client/efi.c | 5 +++++ lib/efi_client/efi_vars.c | 9 +++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/efi.h b/include/efi.h index 9ff945ae1c3..742c40bfd8c 100644 --- a/include/efi.h +++ b/include/efi.h @@ -604,6 +604,13 @@ struct efi_system_table *efi_get_sys_table(void); */ struct efi_boot_services *efi_get_boot(void); +/** + * efi_get_run() - Get access to the EFI runtime-services table + * + * Returns: pointer to EFI runtime-services table + */ +struct efi_runtime_services *efi_get_run(void); + /** * efi_get_parent_image() - Get the handle of the parent image * diff --git a/lib/efi_client/efi.c b/lib/efi_client/efi.c index c5573dd67f9..e2cc9d3eae3 100644 --- a/lib/efi_client/efi.c +++ b/lib/efi_client/efi.c @@ -65,6 +65,11 @@ struct efi_boot_services *efi_get_boot(void) return global_priv->boot; } +struct efi_runtime_services *efi_get_run(void) +{ + return global_priv->run; +} + efi_handle_t efi_get_parent_image(void) { return global_priv->parent_image; diff --git a/lib/efi_client/efi_vars.c b/lib/efi_client/efi_vars.c index 099a59b2a1e..e652ee3f243 100644 --- a/lib/efi_client/efi_vars.c +++ b/lib/efi_client/efi_vars.c @@ -18,8 +18,7 @@ efi_status_t efi_get_variable_int(const u16 *variable_name, const efi_guid_t *ve u32 *attributes, efi_uintn_t *data_size, void *data, u64 *timep) { - struct efi_priv *priv = efi_get_priv(); - struct efi_runtime_services *run = priv->run; + struct efi_runtime_services *run = efi_get_run(); return run->get_variable((u16 *)variable_name, vendor, attributes, data_size, data); } @@ -28,8 +27,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name, const efi_guid_t *ve u32 attributes, efi_uintn_t data_size, const void *data, bool ro_check) { - struct efi_priv *priv = efi_get_priv(); - struct efi_runtime_services *run = priv->run; + struct efi_runtime_services *run = efi_get_run(); return run->set_variable((u16 *)variable_name, vendor, attributes, data_size, data); } @@ -37,8 +35,7 @@ efi_status_t efi_set_variable_int(const u16 *variable_name, const efi_guid_t *ve efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *vendor) { - struct efi_priv *priv = efi_get_priv(); - struct efi_runtime_services *run = priv->run; + struct efi_runtime_services *run = efi_get_run(); return run->get_next_variable_name(variable_name_size, variable_name, vendor); } -- 2.43.0

From: Simon Glass <sjg@chromium.org> Checking if a variable is a load option is useful for the app, so move efi_varname_is_load_option() and u16_tohex() into a new helper.c file. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) lib/efi/Makefile | 1 + lib/efi/helper.c | 42 +++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_helper.c | 33 ----------------------------- 3 files changed, 43 insertions(+), 33 deletions(-) create mode 100644 lib/efi/helper.c diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 213c9910b39..a31caf1fce9 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -5,5 +5,6 @@ obj-y += basename.o obj-y += device_path.o +obj-y += helper.o obj-y += memory.o obj-y += run.o diff --git a/lib/efi/helper.c b/lib/efi/helper.c new file mode 100644 index 00000000000..34cf3f49f95 --- /dev/null +++ b/lib/efi/helper.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020, Linaro Limited + */ + +#define LOG_CATEGORY LOGC_EFI + +#include <string.h> +#include <linux/types.h> + +static int u16_tohex(u16 c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + /* not hexadecimal */ + return -1; +} + +bool efi_varname_is_load_option(u16 *var_name16, int *index) +{ + int id, i, digit; + + if (memcmp(var_name16, u"Boot", 8)) + return false; + + for (id = 0, i = 0; i < 4; i++) { + digit = u16_tohex(var_name16[4 + i]); + if (digit < 0) + break; + id = (id << 4) + digit; + } + if (i == 4 && !var_name16[8]) { + if (index) + *index = id; + return true; + } + + return false; +} diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 82e0fd7b069..56ea7d1c7d9 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -241,39 +241,6 @@ int efi_unlink_dev(efi_handle_t handle) return 0; } -static int u16_tohex(u16 c) -{ - if (c >= '0' && c <= '9') - return c - '0'; - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - /* not hexadecimal */ - return -1; -} - -bool efi_varname_is_load_option(u16 *var_name16, int *index) -{ - int id, i, digit; - - if (memcmp(var_name16, u"Boot", 8)) - return false; - - for (id = 0, i = 0; i < 4; i++) { - digit = u16_tohex(var_name16[4 + i]); - if (digit < 0) - break; - id = (id << 4) + digit; - } - if (i == 4 && !var_name16[8]) { - if (index) - *index = id; - return true; - } - - return false; -} - /** * efi_next_variable_name() - get next variable name * -- 2.43.0

From: Simon Glass <sjg@chromium.org> These functions are useful for the app as well as the loader. For now, efi_set_load_options() calls efi_search_protocol() which is still in the loader, but we can provide an 'app' version when needed. It doesn't seem worth keeping that one function in a separate file. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) lib/efi/Makefile | 1 + lib/{efi_loader/efi_load_options.c => efi/load_options.c} | 0 lib/efi_loader/Makefile | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename lib/{efi_loader/efi_load_options.c => efi/load_options.c} (100%) diff --git a/lib/efi/Makefile b/lib/efi/Makefile index a31caf1fce9..9b65cbc0dc2 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -6,5 +6,6 @@ obj-y += basename.o obj-y += device_path.o obj-y += helper.o +obj-y += load_options.o obj-y += memory.o obj-y += run.o diff --git a/lib/efi_loader/efi_load_options.c b/lib/efi/load_options.c similarity index 100% rename from lib/efi_loader/efi_load_options.c rename to lib/efi/load_options.c diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 3158fc6da68..2b232940bc3 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -38,7 +38,6 @@ obj-y += efi_fdt.o obj-y += efi_file.o obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o obj-y += efi_image_loader.o -obj-y += efi_load_options.o obj-$(CONFIG_EFI_LOG) += efi_log.o obj-y += efi_memory.o obj-y += efi_root_node.o -- 2.43.0

From: Simon Glass <sjg@chromium.org> The global-variable GUID is already set in the common device_path.c file but its declaration is only in the efi_loader header. Move it and also move over the FDT GUIDs. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) include/efi.h | 3 +++ include/efi_loader.h | 3 --- lib/efi/device_path.c | 2 ++ lib/efi_loader/efi_boottime.c | 2 -- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/efi.h b/include/efi.h index 742c40bfd8c..ed22ff9a5a4 100644 --- a/include/efi.h +++ b/include/efi.h @@ -152,6 +152,9 @@ typedef struct efi_object *efi_handle_t; (c) & 0xff, ((c) >> 8) & 0xff, \ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } } +extern const efi_guid_t efi_global_variable_guid; +extern const efi_guid_t efi_guid_fdt; + /* Generic EFI table header */ struct efi_table_hdr { u64 signature; diff --git a/include/efi_loader.h b/include/efi_loader.h index b57196da8da..c4d9c4f1c7c 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -317,7 +317,6 @@ extern const efi_guid_t efi_guid_host_dev; extern const efi_guid_t efi_block_io_guid; /* GUID of the EFI_SIMPLE_NETWORK_PROTOCOL */ extern const efi_guid_t efi_net_guid; -extern const efi_guid_t efi_global_variable_guid; extern const efi_guid_t efi_guid_console_control; extern const efi_guid_t efi_guid_device_path; /* GUID of the EFI system partition */ @@ -336,8 +335,6 @@ extern const efi_guid_t efi_guid_event_group_ready_to_boot; extern const efi_guid_t efi_guid_event_group_reset_system; /* event group return to efibootmgr */ extern const efi_guid_t efi_guid_event_group_return_to_efibootmgr; -/* GUID of the device tree table */ -extern const efi_guid_t efi_guid_fdt; extern const efi_guid_t efi_guid_loaded_image; extern const efi_guid_t efi_guid_loaded_image_device_path; extern const efi_guid_t efi_guid_device_path_to_text_protocol; diff --git a/lib/efi/device_path.c b/lib/efi/device_path.c index fb6653b23a3..db5a686ccb2 100644 --- a/lib/efi/device_path.c +++ b/lib/efi/device_path.c @@ -32,6 +32,8 @@ const efi_guid_t efi_simple_file_system_protocol_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; const efi_guid_t efi_u_boot_guid = U_BOOT_GUID; +/* GUID of the device tree table */ +const efi_guid_t efi_guid_fdt = EFI_FDT_GUID; /* template EFI_DP_END node: */ const struct efi_device_path EFI_DP_END = { diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 8ba42ec4544..0f9a654ca03 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -68,8 +68,6 @@ efi_status_t efi_uninstall_protocol /* 1 if inside U-Boot code, 0 if inside EFI payload code */ static int entry_count = 1; static int nesting_level; -/* GUID of the device tree table */ -const efi_guid_t efi_guid_fdt = EFI_FDT_GUID; /* GUID of the EFI_DRIVER_BINDING_PROTOCOL */ const efi_guid_t efi_guid_driver_binding_protocol = EFI_DRIVER_BINDING_PROTOCOL_GUID; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Seeing the boot order is useful in the app. Everything we need is present except an implementation of efi_query_variable_info_int(), so add that and enable 'efidebug boot dump'. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) cmd/efidebug.c | 6 ------ lib/efi_client/efi_vars.c | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 2f1fecf494a..a48e0de1208 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1234,9 +1234,6 @@ static int do_efi_boot_dump(struct cmd_tbl *cmdtp, int flag, efi_guid_t guid; efi_status_t ret; - if (app_not_supported("boot dump")) - return CMD_RET_FAILURE; - if (argc > 1) return CMD_RET_USAGE; @@ -1615,9 +1612,6 @@ static int do_efi_query_info(struct cmd_tbl *cmdtp, int flag, u64 max_variable_size; int i; - if (app_not_supported("query")) - return CMD_RET_FAILURE; - for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-bs")) attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; diff --git a/lib/efi_client/efi_vars.c b/lib/efi_client/efi_vars.c index e652ee3f243..4fc48b90d6c 100644 --- a/lib/efi_client/efi_vars.c +++ b/lib/efi_client/efi_vars.c @@ -39,3 +39,17 @@ efi_status_t efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, return run->get_next_variable_name(variable_name_size, variable_name, vendor); } + +efi_status_t efi_query_variable_info_int(u32 attributes, + u64 *maximum_variable_storage_size, + u64 *remaining_variable_storage_size, + u64 *maximum_variable_size) +{ + struct efi_runtime_services *run = efi_get_run(); + + return run->query_variable_info(attributes, + maximum_variable_storage_size, + remaining_variable_storage_size, + maximum_variable_size); +} + -- 2.43.0

From: Simon Glass <sjg@chromium.org> Some protocols are generally useful for the app and it makes sense to store these in the priv struct rather than requesting them each time they are needed. Add a new function which locates the device-path-to-text protocol and stores it. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) include/efi.h | 2 ++ lib/efi_client/efi_app.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/include/efi.h b/include/efi.h index ed22ff9a5a4..28c297d87db 100644 --- a/include/efi.h +++ b/include/efi.h @@ -471,6 +471,7 @@ static inline struct efi_mem_desc *efi_get_next_mem_desc( * allocate_pages() and free_pages() * @ram_base: Base address of RAM (size CONFIG_EFI_RAM_SIZE) * @image_data_type: Type of the loaded image (e.g. EFI_LOADER_CODE) + * @efi_dp_to_text: Pointer to the EFI_DEVICE_PATH protocol, or NULL if none * * @info: Header of the info list, holding info collected by the stub and passed * to U-Boot @@ -496,6 +497,7 @@ struct efi_priv { bool use_pool_for_malloc; unsigned long ram_base; unsigned int image_data_type; + struct efi_device_path_to_text_protocol *efi_dp_to_text; /* stub: */ struct efi_info_hdr *info; diff --git a/lib/efi_client/efi_app.c b/lib/efi_client/efi_app.c index df51c5a4de9..7c9c156e006 100644 --- a/lib/efi_client/efi_app.c +++ b/lib/efi_client/efi_app.c @@ -176,6 +176,14 @@ static void scan_tables(struct efi_system_table *sys_table) } } +static void find_protocols(struct efi_priv *priv) +{ + efi_guid_t guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + struct efi_boot_services *boot = priv->boot; + + boot->locate_protocol(&guid, NULL, (void **)&priv->efi_dp_to_text); +} + /** * efi_main() - Start an EFI image * @@ -211,6 +219,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image, } scan_tables(priv->sys_table); + find_protocols(priv); /* * We could store the EFI memory map here, but it changes all the time, -- 2.43.0

From: Simon Glass <sjg@chromium.org> This printf() extension is useful for the app. Add an implementation of efi_dp_str() so that it works as expected. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) lib/efi/Kconfig | 12 +++++++++++- lib/efi_client/efi.c | 15 +++++++++++++++ lib/efi_loader/Kconfig | 7 ------- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/efi/Kconfig b/lib/efi/Kconfig index 16de786b1e2..ed12741f61a 100644 --- a/lib/efi/Kconfig +++ b/lib/efi/Kconfig @@ -11,12 +11,22 @@ config EFI This is used to provide libraries shared by both. +if EFI_LOADER + config EFI_BINARY_EXEC bool "Execute UEFI binary" default y - depends on EFI_LOADER help Select this option if you want to execute the UEFI binary after loading it with U-Boot load commands or other methods. You may enable CMD_BOOTEFI_BINARY so that you can use bootefi command to do that. + +config EFI_DEVICE_PATH_TO_TEXT + bool "Device path to text protocol" + default y + help + The device path to text protocol converts device nodes and paths to + human readable strings. + +endif # EFI_LOADER diff --git a/lib/efi_client/efi.c b/lib/efi_client/efi.c index e2cc9d3eae3..739010e60e3 100644 --- a/lib/efi_client/efi.c +++ b/lib/efi_client/efi.c @@ -196,3 +196,18 @@ void efi_free_pool(void *ptr) efi_free(priv, ptr); } + +/* helper for debug prints.. efi_free_pool() the result. */ +uint16_t *efi_dp_str(struct efi_device_path *dp) +{ + struct efi_priv *priv = efi_get_priv(); + u16 *val; + + if (!priv->efi_dp_to_text) + return NULL; + + val = priv->efi_dp_to_text->convert_device_path_to_text(dp, true, + true); + + return val; +} diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 6f67e4897f3..c2bb9375df4 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -356,13 +356,6 @@ endmenu menu "UEFI protocol support" -config EFI_DEVICE_PATH_TO_TEXT - bool "Device path to text protocol" - default y - help - The device path to text protocol converts device nodes and paths to - human readable strings. - config EFI_DEVICE_PATH_UTIL bool "Device path utilities protocol" default y -- 2.43.0

From: Simon Glass <sjg@chromium.org> This file contains some useful utility functions which are not specific to the EFI loader. Move them to lib/efi so they can be used by the app. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) lib/efi/Makefile | 1 + lib/{efi_loader/efi_string.c => efi/string.c} | 0 lib/efi_loader/Makefile | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename lib/{efi_loader/efi_string.c => efi/string.c} (100%) diff --git a/lib/efi/Makefile b/lib/efi/Makefile index 9b65cbc0dc2..842067dcab3 100644 --- a/lib/efi/Makefile +++ b/lib/efi/Makefile @@ -9,3 +9,4 @@ obj-y += helper.o obj-y += load_options.o obj-y += memory.o obj-y += run.o +obj-y += string.o diff --git a/lib/efi_loader/efi_string.c b/lib/efi/string.c similarity index 100% rename from lib/efi_loader/efi_string.c rename to lib/efi/string.c diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 2b232940bc3..180b83d2fc5 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -43,7 +43,6 @@ obj-y += efi_memory.o obj-y += efi_root_node.o obj-y += efi_runtime.o obj-y += efi_setup.o -obj-y += efi_string.o obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL2) += efi_unicode_collation.o obj-y += efi_var_common.o obj-y += efi_var_mem.o -- 2.43.0

From: Simon Glass <sjg@chromium.org> The app has a function of this name, but it does not return any value. Return success (always) so that we can use the same signature. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) include/efi.h | 8 ++++++++ include/efi_loader.h | 8 -------- lib/efi_client/efi.c | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/include/efi.h b/include/efi.h index 28c297d87db..54da1540d0b 100644 --- a/include/efi.h +++ b/include/efi.h @@ -662,6 +662,14 @@ void *efi_malloc(struct efi_priv *priv, int size, efi_status_t *retp); */ void efi_free(struct efi_priv *priv, void *ptr); +/** + * efi_free_pool() - free memory from pool + * + * @buffer: start of memory to be freed + * Return: status code + */ +efi_status_t efi_free_pool(void *buffer); + /** * efi_puts() - Write out a string to the EFI console * diff --git a/include/efi_loader.h b/include/efi_loader.h index c4d9c4f1c7c..2d5e8de0132 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -891,14 +891,6 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages); efi_status_t efi_allocate_pool(enum efi_memory_type pool_type, efi_uintn_t size, void **buffer); -/** - * efi_free_pool() - free memory from pool - * - * @buffer: start of memory to be freed - * Return: status code - */ -efi_status_t efi_free_pool(void *buffer); - /* Allocate and retrieve EFI memory map */ efi_status_t efi_get_memory_map_alloc(efi_uintn_t *map_size, struct efi_mem_desc **memory_map); diff --git a/lib/efi_client/efi.c b/lib/efi_client/efi.c index 739010e60e3..12a646a36b7 100644 --- a/lib/efi_client/efi.c +++ b/lib/efi_client/efi.c @@ -190,11 +190,13 @@ void *efi_alloc(size_t size) return efi_malloc(priv, size, &ret); } -void efi_free_pool(void *ptr) +efi_status_t efi_free_pool(void *ptr) { struct efi_priv *priv = efi_get_priv(); efi_free(priv, ptr); + + return 0; } /* helper for debug prints.. efi_free_pool() the result. */ -- 2.43.0

From: Simon Glass <sjg@chromium.org> This function is useful in the app so move it to the common helper. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) lib/efi/helper.c | 46 +++++++++++++++++++++++++++++++++++++ lib/efi_loader/efi_helper.c | 44 ----------------------------------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/lib/efi/helper.c b/lib/efi/helper.c index 34cf3f49f95..85a2a270f20 100644 --- a/lib/efi/helper.c +++ b/lib/efi/helper.c @@ -5,6 +5,8 @@ #define LOG_CATEGORY LOGC_EFI +#include <efi.h> +#include <efi_device_path.h> #include <string.h> #include <linux/types.h> @@ -40,3 +42,47 @@ bool efi_varname_is_load_option(u16 *var_name16, int *index) return false; } + +/** + * efi_load_option_dp_join() - join device-paths for load option + * + * @dp: in: binary device-path, out: joined device-path + * @dp_size: size of joined device-path + * @initrd_dp: initrd device-path or NULL + * @fdt_dp: device-tree device-path or NULL + * Return: status_code + */ +efi_status_t efi_load_option_dp_join(struct efi_device_path **dp, + size_t *dp_size, + struct efi_device_path *initrd_dp, + struct efi_device_path *fdt_dp) +{ + if (!dp) + return EFI_INVALID_PARAMETER; + + *dp_size = efi_dp_size(*dp); + + if (initrd_dp) { + struct efi_device_path *tmp_dp = *dp; + + *dp = efi_dp_concat(tmp_dp, initrd_dp, *dp_size); + efi_free_pool(tmp_dp); + if (!*dp) + return EFI_OUT_OF_RESOURCES; + *dp_size += efi_dp_size(initrd_dp) + sizeof(EFI_DP_END); + } + + if (fdt_dp) { + struct efi_device_path *tmp_dp = *dp; + + *dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size); + efi_free_pool(tmp_dp); + if (!*dp) + return EFI_OUT_OF_RESOURCES; + *dp_size += efi_dp_size(fdt_dp) + sizeof(EFI_DP_END); + } + + *dp_size += sizeof(EFI_DP_END); + + return EFI_SUCCESS; +} diff --git a/lib/efi_loader/efi_helper.c b/lib/efi_loader/efi_helper.c index 56ea7d1c7d9..3030e6f52d4 100644 --- a/lib/efi_loader/efi_helper.c +++ b/lib/efi_loader/efi_helper.c @@ -99,50 +99,6 @@ err: return file_path; } -/** - * efi_load_option_dp_join() - join device-paths for load option - * - * @dp: in: binary device-path, out: joined device-path - * @dp_size: size of joined device-path - * @initrd_dp: initrd device-path or NULL - * @fdt_dp: device-tree device-path or NULL - * Return: status_code - */ -efi_status_t efi_load_option_dp_join(struct efi_device_path **dp, - size_t *dp_size, - struct efi_device_path *initrd_dp, - struct efi_device_path *fdt_dp) -{ - if (!dp) - return EFI_INVALID_PARAMETER; - - *dp_size = efi_dp_size(*dp); - - if (initrd_dp) { - struct efi_device_path *tmp_dp = *dp; - - *dp = efi_dp_concat(tmp_dp, initrd_dp, *dp_size); - efi_free_pool(tmp_dp); - if (!*dp) - return EFI_OUT_OF_RESOURCES; - *dp_size += efi_dp_size(initrd_dp) + sizeof(EFI_DP_END); - } - - if (fdt_dp) { - struct efi_device_path *tmp_dp = *dp; - - *dp = efi_dp_concat(tmp_dp, fdt_dp, *dp_size); - efi_free_pool(tmp_dp); - if (!*dp) - return EFI_OUT_OF_RESOURCES; - *dp_size += efi_dp_size(fdt_dp) + sizeof(EFI_DP_END); - } - - *dp_size += sizeof(EFI_DP_END); - - return EFI_SUCCESS; -} - const struct guid_to_hash_map { efi_guid_t guid; const char algo[32]; -- 2.43.0

From: Simon Glass <sjg@chromium.org> Enable these commands in the app, since the requires pieces are now in place. Signed-off-by: Simon Glass <sjg@chromium.org> --- (no changes since v1) cmd/efidebug.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index a48e0de1208..7755585c778 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -922,9 +922,6 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag, efi_status_t ret; int r = CMD_RET_SUCCESS; - if (app_not_supported("boot add")) - return CMD_RET_FAILURE; - guid = efi_global_variable_guid; /* attributes */ @@ -1105,9 +1102,6 @@ static int do_efi_boot_rm(struct cmd_tbl *cmdtp, int flag, u16 var_name16[9]; efi_status_t ret; - if (app_not_supported("boot rm")) - return CMD_RET_FAILURE; - if (argc == 1) return CMD_RET_USAGE; @@ -1290,9 +1284,6 @@ static int show_efi_boot_order(void) struct efi_load_option lo; efi_status_t ret; - if (app_not_supported("show_boot_order")) - return CMD_RET_FAILURE; - size = 0; ret = efi_get_variable_int(u"BootOrder", &efi_global_variable_guid, NULL, &size, NULL, NULL); -- 2.43.0

From: Simon Glass <sjg@chromium.org> Mention the efidebug command specifically the EFI-app documentaion, to highlight its usefulness. Signed-off-by: Simon Glass <sjg@chromium.org> --- Changes in v2: - Mention the 'dh' subcommand - Mention that 'order' allows the boot order to be changed - Mention the eficonfig command and the underlying UEFI firmware doc/develop/uefi/u-boot_on_efi.rst | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst index d20d5b00ec6..845d04d7826 100644 --- a/doc/develop/uefi/u-boot_on_efi.rst +++ b/doc/develop/uefi/u-boot_on_efi.rst @@ -143,6 +143,30 @@ enough) should be straightforward. Use the 'reset' command to get back to EFI. +EFI Debugging Commands +~~~~~~~~~~~~~~~~~~~~~~ +When running as an EFI application, U-Boot provides access to the 'efidebug' +command, which offers a subset of functionality useful for debugging and +inspecting the UEFI environment. This command allows you to: + +* Display memory maps with 'efidebug memmap' +* Show EFI system tables with 'efidebug show tables' +* Show EFI handles with 'efidebug dh' +* Manage boot options with 'efidebug boot' subcommands: + + - dump - Display current boot options + - add - Add new boot options + - rm - Remove boot options + - order - Display and modify the boot order + +This command uses the EFI system table and runtime services to provide this +functionality, so it can help with understanding and debugging UEFI +environments. See the :doc:`/usage/cmd/efidebug` for more information. + +See also the :doc:`/usage/cmd/eficonfig` for controlling the boot order. The +underlying UEFI firmware typically provides an easier way to manage boot +options. + EFI Payload ~~~~~~~~~~~ The payload approach is a different kettle of fish. It works by building -- 2.43.0
participants (1)
-
Simon Glass