From 2363effb7a689de66634ba325e57c2d6fc12f4e9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 15 Jan 2021 19:02:49 +0100 Subject: [PATCH 01/12] efi_loader: move load options to new module Move all load options related functions to a new module. So that they can be compiled independently. Signed-off-by: Heinrich Schuchardt --- 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 +#include +#include +#include +#include +#include + +/** + * 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; +} From ff2f532fadd8f5238cc1ac2ae4ab075703bcc313 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 15 Jan 2021 19:02:50 +0100 Subject: [PATCH 02/12] 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. Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 13 +++++++++---- cmd/efidebug.c | 8 ++++++-- include/config_distro_bootcmd.h | 12 +++++++++--- lib/efi_loader/Kconfig | 8 ++++++++ lib/efi_loader/Makefile | 2 +- 5 files changed, 33 insertions(+), 10 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 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/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h index c9862260a3..2627c2a6a5 100644 --- a/include/config_distro_bootcmd.h +++ b/include/config_distro_bootcmd.h @@ -123,14 +123,20 @@ #endif #endif - -#define BOOTENV_SHARED_EFI \ +#ifdef CONFIG_CMD_BOOTEFI_BOOTMGR +#define BOOTENV_EFI_BOOTMGR \ "boot_efi_bootmgr=" \ "if fdt addr ${fdt_addr_r}; then " \ "bootefi bootmgr ${fdt_addr_r};" \ "else " \ "bootefi bootmgr;" \ - "fi\0" \ + "fi\0" +#else +#define BOOTENV_EFI_BOOTMGR +#endif + +#define BOOTENV_SHARED_EFI \ + BOOTENV_EFI_BOOTMGR \ \ "boot_efi_binary=" \ "load ${devtype} ${devnum}:${distro_bootpart} " \ 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 From 535c473e10b32036ea0f2900bc6986f30e76c696 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 16 Jan 2021 08:50:10 +0100 Subject: [PATCH 03/12] efi_loader: fixup protocol, avoid forward declaration Avoid a forward declaration. Add a missing function description. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_dt_fixup.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index 5f0ae5c338..c2f2daef33 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -10,16 +10,6 @@ #include #include -static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this, - void *dtb, - efi_uintn_t *buffer_size, - u32 flags); - -struct efi_dt_fixup_protocol efi_dt_fixup_prot = { - .revision = EFI_DT_FIXUP_PROTOCOL_REVISION, - .fixup = efi_dt_fixup -}; - const efi_guid_t efi_guid_dt_fixup_protocol = EFI_DT_FIXUP_PROTOCOL_GUID; /** @@ -102,6 +92,18 @@ void efi_carve_out_dt_rsv(void *fdt) } } +/** + * efi_dt_fixup() - fix up device tree + * + * This function implements the Fixup() service of the + * EFI Device Tree Fixup Protocol. + * + * @this: instance of the protocol + * @dtb: device tree provided by caller + * @buffer_size: size of buffer for the device tree including free space + * @flags: bit field designating action to be performed + * Return: status code + */ static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this, void *dtb, efi_uintn_t *buffer_size, @@ -158,3 +160,8 @@ static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this, out: return EFI_EXIT(ret); } + +struct efi_dt_fixup_protocol efi_dt_fixup_prot = { + .revision = EFI_DT_FIXUP_PROTOCOL_REVISION, + .fixup = efi_dt_fixup +}; From 4cb07d8d93215820dc55a7fe19d617338358f1f7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 16 Jan 2021 09:33:24 +0100 Subject: [PATCH 04/12] efi_loader: make EFI_DT_FIXUP_PROTOCOL configurable Allow EFI_DT_FIXUP_PROTOCOL to be disabled via configuration. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 8 ++++++++ lib/efi_loader/efi_dt_fixup.c | 7 +++---- lib/efi_loader/efi_root_node.c | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 106f789b4d..227cfa5ca4 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -208,6 +208,14 @@ config EFI_DEVICE_PATH_TO_TEXT The device path to text protocol converts device nodes and paths to human readable strings. +config EFI_DT_FIXUP + bool "Device tree fixup protocol" + depends on !GENERATE_ACPI_TABLE + default y + help + The EFI device-tree fix-up protocol provides a function to let the + firmware apply fix-ups. This may be used by boot loaders. + config EFI_LOADER_HII bool "HII protocols" default y diff --git a/lib/efi_loader/efi_dt_fixup.c b/lib/efi_loader/efi_dt_fixup.c index c2f2daef33..3850ab3b0f 100644 --- a/lib/efi_loader/efi_dt_fixup.c +++ b/lib/efi_loader/efi_dt_fixup.c @@ -104,10 +104,9 @@ void efi_carve_out_dt_rsv(void *fdt) * @flags: bit field designating action to be performed * Return: status code */ -static efi_status_t EFIAPI efi_dt_fixup(struct efi_dt_fixup_protocol *this, - void *dtb, - efi_uintn_t *buffer_size, - u32 flags) +static efi_status_t __maybe_unused EFIAPI +efi_dt_fixup(struct efi_dt_fixup_protocol *this, void *dtb, + efi_uintn_t *buffer_size, u32 flags) { efi_status_t ret; size_t required_size; diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index b411a12cf6..8383fce943 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -61,7 +61,7 @@ efi_status_t efi_root_node_register(void) /* Device path utilities protocol */ &efi_guid_device_path_utilities_protocol, (void *)&efi_device_path_utilities, -#if !CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) +#ifdef CONFIG_EFI_DT_FIXUP /* Device-tree fix-up protocol */ &efi_guid_dt_fixup_protocol, (void *)&efi_dt_fixup_prot, From 59593a52a3438d163904079ae9c5d4d7c69675bb Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 16 Jan 2021 09:44:25 +0100 Subject: [PATCH 05/12] efi_loader: EFI_DEVICE_PATH_UTILITIES_PROTOCOL configurable Allow the EFI_DEVICE_PATH_UTILITIES_PROTOCOL to be disabled via configuration. On systems that are very tight on U-Boot image size we may want to disable the protocol. As it is required to run the UEFI Shell enable it by default. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 7 +++++++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_root_node.c | 2 ++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 227cfa5ca4..038cdc9b6e 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -208,6 +208,13 @@ config EFI_DEVICE_PATH_TO_TEXT 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 + help + The device path utilities protocol creates and manipulates device + paths and device nodes. It is required to run the EFI Shell. + config EFI_DT_FIXUP bool "Device tree fixup protocol" depends on !GENERATE_ACPI_TABLE diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index a6355d240a..10b42e8847 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o obj-y += efi_console.o obj-y += efi_device_path.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o -obj-y += efi_device_path_utilities.o +obj-$(CONFIG_EFI_DEVICE_PATH_UTIL) += efi_device_path_utilities.o ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) obj-y += efi_dt_fixup.o endif diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index 8383fce943..bfa57c97fc 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -58,9 +58,11 @@ efi_status_t efi_root_node_register(void) &efi_guid_device_path_to_text_protocol, (void *)&efi_device_path_to_text, #endif +#ifdef CONFIG_EFI_DEVICE_PATH_UTIL /* Device path utilities protocol */ &efi_guid_device_path_utilities_protocol, (void *)&efi_device_path_utilities, +#endif #ifdef CONFIG_EFI_DT_FIXUP /* Device-tree fix-up protocol */ &efi_guid_dt_fixup_protocol, From 19ea5e66de3b68fc12533a32c412bfe0594f9ea0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 16 Jan 2021 09:58:06 +0100 Subject: [PATCH 06/12] efi_loader: remove EFI_UNICODE_COLLATION_PROTOCOL In EFI 1.10 a version of the Unicode collation protocol using ISO 639-2 language codes existed. This protocol is not part of the UEFI specification any longer. It was however required to run the UEFI Self Certification Test (SCT) II, version 2.6, 2017. So we implemented it for the sole purpose of running the SCT. As the SCT does not need the protocol anymore it is time for removal. Signed-off-by: Heinrich Schuchardt --- include/efi_api.h | 4 --- include/efi_loader.h | 3 -- lib/efi_loader/Kconfig | 11 -------- lib/efi_loader/efi_root_node.c | 6 ---- lib/efi_loader/efi_unicode_collation.c | 39 ++++---------------------- 5 files changed, 6 insertions(+), 57 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index df9bee2ae4..48e48a6263 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1693,10 +1693,6 @@ struct efi_driver_binding_protocol { efi_handle_t driver_binding_handle; }; -/* Deprecated version of the Unicode collation protocol */ -#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \ - EFI_GUID(0x1d85cd7f, 0xf43d, 0x11d2, \ - 0x9a, 0x0c, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) /* Current version of the Unicode collation protocol */ #define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \ EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \ diff --git a/include/efi_loader.h b/include/efi_loader.h index e53d286b9d..f759cfe287 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -147,9 +147,6 @@ extern const struct efi_device_path_to_text_protocol efi_device_path_to_text; /* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */ extern const struct efi_device_path_utilities_protocol efi_device_path_utilities; -/* deprecated version of the EFI_UNICODE_COLLATION_PROTOCOL */ -extern const struct efi_unicode_collation_protocol - efi_unicode_collation_protocol; /* current version of the EFI_UNICODE_COLLATION_PROTOCOL */ extern const struct efi_unicode_collation_protocol efi_unicode_collation_protocol2; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 038cdc9b6e..e729f727df 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -252,17 +252,6 @@ config EFI_UNICODE_CAPITALIZATION set, only the the correct handling of the letters of the codepage used by the FAT file system is ensured. -config EFI_UNICODE_COLLATION_PROTOCOL - bool "Deprecated version of the Unicode collation protocol" - default n - help - In EFI 1.10 a version of the Unicode collation protocol using ISO - 639-2 language codes existed. This protocol is not part of the UEFI - specification any longer. Unfortunately it is required to run the - UEFI Self Certification Test (SCT) II, version 2.6, 2017. - - Choose this option for testing only. It is bound to be removed. - endif config EFI_LOADER_BOUNCE_BUFFER diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index bfa57c97fc..739c6867f4 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -69,12 +69,6 @@ efi_status_t efi_root_node_register(void) (void *)&efi_dt_fixup_prot, #endif #if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL2) -#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL) - /* Deprecated Unicode collation protocol */ - &efi_guid_unicode_collation_protocol, - (void *)&efi_unicode_collation_protocol, -#endif - /* Current Unicode collation protocol */ &efi_guid_unicode_collation_protocol2, (void *)&efi_unicode_collation_protocol2, #endif diff --git a/lib/efi_loader/efi_unicode_collation.c b/lib/efi_loader/efi_unicode_collation.c index 6655c68092..f6c875bc33 100644 --- a/lib/efi_loader/efi_unicode_collation.c +++ b/lib/efi_loader/efi_unicode_collation.c @@ -38,7 +38,7 @@ const efi_guid_t efi_guid_unicode_collation_protocol2 = * @s2: second string * * This function implements the StriColl() service of the - * EFI_UNICODE_COLLATION_PROTOCOL. + * EFI_UNICODE_COLLATION_PROTOCOL2. * * See the Unified Extensible Firmware Interface (UEFI) specification for * details. @@ -179,7 +179,7 @@ static bool metai_match(const u16 *string, const u16 *pattern) * - [-] matches any character in the range * * This function implements the MetaMatch() service of the - * EFI_UNICODE_COLLATION_PROTOCOL. + * EFI_UNICODE_COLLATION_PROTOCOL2. * * Return: true if the string is matched. */ @@ -204,7 +204,7 @@ static bool EFIAPI efi_metai_match(struct efi_unicode_collation_protocol *this, * same number of words this does not pose a problem. * * This function implements the StrLwr() service of the - * EFI_UNICODE_COLLATION_PROTOCOL. + * EFI_UNICODE_COLLATION_PROTOCOL2. */ static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this, u16 *string) @@ -225,7 +225,7 @@ static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this, * same number of words this does not pose a problem. * * This function implements the StrUpr() service of the - * EFI_UNICODE_COLLATION_PROTOCOL. + * EFI_UNICODE_COLLATION_PROTOCOL2. */ static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this, u16 *string) @@ -245,7 +245,7 @@ static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this, * @string: converted string * * This function implements the FatToStr() service of the - * EFI_UNICODE_COLLATION_PROTOCOL. + * EFI_UNICODE_COLLATION_PROTOCOL2. */ static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this, efi_uintn_t fat_size, char *fat, u16 *string) @@ -276,7 +276,7 @@ static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this, * @fat: converted string * * This function implements the StrToFat() service of the - * EFI_UNICODE_COLLATION_PROTOCOL. + * EFI_UNICODE_COLLATION_PROTOCOL2. * * Return: true if an illegal character was substituted by '_'. */ @@ -337,30 +337,3 @@ const struct efi_unicode_collation_protocol efi_unicode_collation_protocol2 = { .str_to_fat = efi_str_to_fat, .supported_languages = "en", }; - -/* - * In EFI 1.10 a version of the Unicode collation protocol using ISO 639-2 - * language codes existed. This protocol is not part of the UEFI specification - * any longer. Unfortunately it is required to run the UEFI Self Certification - * Test (SCT) II, version 2.6, 2017. So we implement it here for the sole - * purpose of running the SCT. It can be removed when a compliant SCT is - * available. - */ -#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL) - -/* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */ -const efi_guid_t efi_guid_unicode_collation_protocol = - EFI_UNICODE_COLLATION_PROTOCOL_GUID; - -const struct efi_unicode_collation_protocol efi_unicode_collation_protocol = { - .stri_coll = efi_stri_coll, - .metai_match = efi_metai_match, - .str_lwr = efi_str_lwr, - .str_upr = efi_str_upr, - .fat_to_str = efi_fat_to_str, - .str_to_fat = efi_str_to_fat, - /* ISO 639-2 language code */ - .supported_languages = "eng", -}; - -#endif From b6f6080f56986670a3012fa565391da112724d21 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 17 Jan 2021 05:13:21 +0100 Subject: [PATCH 07/12] efi_selftest: ask before overwriting in dtbdump.efi Before overwriting an existing file ask the user. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/dtbdump.c | 60 +++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/lib/efi_selftest/dtbdump.c b/lib/efi_selftest/dtbdump.c index efef759863..cbc9067b5a 100644 --- a/lib/efi_selftest/dtbdump.c +++ b/lib/efi_selftest/dtbdump.c @@ -41,7 +41,51 @@ static void error(u16 *string) } /** - * input() - read string from console + * efi_input_yn() - get answer to yes/no question + * + * Return: + * y or Y + * EFI_SUCCESS + * n or N + * EFI_ACCESS_DENIED + * ESC + * EFI_ABORTED + */ +static efi_status_t efi_input_yn(void) +{ + struct efi_input_key key = {0}; + efi_uintn_t index; + efi_status_t ret; + + /* Drain the console input */ + ret = cin->reset(cin, true); + for (;;) { + ret = bs->wait_for_event(1, &cin->wait_for_key, &index); + if (ret != EFI_SUCCESS) + continue; + ret = cin->read_key_stroke(cin, &key); + if (ret != EFI_SUCCESS) + continue; + switch (key.scan_code) { + case 0x17: /* Escape */ + return EFI_ABORTED; + default: + break; + } + /* Convert to lower case */ + switch (key.unicode_char | 0x20) { + case 'y': + return EFI_SUCCESS; + case 'n': + return EFI_ACCESS_DENIED; + default: + break; + } + } +} + +/** + * efi_input() - read string from console * * @buffer: input buffer * @buffer_size: buffer size @@ -379,6 +423,20 @@ efi_status_t do_save(u16 *filename) error(L"Failed to open volume\n"); return ret; } + /* Check if file already exists */ + ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); + if (ret == EFI_SUCCESS) { + file->close(file); + cout->output_string(cout, L"Overwrite existing file (y/n)? "); + ret = efi_input_yn(); + cout->output_string(cout, L"\n"); + if (ret != EFI_SUCCESS) { + root->close(root); + error(L"Aborted by user\n"); + return ret; + } + } + /* Create file */ ret = root->open(root, &file, filename, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | From 8644af7dc447427f842754d93b1e78217aad98f2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 17 Jan 2021 05:41:41 +0100 Subject: [PATCH 08/12] efi_selftest: don't compile dtbdump if GENERATE_ACPI_TABLE If we are using ACPI tables instead of a device tree, we don't need the dtbdump.efi test tool. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/Makefile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 426552bfa0..fa3dc66baa 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -78,8 +78,9 @@ efi_selftest_miniapp_exception.efi \ efi_selftest_miniapp_exit.efi \ efi_selftest_miniapp_return.efi -always += \ -dtbdump.efi +ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) +always += dtbdump.efi +endif $(obj)/efi_miniapp_file_image_exception.h: $(obj)/efi_selftest_miniapp_exception.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exception.efi > \ From 65ab48d69ddb395406266b0c70a1619d638e579a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 17 Jan 2021 07:30:26 +0100 Subject: [PATCH 09/12] efi_selftest: provide initrddump test tool Provide an UEFI application to save the initial RAM disk provided by U-Boot via the Load File2 protocol. Signed-off-by: Heinrich Schuchardt Acked-by: Ilias Apalodimas --- lib/efi_selftest/Makefile | 6 + lib/efi_selftest/efi_selftest_console.c | 3 +- lib/efi_selftest/initrddump.c | 449 ++++++++++++++++++++++++ 3 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 lib/efi_selftest/initrddump.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index fa3dc66baa..7d6ea30102 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -14,6 +14,8 @@ CFLAGS_efi_selftest_miniapp_exit.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) +CFLAGS_initrddump_exit.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_initrddump.o := $(CFLAGS_NON_EFI) obj-y += \ efi_selftest.o \ @@ -82,6 +84,10 @@ ifeq ($(CONFIG_GENERATE_ACPI_TABLE),) always += dtbdump.efi endif +ifdef CONFIG_EFI_LOAD_FILE2_INITRD +always += initrddump.efi +endif + $(obj)/efi_miniapp_file_image_exception.h: $(obj)/efi_selftest_miniapp_exception.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_exception.efi > \ $(obj)/efi_miniapp_file_image_exception.h diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index 0219bd70e0..ffd88a1e26 100644 --- a/lib/efi_selftest/efi_selftest_console.c +++ b/lib/efi_selftest/efi_selftest_console.c @@ -46,11 +46,10 @@ static void mac(void *pointer, u16 **buf) /* * printx() - print hexadecimal number to an u16 string * - * @pointer: pointer + * @p: value to print * @prec: minimum number of digits to print * @buf: pointer to buffer address, * on return position of terminating zero word - * @size: size of value to be printed in bytes */ static void printx(u64 p, int prec, u16 **buf) { diff --git a/lib/efi_selftest/initrddump.c b/lib/efi_selftest/initrddump.c new file mode 100644 index 0000000000..c23a05c718 --- /dev/null +++ b/lib/efi_selftest/initrddump.c @@ -0,0 +1,449 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020, Heinrich Schuchardt + * + * initrddump.efi saves the initial RAM disk provided via the + * EFI_LOAD_FILE2_PROTOCOL. + */ + +#include +#include +#include + +#define BUFFER_SIZE 64 +#define ESC 0x17 + +#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) + +static struct efi_system_table *systable; +static struct efi_boot_services *bs; +static struct efi_simple_text_output_protocol *cerr; +static struct efi_simple_text_output_protocol *cout; +static struct efi_simple_text_input_protocol *cin; +static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID; +static const efi_guid_t guid_simple_file_system_protocol = + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; +static efi_handle_t handle; + +/* + * Device path defined by Linux to identify the handle providing the + * EFI_LOAD_FILE2_PROTOCOL used for loading the initial ramdisk. + */ +static const struct efi_initrd_dp initrd_dp = { + .vendor = { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR_PATH, + sizeof(initrd_dp.vendor), + }, + EFI_INITRD_MEDIA_GUID, + }, + .end = { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(initrd_dp.end), + } +}; + +/** + * print() - print string + * + * @string: text + */ +static void print(u16 *string) +{ + cout->output_string(cout, string); +} + +/** + * error() - print error string + * + * @string: error text + */ +static void error(u16 *string) +{ + cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK); + print(string); + cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); +} + +/* + * printx() - print hexadecimal number + * + * @val: value to print; + * @prec: minimum number of digits to print + */ +static void printx(u64 val, u32 prec) +{ + int i; + u16 c; + u16 buf[16]; + u16 *pos = buf; + + for (i = 2 * sizeof(val) - 1; i >= 0; --i) { + c = (val >> (4 * i)) & 0x0f; + if (c || pos != buf || !i || i < prec) { + c += '0'; + if (c > '9') + c += 'a' - '9' - 1; + *pos++ = c; + } + } + *pos = 0; + print(buf); +} + +/** + * efi_input_yn() - get answer to yes/no question + * + * Return: + * y or Y + * EFI_SUCCESS + * n or N + * EFI_ACCESS_DENIED + * ESC + * EFI_ABORTED + */ +static efi_status_t efi_input_yn(void) +{ + struct efi_input_key key = {0}; + efi_uintn_t index; + efi_status_t ret; + + /* Drain the console input */ + ret = cin->reset(cin, true); + for (;;) { + ret = bs->wait_for_event(1, &cin->wait_for_key, &index); + if (ret != EFI_SUCCESS) + continue; + ret = cin->read_key_stroke(cin, &key); + if (ret != EFI_SUCCESS) + continue; + switch (key.scan_code) { + case 0x17: /* Escape */ + return EFI_ABORTED; + default: + break; + } + /* Convert to lower case */ + switch (key.unicode_char | 0x20) { + case 'y': + return EFI_SUCCESS; + case 'n': + return EFI_ACCESS_DENIED; + default: + break; + } + } +} + +/** + * efi_input() - read string from console + * + * @buffer: input buffer + * @buffer_size: buffer size + * Return: status code + */ +static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) +{ + struct efi_input_key key = {0}; + efi_uintn_t index; + efi_uintn_t pos = 0; + u16 outbuf[2] = L" "; + efi_status_t ret; + + /* Drain the console input */ + ret = cin->reset(cin, true); + *buffer = 0; + for (;;) { + ret = bs->wait_for_event(1, &cin->wait_for_key, &index); + if (ret != EFI_SUCCESS) + continue; + ret = cin->read_key_stroke(cin, &key); + if (ret != EFI_SUCCESS) + continue; + switch (key.scan_code) { + case 0x17: /* Escape */ + print(L"\r\nAborted\r\n"); + return EFI_ABORTED; + default: + break; + } + switch (key.unicode_char) { + case 0x08: /* Backspace */ + if (pos) { + buffer[pos--] = 0; + print(L"\b \b"); + } + break; + case 0x0a: /* Linefeed */ + case 0x0d: /* Carriage return */ + print(L"\r\n"); + return EFI_SUCCESS; + default: + break; + } + /* Ignore surrogate codes */ + if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF) + continue; + if (key.unicode_char >= 0x20 && + pos < buffer_size - 1) { + *outbuf = key.unicode_char; + buffer[pos++] = key.unicode_char; + buffer[pos] = 0; + print(outbuf); + } + } +} + +/** + * skip_whitespace() - skip over leading whitespace + * + * @pos: UTF-16 string + * Return: pointer to first non-whitespace + */ +static u16 *skip_whitespace(u16 *pos) +{ + for (; *pos && *pos <= 0x20; ++pos) + ; + return pos; +} + +/** + * starts_with() - check if @string starts with @keyword + * + * @string: string to search for keyword + * @keyword: keyword to be searched + * Return: true fi @string starts with the keyword + */ +static bool starts_with(u16 *string, u16 *keyword) +{ + for (; *keyword; ++string, ++keyword) { + if (*string != *keyword) + return false; + } + return true; +} + +/** + * do_help() - print help + */ +static void do_help(void) +{ + error(L"load - show length and CRC32 of initial RAM disk\r\n"); + error(L"save - save initial RAM disk to file\r\n"); + error(L"exit - exit the shell\r\n"); +} + +/** + * get_initrd() - read initial RAM disk via EFI_LOAD_FILE2_PROTOCOL + * + * @initrd: on return buffer with initial RAM disk + * @initrd_size: size of initial RAM disk + * Return: status code + */ +static efi_status_t get_initrd(void **initrd, efi_uintn_t *initrd_size) +{ + struct efi_device_path *dp = (struct efi_device_path *)&initrd_dp; + struct efi_load_file_protocol *load_file2_prot; + u64 buffer; + efi_handle_t handle; + efi_status_t ret; + + *initrd = NULL; + *initrd_size = 0; + ret = bs->locate_device_path(&load_file2_guid, &dp, &handle); + if (ret != EFI_SUCCESS) { + error(L"Load File2 protocol not found\r\n"); + return ret; + } + ret = bs->handle_protocol(handle, &load_file2_guid, + (void **)&load_file2_prot); + ret = load_file2_prot->load_file(load_file2_prot, dp, false, + initrd_size, NULL); + if (ret != EFI_BUFFER_TOO_SMALL) { + error(L"Load File2 protocol does not provide file length\r\n"); + return EFI_LOAD_ERROR; + } + ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_LOADER_DATA, + efi_size_in_pages(*initrd_size), &buffer); + if (ret != EFI_SUCCESS) { + error(L"Out of memory\r\n"); + return ret; + } + *initrd = (void *)buffer; + ret = load_file2_prot->load_file(load_file2_prot, dp, false, + initrd_size, *initrd); + if (ret != EFI_SUCCESS) { + error(L"Load File2 protocol failed to provide file\r\n"); + bs->free_pages(buffer, efi_size_in_pages(*initrd_size)); + return EFI_LOAD_ERROR; + } + return ret; +} + +/** + * do_load() - load initial RAM disk and display CRC32 and length + * + * @filename: file name + * Return: status code + */ +static efi_status_t do_load(void) +{ + void *initrd; + efi_uintn_t initrd_size; + u32 crc32; + efi_uintn_t ret; + + ret = get_initrd(&initrd, &initrd_size); + if (ret != EFI_SUCCESS) + return ret; + print(L"length: 0x"); + printx(initrd_size, 1); + print(L"\r\n"); + + ret = bs->calculate_crc32(initrd, initrd_size, &crc32); + if (ret != EFI_SUCCESS) { + error(L"Calculating CRC32 failed\r\n"); + return EFI_LOAD_ERROR; + } + print(L"crc32: 0x"); + printx(crc32, 8); + print(L"\r\n"); + + return EFI_SUCCESS; +} + +/** + * do_save() - save initial RAM disk + * + * @filename: file name + * Return: status code + */ +static efi_status_t do_save(u16 *filename) +{ + struct efi_loaded_image *loaded_image; + struct efi_simple_file_system_protocol *file_system; + struct efi_file_handle *root, *file; + void *initrd; + efi_uintn_t initrd_size; + efi_uintn_t ret; + + ret = get_initrd(&initrd, &initrd_size); + if (ret != EFI_SUCCESS) + return ret; + + filename = skip_whitespace(filename); + + ret = bs->open_protocol(handle, &loaded_image_guid, + (void **)&loaded_image, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + error(L"Loaded image protocol not found\r\n"); + goto out; + } + + /* Open the simple file system protocol */ + ret = bs->open_protocol(loaded_image->device_handle, + &guid_simple_file_system_protocol, + (void **)&file_system, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + error(L"Failed to open simple file system protocol\r\n"); + goto out; + } + + /* Open volume */ + ret = file_system->open_volume(file_system, &root); + if (ret != EFI_SUCCESS) { + error(L"Failed to open volume\r\n"); + goto out; + } + /* Check if file already exists */ + ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); + if (ret == EFI_SUCCESS) { + file->close(file); + print(L"Overwrite existing file (y/n)? "); + ret = efi_input_yn(); + print(L"\r\n"); + if (ret != EFI_SUCCESS) { + root->close(root); + error(L"Aborted by user\r\n"); + goto out; + } + } + + /* Create file */ + ret = root->open(root, &file, filename, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | + EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE); + if (ret == EFI_SUCCESS) { + /* Write file */ + ret = file->write(file, &initrd_size, initrd); + if (ret != EFI_SUCCESS) { + error(L"Failed to write file\r\n"); + } else { + print(filename); + print(L" written\r\n"); + } + file->close(file); + } else { + error(L"Failed to open file\r\n"); + } + root->close(root); + +out: + if (initrd) + bs->free_pages((uintptr_t)initrd, + efi_size_in_pages(initrd_size)); + return ret; +} + +/** + * efi_main() - entry point of the EFI application. + * + * @handle: handle of the loaded image + * @systab: system table + * @return: status code + */ +efi_status_t EFIAPI efi_main(efi_handle_t image_handle, + struct efi_system_table *systab) +{ + handle = image_handle; + systable = systab; + cerr = systable->std_err; + cout = systable->con_out; + cin = systable->con_in; + bs = systable->boottime; + + cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); + cout->clear_screen(cout); + cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK); + print(L"INITRD Dump\r\n========\r\n\r\n"); + cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); + + for (;;) { + u16 command[BUFFER_SIZE]; + u16 *pos; + efi_uintn_t ret; + + print(L"=> "); + ret = efi_input(command, sizeof(command)); + if (ret == EFI_ABORTED) + break; + pos = skip_whitespace(command); + if (starts_with(pos, L"exit")) + break; + else if (starts_with(pos, L"load")) + do_load(); + else if (starts_with(pos, L"save ")) + do_save(pos + 5); + else + do_help(); + } + + cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); + cout->clear_screen(cout); + return EFI_SUCCESS; +} From d56013d37c829254e181c93dfefa745b9a1347d5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 19 Jan 2021 10:06:00 +0100 Subject: [PATCH 10/12] efi_selftest: use CRLF as line endings in dtbdump EFI applications must use CR LF as line endings. Provide a print() function to reduce code size. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/dtbdump.c | 94 +++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 42 deletions(-) diff --git a/lib/efi_selftest/dtbdump.c b/lib/efi_selftest/dtbdump.c index cbc9067b5a..953b264d9d 100644 --- a/lib/efi_selftest/dtbdump.c +++ b/lib/efi_selftest/dtbdump.c @@ -28,6 +28,16 @@ static struct efi_system_table *systable; static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID; static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; +/** + * print() - print string + * + * @string: text + */ +static void print(u16 *string) +{ + cout->output_string(cout, string); +} + /** * error() - print error string * @@ -36,7 +46,7 @@ static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; static void error(u16 *string) { cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK); - cout->output_string(cout, string); + print(string); cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); } @@ -111,7 +121,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) continue; switch (key.scan_code) { case 0x17: /* Escape */ - cout->output_string(cout, L"\nAborted\n"); + print(L"\r\nAborted\r\n"); return EFI_ABORTED; default: break; @@ -120,12 +130,12 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) case 0x08: /* Backspace */ if (pos) { buffer[pos--] = 0; - cout->output_string(cout, L"\b \b"); + print(L"\b \b"); } break; case 0x0a: /* Linefeed */ case 0x0d: /* Carriage return */ - cout->output_string(cout, L"\n"); + print(L"\r\n"); return EFI_SUCCESS; default: break; @@ -138,7 +148,7 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) *outbuf = key.unicode_char; buffer[pos++] = key.unicode_char; buffer[pos] = 0; - cout->output_string(cout, outbuf); + print(outbuf); } } } @@ -215,9 +225,9 @@ bool starts_with(u16 *string, u16 *keyword) */ void do_help(void) { - error(L"load - load device-tree from file\n"); - error(L"save - save device-tree to file\n"); - error(L"exit - exit the shell\n"); + error(L"load - load device-tree from file\r\n"); + error(L"save - save device-tree to file\r\n"); + error(L"exit - exit the shell\r\n"); } /** @@ -242,7 +252,7 @@ efi_status_t do_load(u16 *filename) ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL, (void **)&dt_fixup_prot); if (ret != EFI_SUCCESS) { - error(L"Device-tree fix-up protocol not found\n"); + error(L"Device-tree fix-up protocol not found\r\n"); return ret; } @@ -252,7 +262,7 @@ efi_status_t do_load(u16 *filename) (void **)&loaded_image, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Loaded image protocol not found\n"); + error(L"Loaded image protocol not found\r\n"); return ret; } /* Open the simple file system protocol */ @@ -261,57 +271,57 @@ efi_status_t do_load(u16 *filename) (void **)&file_system, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Failed to open simple file system protocol\n"); + error(L"Failed to open simple file system protocol\r\n"); goto out; } /* Open volume */ ret = file_system->open_volume(file_system, &root); if (ret != EFI_SUCCESS) { - error(L"Failed to open volume\n"); + error(L"Failed to open volume\r\n"); goto out; } /* Open file */ ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); if (ret != EFI_SUCCESS) { - error(L"File not found\n"); + error(L"File not found\r\n"); goto out; } /* Get file size */ buffer_size = 0; ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL); if (ret != EFI_BUFFER_TOO_SMALL) { - error(L"Can't get file info size\n"); + error(L"Can't get file info size\r\n"); goto out; } ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info); if (ret != EFI_SUCCESS) { - error(L"Out of memory\n"); + error(L"Out of memory\r\n"); goto out; } ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info); if (ret != EFI_SUCCESS) { - error(L"Can't get file info\n"); + error(L"Can't get file info\r\n"); goto out; } buffer_size = info->file_size; pages = efi_size_in_pages(buffer_size); ret = bs->free_pool(info); if (ret != EFI_SUCCESS) - error(L"Can't free memory pool\n"); + error(L"Can't free memory pool\r\n"); /* Read file */ ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_ACPI_RECLAIM_MEMORY, pages, &addr); if (ret != EFI_SUCCESS) { - error(L"Out of memory\n"); + error(L"Out of memory\r\n"); goto out; } dtb = (struct fdt_header *)(uintptr_t)addr; ret = file->read(file, &buffer_size, dtb); if (ret != EFI_SUCCESS) { - error(L"Can't read file\n"); + error(L"Can't read file\r\n"); goto out; } /* Fixup file, expecting EFI_BUFFER_TOO_SMALL */ @@ -322,24 +332,24 @@ efi_status_t do_load(u16 *filename) /* Read file into larger buffer */ ret = bs->free_pages(addr, pages); if (ret != EFI_SUCCESS) - error(L"Can't free memory pages\n"); + error(L"Can't free memory pages\r\n"); pages = efi_size_in_pages(buffer_size); ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_ACPI_RECLAIM_MEMORY, pages, &addr); if (ret != EFI_SUCCESS) { - error(L"Out of memory\n"); + error(L"Out of memory\r\n"); goto out; } dtb = (struct fdt_header *)(uintptr_t)addr; ret = file->setpos(file, 0); if (ret != EFI_SUCCESS) { - error(L"Can't position file\n"); + error(L"Can't position file\r\n"); goto out; } ret = file->read(file, &buffer_size, dtb); if (ret != EFI_SUCCESS) { - error(L"Can't read file\n"); + error(L"Can't read file\r\n"); goto out; } buffer_size = pages << EFI_PAGE_SHIFT; @@ -349,24 +359,24 @@ efi_status_t do_load(u16 *filename) EFI_DT_INSTALL_TABLE); } if (ret == EFI_SUCCESS) - cout->output_string(cout, L"device-tree installed\n"); + print(L"device-tree installed\r\n"); else - error(L"Device-tree fix-up failed\n"); + error(L"Device-tree fix-up failed\r\n"); out: if (addr) { ret2 = bs->free_pages(addr, pages); if (ret2 != EFI_SUCCESS) - error(L"Can't free memory pages\n"); + error(L"Can't free memory pages\r\n"); } if (file) { ret2 = file->close(file); if (ret2 != EFI_SUCCESS) - error(L"Can't close file\n"); + error(L"Can't close file\r\n"); } if (root) { ret2 = root->close(root); if (ret2 != EFI_SUCCESS) - error(L"Can't close volume\n"); + error(L"Can't close volume\r\n"); } return ret; } @@ -388,11 +398,11 @@ efi_status_t do_save(u16 *filename) dtb = get_dtb(systable); if (!dtb) { - error(L"DTB not found\n"); + error(L"DTB not found\r\n"); return EFI_NOT_FOUND; } if (f2h(dtb->magic) != FDT_MAGIC) { - error(L"Wrong device tree magic\n"); + error(L"Wrong device tree magic\r\n"); return EFI_NOT_FOUND; } dtb_size = f2h(dtb->totalsize); @@ -403,7 +413,7 @@ efi_status_t do_save(u16 *filename) (void **)&loaded_image, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Loaded image protocol not found\n"); + error(L"Loaded image protocol not found\r\n"); return ret; } @@ -413,26 +423,26 @@ efi_status_t do_save(u16 *filename) (void **)&file_system, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret != EFI_SUCCESS) { - error(L"Failed to open simple file system protocol\n"); + error(L"Failed to open simple file system protocol\r\n"); return ret; } /* Open volume */ ret = file_system->open_volume(file_system, &root); if (ret != EFI_SUCCESS) { - error(L"Failed to open volume\n"); + error(L"Failed to open volume\r\n"); return ret; } /* Check if file already exists */ ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); if (ret == EFI_SUCCESS) { file->close(file); - cout->output_string(cout, L"Overwrite existing file (y/n)? "); + print(L"Overwrite existing file (y/n)? "); ret = efi_input_yn(); - cout->output_string(cout, L"\n"); + print(L"\r\n"); if (ret != EFI_SUCCESS) { root->close(root); - error(L"Aborted by user\n"); + error(L"Aborted by user\r\n"); return ret; } } @@ -445,16 +455,16 @@ efi_status_t do_save(u16 *filename) /* Write file */ ret = file->write(file, &dtb_size, dtb); if (ret != EFI_SUCCESS) - error(L"Failed to write file\n"); + error(L"Failed to write file\r\n"); file->close(file); } else { - error(L"Failed to open file\n"); + error(L"Failed to open file\r\n"); } root->close(root); if (ret == EFI_SUCCESS) { - cout->output_string(cout, filename); - cout->output_string(cout, L" written\n"); + print(filename); + print(L" written\r\n"); } return ret; @@ -480,7 +490,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle, cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); cout->clear_screen(cout); cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK); - cout->output_string(cout, L"DTB Dump\n========\n\n"); + print(L"DTB Dump\r\n========\r\n\r\n"); cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); for (;;) { @@ -488,7 +498,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle, u16 *pos; efi_uintn_t ret; - cout->output_string(cout, L"=> "); + print(L"=> "); ret = efi_input(command, sizeof(command)); if (ret == EFI_ABORTED) break; From 0a7e5165ec21d8092565a833211b21b356195398 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 17 Jan 2021 07:52:09 +0100 Subject: [PATCH 11/12] efi_loader: efi_size_in_pages() missing parentheses Add parentheses around size to avoid possible operator precedence problems. Signed-off-by: Heinrich Schuchardt --- include/efi_loader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index f759cfe287..f470bbd636 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -561,7 +561,7 @@ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp); * @size: size in bytes * Return: size in pages */ -#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) +#define efi_size_in_pages(size) (((size) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); /* More specific EFI memory allocator, called by EFI payloads */ From 53e54bf50d285597c1553cdf2bd0e646fcd4dd60 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Sat, 16 Jan 2021 17:28:04 +0200 Subject: [PATCH 12/12] efi_loader: Avoid emitting efi_var_buf to .GOT Atish reports that on RISC-V, accessing the EFI variables causes a kernel panic. An objdump of the file verifies that, since the global pointer for efi_var_buf ends up in .GOT section which is not mapped in virtual address space for Linux. 0000000000000084 : 84: 715d addi sp,sp,-80 * objdump -dr 0000000000000086 <.LCFI2>: 86: e0a2 sd s0,64(sp) 88: fc26 sd s1,56(sp) 8a: e486 sd ra,72(sp) 8c: f84a sd s2,48(sp) 8e: f44e sd s3,40(sp) 90: f052 sd s4,32(sp) 92: ec56 sd s5,24(sp) 94: 00000497 auipc s1,0x0 94: R_RISCV_GOT_HI20 efi_var_buf 98: 0004b483 ld s1,0(s1) # 94 <.LCFI2+0xe> 98: R_RISCV_PCREL_LO12_I .L0 98: R_RISCV_RELAX *ABS* * objdump -t 0000000000000084 g F .text.efi_runtime 00000000000000b8 efi_var_mem_find With the patch applied: * objdump -dr 0000000000000086 <.LCFI2>: 86: e0a2 sd s0,64(sp) 88: fc26 sd s1,56(sp) 8a: e486 sd ra,72(sp) 8c: f84a sd s2,48(sp) 8e: f44e sd s3,40(sp) 90: f052 sd s4,32(sp) 92: ec56 sd s5,24(sp) 94: 00000497 auipc s1,0x0 94: R_RISCV_PCREL_HI20 .LANCHOR0 94: R_RISCV_RELAX *ABS* 98: 00048493 mv s1,s1 98: R_RISCV_PCREL_LO12_I .L0 98: R_RISCV_RELAX *ABS* * objdump -t 0000000000000008 l O .data.efi_runtime 0000000000000008 efi_var_buf On arm64 this works, because there's no .GOT entries for this and everything is converted to relative references. * objdump -dr (identical pre-post patch, only the new function shows up) 00000000000000b4 : b4: aa0003ee mov x14, x0 b8: 9000000a adrp x10, 0 b8: R_AARCH64_ADR_PREL_PG_HI21 .data.efi_runtime bc: 91000140 add x0, x10, #0x0 bc: R_AARCH64_ADD_ABS_LO12_NC .data.efi_runtime c0: aa0103ed mov x13, x1 c4: 79400021 ldrh w1, [x1] c8: aa0203eb mov x11, x2 cc: f9400400 ldr x0, [x0, #8] d0: b940100c ldr w12, [x0, #16] d4: 8b0c000c add x12, x0, x12 So let's switch efi_var_buf to static and create a helper function for anyone that needs to update it. Fixes: e01aed47d6a0 ("efi_loader: Enable run-time variable support for tee based variables") Reported-by: Atish Patra Tested-by: Atish Patra Signed-off-by: Ilias Apalodimas Reviewed-by: Heinrich Schuchardt --- include/efi_variable.h | 11 +++++++++++ lib/efi_loader/efi_var_mem.c | 13 ++++++++++++- lib/efi_loader/efi_variable_tee.c | 2 +- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/efi_variable.h b/include/efi_variable.h index bf5076233e..4623a64142 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -306,4 +306,15 @@ efi_status_t __efi_runtime EFIAPI efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *guid); +/** + * efi_var_buf_update() - udpate memory buffer for variables + * + * @var_buf: source buffer + * + * This function copies to the memory buffer for UEFI variables. Call this + * function in ExitBootServices() if memory backed variables are only used + * at runtime to fill the buffer. + */ +void efi_var_buf_update(struct efi_var_file *var_buf); + #endif diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c index d155f25f60..3d335a8274 100644 --- a/lib/efi_loader/efi_var_mem.c +++ b/lib/efi_loader/efi_var_mem.c @@ -10,7 +10,13 @@ #include #include -struct efi_var_file __efi_runtime_data *efi_var_buf; +/* + * The variables efi_var_file and efi_var_entry must be static to avoid + * referencing them via the global offset table (section .got). The GOT + * is neither mapped as EfiRuntimeServicesData nor do we support its + * relocation during SetVirtualAddressMap(). + */ +static struct efi_var_file __efi_runtime_data *efi_var_buf; static struct efi_var_entry __efi_runtime_data *efi_current_var; /** @@ -339,3 +345,8 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, return EFI_SUCCESS; } + +void efi_var_buf_update(struct efi_var_file *var_buf) +{ + memcpy(efi_var_buf, var_buf, EFI_VAR_BUF_SIZE); +} diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index b8808fdeca..51920bcb51 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -702,7 +702,7 @@ void efi_variables_boot_exit_notify(void) if (ret != EFI_SUCCESS) log_err("Can't populate EFI variables. No runtime variables will be available\n"); else - memcpy(efi_var_buf, var_buf, len); + efi_var_buf_update(var_buf); free(var_buf); /* Update runtime service table */