[PATCH v2 0/2] efi_loader: make the UEFI boot manager configurable

Some boards are very tight on the binary size. Booting via UEFI is possible without using the boot manager.
Provide a configuration option to make the boot manager available.
v2: Some stuff belonging into the first patch were in the second patch Correct copyright notice in lib/efi_loader/efi_load_options.c
Heinrich Schuchardt (2): efi_loader: move load options to new module efi_loader: make the UEFI boot manager configurable
cmd/bootefi.c | 13 ++- cmd/efidebug.c | 8 +- lib/efi_loader/Kconfig | 8 ++ lib/efi_loader/Makefile | 3 +- lib/efi_loader/efi_bootmgr.c | 135 --------------------------- lib/efi_loader/efi_load_options.c | 149 ++++++++++++++++++++++++++++++ 6 files changed, 174 insertions(+), 142 deletions(-) create mode 100644 lib/efi_loader/efi_load_options.c
-- 2.29.2

Move all load options related functions to a new module. So that they can be compiled independently.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2: move stuff from patch 2 to patch 1 correct copyright notice --- lib/efi_loader/Makefile | 1 + lib/efi_loader/efi_bootmgr.c | 135 --------------------------- lib/efi_loader/efi_load_options.c | 149 ++++++++++++++++++++++++++++++ 3 files changed, 150 insertions(+), 135 deletions(-) create mode 100644 lib/efi_loader/efi_load_options.c
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 412fa88245..0216eb83dc 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -35,6 +35,7 @@ endif obj-y += efi_file.o obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o obj-y += efi_image_loader.o +obj-y += efi_load_options.o obj-y += efi_memory.o obj-y += efi_root_node.o obj-y += efi_runtime.o diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index d3be2f94c6..25f5cebfdb 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -30,141 +30,6 @@ static const struct efi_runtime_services *rs; * should do normal or recovery boot. */
-/** - * efi_set_load_options() - set the load options of a loaded image - * - * @handle: the image handle - * @load_options_size: size of load options - * @load_options: pointer to load options - * Return: status code - */ -efi_status_t efi_set_load_options(efi_handle_t handle, - efi_uintn_t load_options_size, - void *load_options) -{ - struct efi_loaded_image *loaded_image_info; - 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 = load_options; - loaded_image_info->load_options_size = load_options_size; - - return EFI_CALL(systab.boottime->close_protocol(handle, - &efi_guid_loaded_image, - efi_root, NULL)); -} - - -/** - * efi_deserialize_load_option() - parse serialized data - * - * Parse serialized data describing a load option and transform it to the - * efi_load_option structure. - * - * @lo: pointer to target - * @data: serialized data - * @size: size of the load option, on return size of the optional data - * Return: status code - */ -efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, - efi_uintn_t *size) -{ - efi_uintn_t len; - - len = sizeof(u32); - if (*size < len + 2 * sizeof(u16)) - return EFI_INVALID_PARAMETER; - lo->attributes = get_unaligned_le32(data); - data += len; - *size -= len; - - len = sizeof(u16); - lo->file_path_length = get_unaligned_le16(data); - data += len; - *size -= len; - - lo->label = (u16 *)data; - len = u16_strnlen(lo->label, *size / sizeof(u16) - 1); - if (lo->label[len]) - return EFI_INVALID_PARAMETER; - len = (len + 1) * sizeof(u16); - if (*size < len) - return EFI_INVALID_PARAMETER; - data += len; - *size -= len; - - len = lo->file_path_length; - if (*size < len) - return EFI_INVALID_PARAMETER; - lo->file_path = (struct efi_device_path *)data; - if (efi_dp_check_length(lo->file_path, len) < 0) - return EFI_INVALID_PARAMETER; - data += len; - *size -= len; - - lo->optional_data = data; - - return EFI_SUCCESS; -} - -/** - * efi_serialize_load_option() - serialize load option - * - * Serialize efi_load_option structure into byte stream for BootXXXX. - * - * @data: buffer for serialized data - * @lo: load option - * Return: size of allocated buffer - */ -unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data) -{ - unsigned long label_len; - unsigned long size; - u8 *p; - - label_len = (u16_strlen(lo->label) + 1) * sizeof(u16); - - /* total size */ - size = sizeof(lo->attributes); - size += sizeof(lo->file_path_length); - size += label_len; - size += lo->file_path_length; - if (lo->optional_data) - size += (utf8_utf16_strlen((const char *)lo->optional_data) - + 1) * sizeof(u16); - p = malloc(size); - if (!p) - return 0; - - /* copy data */ - *data = p; - memcpy(p, &lo->attributes, sizeof(lo->attributes)); - p += sizeof(lo->attributes); - - memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length)); - p += sizeof(lo->file_path_length); - - memcpy(p, lo->label, label_len); - p += label_len; - - memcpy(p, lo->file_path, lo->file_path_length); - p += lo->file_path_length; - - if (lo->optional_data) { - utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data); - p += sizeof(u16); /* size of trailing \0 */ - } - return size; -} - /** * get_var() - get UEFI variable * diff --git a/lib/efi_loader/efi_load_options.c b/lib/efi_loader/efi_load_options.c new file mode 100644 index 0000000000..68cd85ba2e --- /dev/null +++ b/lib/efi_loader/efi_load_options.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * EFI boot manager + * + * Copyright (c) 2018 AKASHI Takahiro, et.al. + */ + +#define LOG_CATEGORY LOGC_EFI + +#include <common.h> +#include <charset.h> +#include <log.h> +#include <malloc.h> +#include <efi_loader.h> +#include <asm/unaligned.h> + +/** + * efi_set_load_options() - set the load options of a loaded image + * + * @handle: the image handle + * @load_options_size: size of load options + * @load_options: pointer to load options + * Return: status code + */ +efi_status_t efi_set_load_options(efi_handle_t handle, + efi_uintn_t load_options_size, + void *load_options) +{ + struct efi_loaded_image *loaded_image_info; + 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 = load_options; + loaded_image_info->load_options_size = load_options_size; + + return EFI_CALL(systab.boottime->close_protocol(handle, + &efi_guid_loaded_image, + efi_root, NULL)); +} + +/** + * efi_deserialize_load_option() - parse serialized data + * + * Parse serialized data describing a load option and transform it to the + * efi_load_option structure. + * + * @lo: pointer to target + * @data: serialized data + * @size: size of the load option, on return size of the optional data + * Return: status code + */ +efi_status_t efi_deserialize_load_option(struct efi_load_option *lo, u8 *data, + efi_uintn_t *size) +{ + efi_uintn_t len; + + len = sizeof(u32); + if (*size < len + 2 * sizeof(u16)) + return EFI_INVALID_PARAMETER; + lo->attributes = get_unaligned_le32(data); + data += len; + *size -= len; + + len = sizeof(u16); + lo->file_path_length = get_unaligned_le16(data); + data += len; + *size -= len; + + lo->label = (u16 *)data; + len = u16_strnlen(lo->label, *size / sizeof(u16) - 1); + if (lo->label[len]) + return EFI_INVALID_PARAMETER; + len = (len + 1) * sizeof(u16); + if (*size < len) + return EFI_INVALID_PARAMETER; + data += len; + *size -= len; + + len = lo->file_path_length; + if (*size < len) + return EFI_INVALID_PARAMETER; + lo->file_path = (struct efi_device_path *)data; + if (efi_dp_check_length(lo->file_path, len) < 0) + return EFI_INVALID_PARAMETER; + data += len; + *size -= len; + + lo->optional_data = data; + + return EFI_SUCCESS; +} + +/** + * efi_serialize_load_option() - serialize load option + * + * Serialize efi_load_option structure into byte stream for BootXXXX. + * + * @data: buffer for serialized data + * @lo: load option + * Return: size of allocated buffer + */ +unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data) +{ + unsigned long label_len; + unsigned long size; + u8 *p; + + label_len = (u16_strlen(lo->label) + 1) * sizeof(u16); + + /* total size */ + size = sizeof(lo->attributes); + size += sizeof(lo->file_path_length); + size += label_len; + size += lo->file_path_length; + if (lo->optional_data) + size += (utf8_utf16_strlen((const char *)lo->optional_data) + + 1) * sizeof(u16); + p = malloc(size); + if (!p) + return 0; + + /* copy data */ + *data = p; + memcpy(p, &lo->attributes, sizeof(lo->attributes)); + p += sizeof(lo->attributes); + + memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length)); + p += sizeof(lo->file_path_length); + + memcpy(p, lo->label, label_len); + p += label_len; + + memcpy(p, lo->file_path, lo->file_path_length); + p += lo->file_path_length; + + if (lo->optional_data) { + utf8_utf16_strcpy((u16 **)&p, (const char *)lo->optional_data); + p += sizeof(u16); /* size of trailing \0 */ + } + return size; +} -- 2.29.2

