From 8a4c443c00432a242bf601e4a1a193a69cd060c7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 8 May 2019 19:34:48 +0200 Subject: [PATCH 01/19] lib: charset: correct utf8_utf16_strnlen() description Correct the description of utf8_utf16_strnlen() and utf8_utf16_strlen() to reflect that they return u16 count and not byte count. For these functions and utf16_utf8_strnlen() describe the handling of invalid code sequences. Signed-off-by: Heinrich Schuchardt --- include/charset.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/charset.h b/include/charset.h index 65087f76d1..4f7ae8fafd 100644 --- a/include/charset.h +++ b/include/charset.h @@ -46,9 +46,9 @@ int utf8_put(s32 code, char **dst); * * @src: utf-8 string * @count: maximum number of code points to convert - * Return: length in bytes after conversion to utf-16 without the + * Return: length in u16 after conversion to utf-16 without the * trailing \0. If an invalid UTF-8 sequence is hit one - * word will be reserved for a replacement character. + * u16 will be reserved for a replacement character. */ size_t utf8_utf16_strnlen(const char *src, size_t count); @@ -56,8 +56,9 @@ size_t utf8_utf16_strnlen(const char *src, size_t count); * utf8_utf16_strlen() - length of a utf-8 string after conversion to utf-16 * * @src: utf-8 string - * Return: length in bytes after conversion to utf-16 without the - * trailing \0. -1 if the utf-8 string is not valid. + * Return: length in u16 after conversion to utf-16 without the + * trailing \0. If an invalid UTF-8 sequence is hit one + * u16 will be reserved for a replacement character. */ #define utf8_utf16_strlen(a) utf8_utf16_strnlen((a), SIZE_MAX) @@ -127,7 +128,8 @@ size_t utf16_utf8_strnlen(const u16 *src, size_t count); * * @src: utf-16 string * Return: length in bytes after conversion to utf-8 without the - * trailing \0. -1 if the utf-16 string is not valid. + * trailing \0. If an invalid UTF-16 sequence is hit one + * byte will be reserved for a replacement character. */ #define utf16_utf8_strlen(a) utf16_utf8_strnlen((a), SIZE_MAX) From 1db6ab28b29131ccb4f1bb41163c57fa9b5ea3bd Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 8 May 2019 19:41:35 +0200 Subject: [PATCH 02/19] MAINTAINERS: assign include/charset.h Assign include/charset.h to EFI PAYLOAD. The functions defined in this include are used by the UEFI sub-system. Signed-off-by: Heinrich Schuchardt --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 33fd4652a4..c41bc89fe9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -476,6 +476,7 @@ F: doc/README.uefi F: doc/README.iscsi F: Documentation/efi.rst F: include/capitalization.h +F: include/charset.h F: include/cp1250.h F: include/cp437.h F: include/efi* From 5ad3877448a4035bdea4a5de7eb8b8deb8dc068d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 8 May 2019 21:42:36 +0200 Subject: [PATCH 03/19] efi_loader: observe CONFIG_EFI_LOADER_HII If EFI_LOADER_HII is not set, do not unnecessarily compile files for HII protocols. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 4e90a35896..e6bbe43154 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -24,7 +24,7 @@ obj-y += efi_device_path.o obj-y += efi_device_path_to_text.o obj-y += efi_device_path_utilities.o obj-y += efi_file.o -obj-y += efi_hii.o efi_hii_config.o +obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o obj-y += efi_image_loader.o obj-y += efi_memory.o obj-y += efi_root_node.o From 5684c8d1ea3ce39c6850a8acdfb0bb90fe754df0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 8 May 2019 23:17:38 +0200 Subject: [PATCH 04/19] efi_loader: format Kconfig Use if/endif for dependencies to give structure to the configuration menu. Sort important settings to the top. Abbreviate the short description of EFI_LOADER_HII. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 61 +++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 50b050159c..03b082750f 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -16,38 +16,10 @@ config EFI_LOADER interfaces to a loaded EFI application, enabling it to reuse U-Boot's device drivers. -config EFI_UNICODE_CAPITALIZATION - bool "Support Unicode capitalization" - depends on EFI_LOADER - default y - help - Select this option to enable correct handling of the capitalization of - Unicode codepoints in the range 0x0000-0xffff. If this option is not - set, only the the correct handling of the letters of the codepage - used by the FAT file system is ensured. - -config EFI_PLATFORM_LANG_CODES - string "Language codes supported by firmware" - depends on EFI_LOADER - default "en-US" - help - This value is used to initialize the PlatformLangCodes variable. Its - value is a semicolon (;) separated list of language codes in native - RFC 4646 format, e.g. "en-US;de-DE". The first language code is used - to initialize the PlatformLang variable. - -config EFI_LOADER_BOUNCE_BUFFER - bool "EFI Applications use bounce buffers for DMA operations" - depends on EFI_LOADER && ARM64 - default n - help - Some hardware does not support DMA to full 64bit addresses. For this - hardware we can create a bounce buffer so that payloads don't have to - worry about platform details. +if EFI_LOADER config EFI_LOADER_HII - bool "Expose HII protocols to EFI applications" - depends on EFI_LOADER + bool "HII protocols" default y help The Human Interface Infrastructure is a complicated framework that @@ -56,3 +28,32 @@ config EFI_LOADER_HII U-Boot implements enough of its features to be able to run the UEFI Shell, but not more than that. + +config EFI_UNICODE_CAPITALIZATION + bool "Support Unicode capitalization" + default y + help + Select this option to enable correct handling of the capitalization of + Unicode codepoints in the range 0x0000-0xffff. If this option is not + set, only the the correct handling of the letters of the codepage + used by the FAT file system is ensured. + +config EFI_LOADER_BOUNCE_BUFFER + bool "EFI Applications use bounce buffers for DMA operations" + depends on ARM64 + default n + help + Some hardware does not support DMA to full 64bit addresses. For this + hardware we can create a bounce buffer so that payloads don't have to + worry about platform details. + +config EFI_PLATFORM_LANG_CODES + string "Language codes supported by firmware" + default "en-US" + help + This value is used to initialize the PlatformLangCodes variable. Its + value is a semicolon (;) separated list of language codes in native + RFC 4646 format, e.g. "en-US;de-DE". The first language code is used + to initialize the PlatformLang variable. + +endif From 9363fd22df56dcb81aa4f3a8c3adbed539fe297d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 11 May 2019 10:27:58 +0200 Subject: [PATCH 05/19] efi_loader: reword the EFI_LOADER config option No need to mention U-Boot in brief description. Fix several typos, mention iPXE. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 03b082750f..2b7ac6855f 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -1,5 +1,5 @@ config EFI_LOADER - bool "Support running EFI Applications in U-Boot" + bool "Support running UEFI applications" depends on (ARM || X86 || RISCV || SANDBOX) && OF_LIBFDT # We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT @@ -11,10 +11,10 @@ config EFI_LOADER select REGEX imply CFB_CONSOLE_ANSI help - Select this option if you want to run EFI applications (like grub2) - on top of U-Boot. If this option is enabled, U-Boot will expose EFI - interfaces to a loaded EFI application, enabling it to reuse U-Boot's - device drivers. + Select this option if you want to run UEFI applications (like GNU + GRUB or iPXE) on top of U-Boot. If this option is enabled, U-Boot + will expose the UEFI API to a loaded application, enabling it to + reuse U-Boot's device drivers. if EFI_LOADER From 334997356e6c394d0898bdb746e7794f4b226ef3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 8 May 2019 23:24:26 +0200 Subject: [PATCH 06/19] efi_loader: make Unicode collation protocol customizable The Unicode collation protocol is not needed for EBBR compliance. So let's make it a customizable option. The Unicode capitalization table is only needed by this protocol. So let it depend on the Unicode collation protocol. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Kconfig | 11 +++++++++++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_root_node.c | 2 ++ lib/efi_selftest/Makefile | 3 ++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 2b7ac6855f..3feb04a5ed 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -29,6 +29,15 @@ config EFI_LOADER_HII U-Boot implements enough of its features to be able to run the UEFI Shell, but not more than that. +config EFI_UNICODE_COLLATION_PROTOCOL + bool "Unicode collation protocol" + default y + help + The Unicode collation protocol is used for lexical comparisons. It is + required to run the UEFI shell. + +if EFI_UNICODE_COLLATION_PROTOCOL + config EFI_UNICODE_CAPITALIZATION bool "Support Unicode capitalization" default y @@ -38,6 +47,8 @@ config EFI_UNICODE_CAPITALIZATION set, only the the correct handling of the letters of the codepage used by the FAT file system is ensured. +endif + config EFI_LOADER_BOUNCE_BUFFER bool "EFI Applications use bounce buffers for DMA operations" depends on ARM64 diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index e6bbe43154..2b1ae61a3d 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -30,7 +30,7 @@ obj-y += efi_memory.o obj-y += efi_root_node.o obj-y += efi_runtime.o obj-y += efi_setup.o -obj-y += efi_unicode_collation.o +obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL) += efi_unicode_collation.o obj-y += efi_variable.o obj-y += efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index 38514e0820..f36ca3456e 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) /* Device path utilities protocol */ &efi_guid_device_path_utilities_protocol, (void *)&efi_device_path_utilities, +#if CONFIG_IS_ENABLED(EFI_UNICODE_COLLATION_PROTOCOL) /* Unicode collation protocol */ &efi_guid_unicode_collation_protocol, (void *)&efi_unicode_collation_protocol, +#endif #if CONFIG_IS_ENABLED(EFI_LOADER_HII) /* HII string protocol */ &efi_guid_hii_string_protocol, diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index c69ad7a9c0..7fdf189c5c 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -34,11 +34,12 @@ efi_selftest_textinput.o \ efi_selftest_textinputex.o \ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ -efi_selftest_unicode_collation.o \ efi_selftest_util.o \ efi_selftest_variables.o \ efi_selftest_watchdog.o +obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL) += efi_selftest_unicode_collation.o + obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o obj-$(CONFIG_EFI_LOADER_HII) += efi_selftest_hii.o From 64b5ba4d293ac9b5416c286aa2d0051b6a9594d6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 11 May 2019 09:53:33 +0200 Subject: [PATCH 07/19] efi_loader: make device path to text protocol customizable The device path to text protocol is not needed for EBBR compliance. So let's make it a customizable option. Signed-off-by: Heinrich Schuchardt --- cmd/Kconfig | 1 + lib/efi_loader/Kconfig | 7 +++++++ lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_root_node.c | 2 ++ lib/efi_selftest/Makefile | 2 +- lib/vsprintf.c | 4 +++- 6 files changed, 15 insertions(+), 3 deletions(-) diff --git a/cmd/Kconfig b/cmd/Kconfig index fd1beb0684..0d36da2a5c 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1436,6 +1436,7 @@ config CMD_DISPLAY config CMD_EFIDEBUG bool "efidebug - display/configure UEFI environment" depends on EFI_LOADER + select EFI_DEVICE_PATH_TO_TEXT default n help Enable the 'efidebug' command which provides a subset of UEFI diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 3feb04a5ed..6501ee56aa 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -18,6 +18,13 @@ config EFI_LOADER if EFI_LOADER +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_LOADER_HII bool "HII protocols" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 2b1ae61a3d..f3d6773bf6 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -21,7 +21,7 @@ obj-y += efi_bootmgr.o obj-y += efi_boottime.o obj-y += efi_console.o obj-y += efi_device_path.o -obj-y += efi_device_path_to_text.o +obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_device_path_to_text.o obj-y += efi_device_path_utilities.o obj-y += efi_file.o obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index f36ca3456e..d8496cc3c2 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -52,9 +52,11 @@ efi_status_t efi_root_node_register(void) (&efi_root, /* Device path protocol */ &efi_guid_device_path, dp, +#if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT) /* Device path to text protocol */ &efi_guid_device_path_to_text_protocol, (void *)&efi_device_path_to_text, +#endif /* Device path utilities protocol */ &efi_guid_device_path_utilities_protocol, (void *)&efi_device_path_utilities, diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 7fdf189c5c..d0bebc7d0c 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -17,7 +17,6 @@ efi_selftest_config_table.o \ efi_selftest_controllers.o \ efi_selftest_console.o \ efi_selftest_crc32.o \ -efi_selftest_devicepath.o \ efi_selftest_devicepath_util.o \ efi_selftest_events.o \ efi_selftest_event_groups.o \ @@ -38,6 +37,7 @@ efi_selftest_util.o \ efi_selftest_variables.o \ efi_selftest_watchdog.o +obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o obj-$(CONFIG_EFI_UNICODE_COLLATION_PROTOCOL) += efi_selftest_unicode_collation.o obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 3502b8088f..8bbbd48c54 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -296,6 +296,7 @@ static char *string16(char *buf, char *end, u16 *s, int field_width, return buf; } +#if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT) static char *device_path_string(char *buf, char *end, void *dp, int field_width, int precision, int flags) { @@ -314,6 +315,7 @@ static char *device_path_string(char *buf, char *end, void *dp, int field_width, return buf; } #endif +#endif #ifdef CONFIG_CMD_NET static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, @@ -451,7 +453,7 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, switch (*fmt) { /* Device paths only exist in the EFI context. */ -#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) +#if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT) && !defined(API_BUILD) case 'D': return device_path_string(buf, end, ptr, field_width, precision, flags); From 0a84319665e764ab1c9f619f43c01ef1627f4053 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 10 May 2019 19:03:49 +0200 Subject: [PATCH 08/19] efi_loader: fix typo in efi_locate_handle() comment %s/not buffer/no buffer/ Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b97d55cb45..887baaab02 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1439,7 +1439,7 @@ static efi_status_t efi_locate_handle( *buffer_size = size; - /* The buffer size is sufficient but there is not buffer */ + /* The buffer size is sufficient but there is no buffer */ if (!buffer) return EFI_INVALID_PARAMETER; From ab557141c2ddb9cccffa992651a240b63d5fbf5b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 10 May 2019 19:21:41 +0200 Subject: [PATCH 09/19] efi_loader: LocateDevicePath() incorrect parameter check A parameter check in LocateDevicePath() does not match the requirements of the UEFI spec. If device is NULL, only return EFI_INVALID_PARAMETER if a matching handle is found. Cf. UEFI SCT II specification (2017)3.3.7 LocateDevicePath(), 5.1.3.7.3 Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 887baaab02..50c5374e5f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2261,7 +2261,7 @@ static efi_status_t EFIAPI efi_locate_device_path( EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); - if (!protocol || !device_path || !*device_path || !device) { + if (!protocol || !device_path || !*device_path) { ret = EFI_INVALID_PARAMETER; goto out; } @@ -2294,6 +2294,10 @@ static efi_status_t EFIAPI efi_locate_device_path( /* Check if dp is a subpath of device_path */ if (memcmp(*device_path, dp, len_dp)) continue; + if (!device) { + ret = EFI_INVALID_PARAMETER; + goto out; + } *device = handles[i]; len_best = len_dp; } From 61c63db7fe8af569229cb598b018c65f9ad9c95f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 10 May 2019 19:55:53 +0200 Subject: [PATCH 10/19] efi_loader: superfluous check in efi_remove_protocol() efi_search_protocol() already checks that the GUID matches. Don't check a second time. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 50c5374e5f..b8589b9531 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -513,8 +513,6 @@ efi_status_t efi_remove_protocol(const efi_handle_t handle, ret = efi_search_protocol(handle, protocol, &handler); if (ret != EFI_SUCCESS) return ret; - if (guidcmp(handler->guid, protocol)) - return EFI_INVALID_PARAMETER; if (handler->protocol_interface != protocol_interface) return EFI_INVALID_PARAMETER; list_del(&handler->link); From 96aa99cded0096bd6c6ea2919e6884c54c80f095 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 10 May 2019 20:06:48 +0200 Subject: [PATCH 11/19] efi_loader: error code in UninstallProtocolInterface() According to the UEFI specification UninstallProtocolInteface() has to return EFI_NOT_FOUND if the interface is not found. Correct the return value. Cf. UEFI SCT II spec (2017), 3.3.2 UninstallProtocolInterface(), 5.1.3.2.4 Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b8589b9531..b583ac6a42 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -514,7 +514,7 @@ efi_status_t efi_remove_protocol(const efi_handle_t handle, if (ret != EFI_SUCCESS) return ret; if (handler->protocol_interface != protocol_interface) - return EFI_INVALID_PARAMETER; + return EFI_NOT_FOUND; list_del(&handler->link); free(handler); return EFI_SUCCESS; From 7d3af58ed9aa84175ed92a901db558f443b33e46 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 10 May 2019 21:21:30 +0200 Subject: [PATCH 12/19] efi_loader: check memory address before freeing When we call FreePages() we essentially add memory to our memory map. We shouldn't do this for memory that does not exit. Check if the memory that is to be freed via FreePages() or FreePool() is in our memory map and is not EFI_CONVENTIONAL_MEMORY. This check is mandated by the UEFI specification. Cf. UEFI SCT II (2017), 3.2.2 FreePages(), 5.1.2.1 - 5.1.2.2 Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_memory.c | 52 +++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 776077cc35..b75722dac3 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -318,6 +318,42 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, return start; } +/** + * efi_check_allocated() - validate address to be freed + * + * Check that the address is within allocated memory: + * + * * The address cannot be NULL. + * * The address must be in a range of the memory map. + * * The address may not point to EFI_CONVENTIONAL_MEMORY. + * + * Page alignment is not checked as this is not a requirement of + * efi_free_pool(). + * + * @addr: address of page to be freed + * Return: status code + */ +static efi_status_t efi_check_allocated(u64 addr) +{ + struct efi_mem_list *item; + + if (!addr) + return EFI_INVALID_PARAMETER; + list_for_each_entry(item, &efi_mem, link) { + u64 start = item->desc.physical_start; + u64 end = start + (item->desc.num_pages << EFI_PAGE_SHIFT); + + if (addr >= start && addr < end) { + if (item->desc.type != EFI_CONVENTIONAL_MEMORY) + return EFI_SUCCESS; + else + return EFI_NOT_FOUND; + } + } + + return EFI_NOT_FOUND; +} + static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr) { struct list_head *lhandle; @@ -450,6 +486,11 @@ void *efi_alloc(uint64_t len, int memory_type) efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) { uint64_t r = 0; + efi_status_t ret; + + ret = efi_check_allocated(memory); + if (ret != EFI_SUCCESS) + return ret; /* Sanity check */ if (!memory || (memory & EFI_PAGE_MASK) || !pages) { @@ -511,11 +552,12 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) */ efi_status_t efi_free_pool(void *buffer) { - efi_status_t r; + efi_status_t ret; struct efi_pool_allocation *alloc; - if (buffer == NULL) - return EFI_INVALID_PARAMETER; + ret = efi_check_allocated((uintptr_t)buffer); + if (ret != EFI_SUCCESS) + return ret; alloc = container_of(buffer, struct efi_pool_allocation, data); @@ -528,9 +570,9 @@ efi_status_t efi_free_pool(void *buffer) /* Avoid double free */ alloc->checksum = 0; - r = efi_free_pages((uintptr_t)alloc, alloc->num_pages); + ret = efi_free_pages((uintptr_t)alloc, alloc->num_pages); - return r; + return ret; } /* From 735fd22800bbe3177edf1491a26794427541102d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 11 May 2019 07:55:05 +0200 Subject: [PATCH 13/19] efi_loader: out of resources in AllocatePages() According to the UEFI AllocatePages() has to return EFI_OUT_OF_RESOURCES if sufficient memory is not available. Change the return value. UEFI SCT II (2017): 3.2.1 AllocatePages(), 5.1.2.1.8 Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index b75722dac3..adbeb1db6b 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -424,7 +424,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, /* Any page */ addr = efi_find_free_memory(len, -1ULL); if (!addr) { - r = EFI_NOT_FOUND; + r = EFI_OUT_OF_RESOURCES; break; } break; @@ -432,7 +432,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, /* Max address */ addr = efi_find_free_memory(len, *memory); if (!addr) { - r = EFI_NOT_FOUND; + r = EFI_OUT_OF_RESOURCES; break; } break; From f756fe83b0d6e189dd524346d22f668d0861e573 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 11 May 2019 08:21:17 +0200 Subject: [PATCH 14/19] efi_loader: AllocateAdress error handling If AllocatePages() is called with AllocateAddress, the UEFI spec requires to return EFI_NOT_FOUND in case the memory page does not exist. The UEFI SCT II 2017 spec additionally requires to return EFI_NOT_FOUND if the page is already allocated. Check that *Memory refers to an unallocated page. UEFI SCT II (2017): AllocatePages(), 5.1.2.1.9 - 5.1.2.1.10 Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_memory.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index adbeb1db6b..11d5547007 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -330,10 +330,11 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, * Page alignment is not checked as this is not a requirement of * efi_free_pool(). * - * @addr: address of page to be freed - * Return: status code + * @addr: address of page to be freed + * @must_be_allocated: return success if the page is allocated + * Return: status code */ -static efi_status_t efi_check_allocated(u64 addr) +static efi_status_t efi_check_allocated(u64 addr, bool must_be_allocated) { struct efi_mem_list *item; @@ -344,7 +345,8 @@ static efi_status_t efi_check_allocated(u64 addr) u64 end = start + (item->desc.num_pages << EFI_PAGE_SHIFT); if (addr >= start && addr < end) { - if (item->desc.type != EFI_CONVENTIONAL_MEMORY) + if (must_be_allocated ^ + (item->desc.type == EFI_CONVENTIONAL_MEMORY)) return EFI_SUCCESS; else return EFI_NOT_FOUND; @@ -438,6 +440,11 @@ efi_status_t efi_allocate_pages(int type, int memory_type, break; case EFI_ALLOCATE_ADDRESS: /* Exact address, reserve it. The addr is already in *memory. */ + r = efi_check_allocated(*memory, false); + if (r != EFI_SUCCESS) { + r = EFI_NOT_FOUND; + break; + } addr = *memory; break; default: @@ -488,7 +495,7 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) uint64_t r = 0; efi_status_t ret; - ret = efi_check_allocated(memory); + ret = efi_check_allocated(memory, true); if (ret != EFI_SUCCESS) return ret; @@ -555,7 +562,7 @@ efi_status_t efi_free_pool(void *buffer) efi_status_t ret; struct efi_pool_allocation *alloc; - ret = efi_check_allocated((uintptr_t)buffer); + ret = efi_check_allocated((uintptr_t)buffer, true); if (ret != EFI_SUCCESS) return ret; From 8ae39857b93edfe697c223fa2f2edfb39d45c98c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 11 May 2019 08:43:30 +0200 Subject: [PATCH 15/19] efi_loader: simplify efi_allocate_pages() Replace unnecessary control structures by using return statements. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_memory.c | 43 +++++++++++++------------------------ 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 11d5547007..76dcaa48f4 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -411,7 +411,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, efi_uintn_t pages, uint64_t *memory) { u64 len = pages << EFI_PAGE_SHIFT; - efi_status_t r = EFI_SUCCESS; + efi_status_t ret; uint64_t addr; /* Check import parameters */ @@ -425,48 +425,35 @@ efi_status_t efi_allocate_pages(int type, int memory_type, case EFI_ALLOCATE_ANY_PAGES: /* Any page */ addr = efi_find_free_memory(len, -1ULL); - if (!addr) { - r = EFI_OUT_OF_RESOURCES; - break; - } + if (!addr) + return EFI_OUT_OF_RESOURCES; break; case EFI_ALLOCATE_MAX_ADDRESS: /* Max address */ addr = efi_find_free_memory(len, *memory); - if (!addr) { - r = EFI_OUT_OF_RESOURCES; - break; - } + if (!addr) + return EFI_OUT_OF_RESOURCES; break; case EFI_ALLOCATE_ADDRESS: /* Exact address, reserve it. The addr is already in *memory. */ - r = efi_check_allocated(*memory, false); - if (r != EFI_SUCCESS) { - r = EFI_NOT_FOUND; - break; - } + ret = efi_check_allocated(*memory, false); + if (ret != EFI_SUCCESS) + return EFI_NOT_FOUND; addr = *memory; break; default: /* UEFI doesn't specify other allocation types */ - r = EFI_INVALID_PARAMETER; - break; + return EFI_INVALID_PARAMETER; } - if (r == EFI_SUCCESS) { - uint64_t ret; + /* Reserve that map in our memory maps */ + if (efi_add_memory_map(addr, pages, memory_type, true) != addr) + /* Map would overlap, bail out */ + return EFI_OUT_OF_RESOURCES; - /* Reserve that map in our memory maps */ - ret = efi_add_memory_map(addr, pages, memory_type, true); - if (ret == addr) { - *memory = addr; - } else { - /* Map would overlap, bail out */ - r = EFI_OUT_OF_RESOURCES; - } - } + *memory = addr; - return r; + return EFI_SUCCESS; } void *efi_alloc(uint64_t len, int memory_type) From 3b985113be63821c799ae6ee98690f740f49a0e9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 11 May 2019 21:44:59 +0200 Subject: [PATCH 16/19] efi_loader: infinite recursion notifying events UEFI SCT uses this call sequence to determine the current TPL level inside notification functions: OldTpl = BS->RaiseTPL(TPL_HIGH_LEVEL); BS->RestoreTPL(OldTpl); In RestoreTPL() we trigger the notification function of queued events. If we do not mark the event as non-queued before calling the notification function, this results in an infinite recursive call sequence. Mark the event as non-queued before entering the notification function. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b583ac6a42..ec6f5758de 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -181,10 +181,12 @@ static void efi_queue_event(struct efi_event *event, bool check_tpl) /* Check TPL */ if (check_tpl && efi_tpl >= event->notify_tpl) return; + event->is_queued = false; EFI_CALL_VOID(event->notify_function(event, event->notify_context)); + } else { + event->is_queued = false; } - event->is_queued = false; } /** From 05fefe768177dee6d5ffa6e95867806adc030c21 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 11 May 2019 23:11:48 +0200 Subject: [PATCH 17/19] efi_loader: ACPI device node to text The device path to text protocol renders ACPI device nodes incorrectly. Use capital hexadecimal numbers as shown in the UEFI spec examples. Always output the optional UID. This matches what UEFI SCT expects and saves us an `if`. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_device_path_to_text.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index e219f84b28..f3a9579076 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -78,9 +78,9 @@ static char *dp_acpi(char *s, struct efi_device_path *dp) case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: { struct efi_device_path_acpi_path *adp = (struct efi_device_path_acpi_path *)dp; - s += sprintf(s, "Acpi(PNP%04x", EISA_PNP_NUM(adp->hid)); - if (adp->uid) - s += sprintf(s, ",%d", adp->uid); + + s += sprintf(s, "Acpi(PNP%04X", EISA_PNP_NUM(adp->hid)); + s += sprintf(s, ",%d", adp->uid); s += sprintf(s, ")"); break; } From 7e92db810b814198d57b10d438f146f181417194 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 May 2019 20:16:25 +0200 Subject: [PATCH 18/19] efi_loader: deduplicate code in cmd/bootefi.c Move duplicate initialization code to single instance. Adjust comments of concerned functions. Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 99 +++++++++++++++++++-------------------------------- 1 file changed, 37 insertions(+), 62 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 52116b308c..0b3c5cdb90 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -314,32 +314,15 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle) } /** - * do_efibootmgr() - execute EFI Boot Manager + * do_efibootmgr() - execute EFI boot manager * - * @fdt_opt: string of fdt start address * Return: status code - * - * Execute EFI Boot Manager */ -static int do_efibootmgr(const char *fdt_opt) +static int do_efibootmgr(void) { efi_handle_t handle; efi_status_t ret; - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } - - ret = efi_install_fdt(fdt_opt); - if (ret == EFI_INVALID_PARAMETER) - return CMD_RET_USAGE; - else if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - ret = efi_bootmgr_load(&handle); if (ret != EFI_SUCCESS) { printf("EFI boot manager: Cannot load any image\n"); @@ -355,16 +338,15 @@ static int do_efibootmgr(const char *fdt_opt) } /* - * do_bootefi_image() - execute EFI binary from command line + * do_bootefi_image() - execute EFI binary + * + * Set up memory image for the binary to be loaded, prepare device path, and + * then call do_bootefi_exec() to execute it. * * @image_opt: string of image start address - * @fdt_opt: string of fdt start address * Return: status code - * - * Set up memory image for the binary to be loaded, prepare - * device path and then call do_bootefi_exec() to execute it. */ -static int do_bootefi_image(const char *image_opt, const char *fdt_opt) +static int do_bootefi_image(const char *image_opt) { void *image_buf; struct efi_device_path *device_path, *image_path; @@ -374,20 +356,6 @@ static int do_bootefi_image(const char *image_opt, const char *fdt_opt) efi_handle_t mem_handle = NULL, handle; efi_status_t ret; - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } - - ret = efi_install_fdt(fdt_opt); - if (ret == EFI_INVALID_PARAMETER) - return CMD_RET_USAGE; - else if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - #ifdef CONFIG_CMD_BOOTEFI_HELLO if (!strcmp(image_opt, "hello")) { char *saddr; @@ -547,33 +515,16 @@ static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj, } /** - * do_efi_selftest() - execute EFI Selftest + * do_efi_selftest() - execute EFI selftest * - * @fdt_opt: string of fdt start address * Return: status code - * - * Execute EFI Selftest */ -static int do_efi_selftest(const char *fdt_opt) +static int do_efi_selftest(void) { struct efi_loaded_image_obj *image_obj; struct efi_loaded_image *loaded_image_info; efi_status_t ret; - /* Initialize EFI drivers */ - ret = efi_init_obj_list(); - if (ret != EFI_SUCCESS) { - printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", - ret & ~EFI_ERROR_MASK); - return CMD_RET_FAILURE; - } - - ret = efi_install_fdt(fdt_opt); - if (ret == EFI_INVALID_PARAMETER) - return CMD_RET_USAGE; - else if (ret != EFI_SUCCESS) - return CMD_RET_FAILURE; - ret = bootefi_test_prepare(&image_obj, &loaded_image_info, "\\selftest", "efi_selftest"); if (ret != EFI_SUCCESS) @@ -587,20 +538,44 @@ static int do_efi_selftest(const char *fdt_opt) } #endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ -/* Interpreter command to boot an arbitrary EFI image from memory */ +/** + * do_bootefi() - execute `bootefi` command + * + * @cmdtp: table entry describing command + * @flag: bitmap indicating how the command was invoked + * @argc: number of arguments + * @argv: command line arguments + * Return: status code + */ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + efi_status_t ret; + if (argc < 2) return CMD_RET_USAGE; + /* Initialize EFI drivers */ + ret = efi_init_obj_list(); + if (ret != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + ret & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + ret = efi_install_fdt(argc > 2 ? argv[2] : NULL); + if (ret == EFI_INVALID_PARAMETER) + return CMD_RET_USAGE; + else if (ret != EFI_SUCCESS) + return CMD_RET_FAILURE; + if (!strcmp(argv[1], "bootmgr")) - return do_efibootmgr(argc > 2 ? argv[2] : NULL); + return do_efibootmgr(); #ifdef CONFIG_CMD_BOOTEFI_SELFTEST else if (!strcmp(argv[1], "selftest")) - return do_efi_selftest(argc > 2 ? argv[2] : NULL); + return do_efi_selftest(); #endif - return do_bootefi_image(argv[1], argc > 2 ? argv[2] : NULL); + return do_bootefi_image(argv[1]); } #ifdef CONFIG_SYS_LONGHELP From e2d82f8b2a91fb3fa78345f935a93a6db575effa Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 12 May 2019 20:16:25 +0200 Subject: [PATCH 19/19] efi_loader: comments for efi_install_fdt() Describe that efi_install_fdt() defaults to using the device tree indicated by environment variable fdtcontroladdr. ACPI tables and device trees are mutually exclusive. Signed-off-by: Heinrich Schuchardt --- cmd/bootefi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 0b3c5cdb90..c19256e00d 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -196,11 +196,16 @@ static void *get_config_table(const efi_guid_t *guid) /** * efi_install_fdt() - install fdt passed by a command argument + * + * If fdt_opt is available, the device tree located at that memory address will + * will be installed as configuration table, otherwise the device tree located + * at the address indicated by environment variable fdtcontroladdr will be used. + * + * On architectures (x86) using ACPI tables device trees shall not be installed + * as configuration table. + * * @fdt_opt: pointer to argument * Return: status code - * - * If specified, fdt will be installed as configuration table, - * otherwise no fdt will be passed. */ static efi_status_t efi_install_fdt(const char *fdt_opt) {