Some boards are very tight on the binary size. Booting via UEFI is possible without using the boot manager.
Provide a configuration option to make the boot manager available.
Signed-off-by: Heinrich Schuchardt xypron.glpk@gmx.de --- v2: move stuff from patch 2 to patch 1 --- cmd/bootefi.c | 13 +++++++++---- cmd/efidebug.c | 8 ++++++-- lib/efi_loader/Kconfig | 8 ++++++++ lib/efi_loader/Makefile | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-)
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index fe70eec625..c8eb5c32b0 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -631,10 +631,12 @@ static int do_bootefi(struct cmd_tbl *cmdtp, int flag, int argc, else if (ret != EFI_SUCCESS) return CMD_RET_FAILURE;
- if (!strcmp(argv[1], "bootmgr")) - return do_efibootmgr(); + if (IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) { + if (!strcmp(argv[1], "bootmgr")) + return do_efibootmgr(); + } #ifdef CONFIG_CMD_BOOTEFI_SELFTEST - else if (!strcmp(argv[1], "selftest")) + if (!strcmp(argv[1], "selftest")) return do_efi_selftest(); #endif
@@ -657,11 +659,14 @@ 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 +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR "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" - " exposed as EFI configuration table.\n"; + " exposed as EFI configuration table.\n" +#endif + ; #endif
U_BOOT_CMD( diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 6de81cab00..9a2d4ddd5e 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -1367,8 +1367,8 @@ static int do_efi_boot_opt(struct cmd_tbl *cmdtp, int flag, * * efidebug test bootmgr */ -static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, - int argc, char * const argv[]) +static __maybe_unused int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, + int argc, char * const argv[]) { efi_handle_t image; efi_uintn_t exit_data_size = 0; @@ -1392,8 +1392,10 @@ static int do_efi_test_bootmgr(struct cmd_tbl *cmdtp, int flag, }
static struct cmd_tbl cmd_efidebug_test_sub[] = { +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR U_BOOT_CMD_MKENT(bootmgr, CONFIG_SYS_MAXARGS, 1, do_efi_test_bootmgr, "", ""), +#endif };
/** @@ -1581,8 +1583,10 @@ static char efidebug_help_text[] = " - show UEFI memory map\n" "efidebug tables\n" " - show UEFI configuration tables\n" +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR "efidebug test bootmgr\n" " - run simple bootmgr for test\n" +#endif "efidebug query [-nv][-bs][-rt][-at]\n" " - show size of UEFI variables store\n"; #endif diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index fdf245dea3..106f789b4d 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -27,6 +27,14 @@ config EFI_LOADER
if EFI_LOADER
+config CMD_BOOTEFI_BOOTMGR + bool "UEFI Boot Manager" + default y + help + Select this option if you want to select the UEFI binary to be booted + via UEFI variables Boot####, BootOrder, and BootNext. This enables the + 'bootefi bootmgr' command. + config EFI_SETUP_EARLY bool default n diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 0216eb83dc..a6355d240a 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -21,7 +21,7 @@ targets += helloworld.o endif
obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o -obj-y += efi_bootmgr.o +obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o obj-y += efi_boottime.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o -- 2.29.2

Hi,
Am 2021-01-19 18:09, schrieb Heinrich Schuchardt:
Some boards are very tight on the binary size. Booting via UEFI is possible without using the boot manager.
Provide a configuration option to make the boot manager available.
include/config_distro_bootcmd.h needs to be updated too, no? "bootefi bootmgr" is called unconditionally there.
-michael

Am 19. Januar 2021 23:51:46 MEZ schrieb Michael Walle michael@walle.cc:
Hi,
Am 2021-01-19 18:09, schrieb Heinrich Schuchardt:
Some boards are very tight on the binary size. Booting via UEFI is possible without using the boot manager.
Provide a configuration option to make the boot manager available.
include/config_distro_bootcmd.h needs to be updated too, no? "bootefi bootmgr" is called unconditionally there.
Yes, we can avoid unnecessary output by not calling the unimplemented command.
-michael
participants (2)
-
Heinrich Schuchardt
-
Michael Walle