From 28cef9ca2e86d90b6f1266a7eefa8557ae0ba144 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 20 Nov 2020 12:55:22 +0100 Subject: fs: fat: create correct short names The current function set_name() used to create short names has the following deficiencies resolved by this patch: * Long names (e.g. FOO.TXT) are stored even if a short name is enough. * Short names with spaces are created, e.g. "A ~1.TXT". * Short names with illegal characters are created, e.g. "FOO++BAR". * Debug output does not not consider that the short file name has no concluding '\0'. The solution for the following bug is split of into a separate patch: * Short file names must be unique. This patch only provides the loop over possible short file names. Fixes: c30a15e590c ("FAT: Add FAT write feature") Signed-off-by: Heinrich Schuchardt --- lib/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/Kconfig b/lib/Kconfig index 7673d2e4e0..06eb8d07dc 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -168,7 +168,7 @@ config REGEX choice prompt "Pseudo-random library support type" depends on NET_RANDOM_ETHADDR || RANDOM_UUID || CMD_UUID || \ - RNG_SANDBOX || UT_LIB && AES + RNG_SANDBOX || UT_LIB && AES || FAT_WRITE default LIB_RAND help Select the library to provide pseudo-random number generator -- cgit From 470fa190f35006e2641d775d4befbd74108837bc Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 9 Dec 2020 07:38:46 +0100 Subject: efi_loader: don't set EFI_RT_SUPPORTED_UPDATE_CAPSULE The EFI_RT_PROPERTIES_TABLE configuration table indicates which runtime services are available at runtime. Even if CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y, we neither support UpdateCapsule() nor QueryCapsuleCapabilities() at runtime. Thus we should not set the corresponding flags EFI_RT_SUPPORTED_UPDATE_CAPSULE and EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES in RuntimeServicesSupported. Fixes: 2bc27ca8a04a ("efi_loader: define UpdateCapsule api") Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_runtime.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 0b171c1ff7..93c9478b22 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -133,10 +133,6 @@ efi_status_t efi_init_runtime_supported(void) #ifdef CONFIG_EFI_HAVE_RUNTIME_RESET rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_RESET_SYSTEM; #endif - if (IS_ENABLED(CONFIG_EFI_RUNTIME_UPDATE_CAPSULE)) - rt_table->runtime_services_supported |= - (EFI_RT_SUPPORTED_UPDATE_CAPSULE | - EFI_RT_SUPPORTED_QUERY_CAPSULE_CAPABILITIES); ret = efi_install_configuration_table(&efi_rt_properties_table_guid, rt_table); -- cgit From 861072b2a88497366a5b33017c4496406f0084b2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 7 Dec 2020 18:20:57 +0100 Subject: efi_loader: remove EFI_HII_CONFIG_ROUTING_PROTOCOL Our implementation of the EFI_HII_CONFIG_ROUTING_PROTOCOL is a mere stub, where all services return an error code. The protocol is neither needed for the EFI shell nor for the UEFI SCT. To reduce the code size remove it from the U-Boot binary. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_hii_config.c | 10 +++++++--- lib/efi_loader/efi_root_node.c | 3 --- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 0afcaf4813..462d4d9ac4 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -30,7 +30,7 @@ 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-y += efi_file.o -obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o efi_hii_config.o +obj-$(CONFIG_EFI_LOADER_HII) += efi_hii.o obj-y += efi_image_loader.o obj-y += efi_memory.o obj-y += efi_root_node.o diff --git a/lib/efi_loader/efi_hii_config.c b/lib/efi_loader/efi_hii_config.c index 26ea4b9bc0..237e8acf84 100644 --- a/lib/efi_loader/efi_hii_config.c +++ b/lib/efi_loader/efi_hii_config.c @@ -1,9 +1,13 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * EFI Human Interface Infrastructure ... Configuration + * EFI Human Interface Infrastructure ... Configuration * - * Copyright (c) 2017 Leif Lindholm - * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + * Copyright (c) 2017 Leif Lindholm + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + * + * As this is still a non-working stub and the protocol is neither required + * by the EFI shell nor by the UEFI SCT this module has been removed from + * the Makefile. */ #include diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c index f68b0fdc61..b17db312f7 100644 --- a/lib/efi_loader/efi_root_node.c +++ b/lib/efi_loader/efi_root_node.c @@ -77,9 +77,6 @@ efi_status_t efi_root_node_register(void) /* HII database protocol */ &efi_guid_hii_database_protocol, (void *)&efi_hii_database, - /* HII configuration routing protocol */ - &efi_guid_hii_config_routing_protocol, - (void *)&efi_hii_config_routing, #endif NULL)); efi_root->type = EFI_OBJECT_TYPE_U_BOOT_FIRMWARE; -- cgit From 0e9d2d7bc25bd3114e8f6ff0d18cdf9ee675909c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 4 Dec 2020 03:02:03 +0100 Subject: efi_loader: resequence functions in efi_boottime.c For implementing support for the EFI_LOAD_FILE_PROTOCOL in the LoadImage() service we will have to call the LocateDevicePath() service. To avoid a forward declaration resequence the functions. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 164 +++++++++++++++++++++--------------------- 1 file changed, 82 insertions(+), 82 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 246b59d3b3..4f7479d4df 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1769,6 +1769,88 @@ failure: return ret; } +/** + * efi_locate_device_path() - Get the device path and handle of an device + * implementing a protocol + * @protocol: GUID of the protocol + * @device_path: device path + * @device: handle of the device + * + * This function implements the LocateDevicePath service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +static efi_status_t EFIAPI efi_locate_device_path( + const efi_guid_t *protocol, + struct efi_device_path **device_path, + efi_handle_t *device) +{ + struct efi_device_path *dp; + size_t i; + struct efi_handler *handler; + efi_handle_t *handles; + size_t len, len_dp; + size_t len_best = 0; + efi_uintn_t no_handles; + u8 *remainder; + efi_status_t ret; + + EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); + + if (!protocol || !device_path || !*device_path) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Find end of device path */ + len = efi_dp_instance_size(*device_path); + + /* Get all handles implementing the protocol */ + ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL, + &no_handles, &handles)); + if (ret != EFI_SUCCESS) + goto out; + + for (i = 0; i < no_handles; ++i) { + /* Find the device path protocol */ + ret = efi_search_protocol(handles[i], &efi_guid_device_path, + &handler); + if (ret != EFI_SUCCESS) + continue; + dp = (struct efi_device_path *)handler->protocol_interface; + len_dp = efi_dp_instance_size(dp); + /* + * This handle can only be a better fit + * if its device path length is longer than the best fit and + * if its device path length is shorter of equal the searched + * device path. + */ + if (len_dp <= len_best || len_dp > len) + continue; + /* 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; + } + if (len_best) { + remainder = (u8 *)*device_path + len_best; + *device_path = (struct efi_device_path *)remainder; + ret = EFI_SUCCESS; + } else { + ret = EFI_NOT_FOUND; + } +out: + return EFI_EXIT(ret); +} + /** * efi_load_image_from_path() - load an image using a file path * @@ -2403,88 +2485,6 @@ found: return EFI_EXIT(EFI_SUCCESS); } -/** - * efi_locate_device_path() - Get the device path and handle of an device - * implementing a protocol - * @protocol: GUID of the protocol - * @device_path: device path - * @device: handle of the device - * - * This function implements the LocateDevicePath service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. - * - * Return: status code - */ -static efi_status_t EFIAPI efi_locate_device_path( - const efi_guid_t *protocol, - struct efi_device_path **device_path, - efi_handle_t *device) -{ - struct efi_device_path *dp; - size_t i; - struct efi_handler *handler; - efi_handle_t *handles; - size_t len, len_dp; - size_t len_best = 0; - efi_uintn_t no_handles; - u8 *remainder; - efi_status_t ret; - - EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); - - if (!protocol || !device_path || !*device_path) { - ret = EFI_INVALID_PARAMETER; - goto out; - } - - /* Find end of device path */ - len = efi_dp_instance_size(*device_path); - - /* Get all handles implementing the protocol */ - ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL, - &no_handles, &handles)); - if (ret != EFI_SUCCESS) - goto out; - - for (i = 0; i < no_handles; ++i) { - /* Find the device path protocol */ - ret = efi_search_protocol(handles[i], &efi_guid_device_path, - &handler); - if (ret != EFI_SUCCESS) - continue; - dp = (struct efi_device_path *)handler->protocol_interface; - len_dp = efi_dp_instance_size(dp); - /* - * This handle can only be a better fit - * if its device path length is longer than the best fit and - * if its device path length is shorter of equal the searched - * device path. - */ - if (len_dp <= len_best || len_dp > len) - continue; - /* 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; - } - if (len_best) { - remainder = (u8 *)*device_path + len_best; - *device_path = (struct efi_device_path *)remainder; - ret = EFI_SUCCESS; - } else { - ret = EFI_NOT_FOUND; - } -out: - return EFI_EXIT(ret); -} - /** * efi_install_multiple_protocol_interfaces() - Install multiple protocol * interfaces -- cgit From b6f11098c9a619f480582b26edd26c5b195c69f4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 4 Dec 2020 03:33:41 +0100 Subject: efi_loader: move EFI_LOAD_FILE2_PROTOCOL_GUID The EFI_LOAD_FILE_PROTOCOL_GUID and EFI_LOAD_FILE2_PROTOCOL_GUID are needed to complement the implementation of the LoadFile() boot service. Remove a duplicate declaration of a variable for the EFI_LOAD_FILE2_PROTOCOL_GUID. Move the remaining declaration to efi_boottime.c. Add a variable for the EFI_LOAD_FILE_PROTOCOL_GUID. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 3 +++ lib/efi_loader/efi_load_initrd.c | 3 --- lib/efi_selftest/efi_selftest_load_initrd.c | 7 ++++--- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4f7479d4df..afe8adb91e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -81,6 +81,9 @@ const efi_guid_t efi_guid_event_group_ready_to_boot = /* event group ResetSystem() invoked (before ExitBootServices) */ const efi_guid_t efi_guid_event_group_reset_system = EFI_EVENT_GROUP_RESET_SYSTEM; +/* GUIDs of the Load File and Load File2 protocols */ +const efi_guid_t efi_guid_load_file_protocol = EFI_LOAD_FILE_PROTOCOL_GUID; +const efi_guid_t efi_guid_load_file2_protocol = EFI_LOAD_FILE2_PROTOCOL_GUID; static efi_status_t EFIAPI efi_disconnect_controller( efi_handle_t controller_handle, diff --git a/lib/efi_loader/efi_load_initrd.c b/lib/efi_loader/efi_load_initrd.c index d517d686c3..4bf3b5ef68 100644 --- a/lib/efi_loader/efi_load_initrd.c +++ b/lib/efi_loader/efi_load_initrd.c @@ -12,9 +12,6 @@ #include #include -static const efi_guid_t efi_guid_load_file2_protocol = - EFI_LOAD_FILE2_PROTOCOL_GUID; - static efi_status_t EFIAPI efi_load_file2_initrd(struct efi_load_file_protocol *this, struct efi_device_path *file_path, bool boot_policy, diff --git a/lib/efi_selftest/efi_selftest_load_initrd.c b/lib/efi_selftest/efi_selftest_load_initrd.c index fe060a6644..f591dcd211 100644 --- a/lib/efi_selftest/efi_selftest_load_initrd.c +++ b/lib/efi_selftest/efi_selftest_load_initrd.c @@ -86,7 +86,6 @@ static int setup(const efi_handle_t handle, static int execute(void) { - efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; struct efi_load_file_protocol *lf2; struct efi_device_path *dp2, *dp2_invalid; efi_status_t status; @@ -99,13 +98,15 @@ static int execute(void) memset(buffer, 0, sizeof(buffer)); dp2 = (struct efi_device_path *)&dp; - status = boottime->locate_device_path(&lf2_proto_guid, &dp2, &handle); + status = boottime->locate_device_path(&efi_guid_load_file2_protocol, + &dp2, &handle); if (status != EFI_SUCCESS) { efi_st_error("Unable to locate device path\n"); return EFI_ST_FAILURE; } - status = boottime->handle_protocol(handle, &lf2_proto_guid, + status = boottime->handle_protocol(handle, + &efi_guid_load_file2_protocol, (void **)&lf2); if (status != EFI_SUCCESS) { efi_st_error("Unable to locate protocol\n"); -- cgit From c06c55b1f5deb994ef7544f99419b4ab68f82e4f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 4 Dec 2020 09:27:41 +0100 Subject: efi_loader: pass boot_policy to efi_load_image_from_path Implementing support for loading images via the EFI_LOAD_FILE_PROTOCOL requires the boot policy as input for efi_load_image_from_path(). Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index afe8adb91e..f18e384c39 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1860,13 +1860,15 @@ out: * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the * callers obligation to update the memory type as needed. * - * @file_path: the path of the image to load - * @buffer: buffer containing the loaded image - * @size: size of the loaded image - * Return: status code + * @boot_policy: true for request originating from the boot manager + * @file_path: the path of the image to load + * @buffer: buffer containing the loaded image + * @size: size of the loaded image + * Return: status code */ static -efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, +efi_status_t efi_load_image_from_path(bool boot_policy, + struct efi_device_path *file_path, void **buffer, efi_uintn_t *size) { struct efi_file_info *info = NULL; @@ -1968,8 +1970,8 @@ efi_status_t EFIAPI efi_load_image(bool boot_policy, } if (!source_buffer) { - ret = efi_load_image_from_path(file_path, &dest_buffer, - &source_size); + ret = efi_load_image_from_path(boot_policy, file_path, + &dest_buffer, &source_size); if (ret != EFI_SUCCESS) goto error; } else { -- cgit From 0e074d12393ba14536f8a103b28c75f74b7c5896 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 6 Dec 2020 10:47:57 +0100 Subject: efi_loader: carve out efi_load_image_from_file() efi_load_image_from_file() should read via either of: * EFI_SIMPLE_FILE_SYSTEM_PROTOCOL * EFI_LOAD_FILE_PROTOCOL * EFI_LOAD_FILE2_PROTOCOL To make the code readable carve out a function to load the image via the file system protocol. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 45 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index f18e384c39..1983ca3f6b 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1855,32 +1855,26 @@ out: } /** - * efi_load_image_from_path() - load an image using a file path + * efi_load_image_from_file() - load an image from file system * * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the * callers obligation to update the memory type as needed. * - * @boot_policy: true for request originating from the boot manager * @file_path: the path of the image to load * @buffer: buffer containing the loaded image * @size: size of the loaded image * Return: status code */ static -efi_status_t efi_load_image_from_path(bool boot_policy, - struct efi_device_path *file_path, +efi_status_t efi_load_image_from_file(struct efi_device_path *file_path, void **buffer, efi_uintn_t *size) { struct efi_file_info *info = NULL; struct efi_file_handle *f; - static efi_status_t ret; + efi_status_t ret; u64 addr; efi_uintn_t bs; - /* In case of failure nothing is returned */ - *buffer = NULL; - *size = 0; - /* Open file */ f = efi_file_from_path(file_path); if (!f) @@ -1928,6 +1922,39 @@ error: return ret; } +/** + * efi_load_image_from_path() - load an image using a file path + * + * Read a file into a buffer allocated as EFI_BOOT_SERVICES_DATA. It is the + * callers obligation to update the memory type as needed. + * + * @boot_policy: true for request originating from the boot manager + * @file_path: the path of the image to load + * @buffer: buffer containing the loaded image + * @size: size of the loaded image + * Return: status code + */ +static +efi_status_t efi_load_image_from_path(bool boot_policy, + struct efi_device_path *file_path, + void **buffer, efi_uintn_t *size) +{ + efi_handle_t device; + efi_status_t ret; + struct efi_device_path *dp; + + /* In case of failure nothing is returned */ + *buffer = NULL; + *size = 0; + + dp = file_path; + ret = EFI_CALL(efi_locate_device_path( + &efi_simple_file_system_protocol_guid, &dp, &device)); + if (ret == EFI_SUCCESS) + return efi_load_image_from_file(file_path, buffer, size); + return EFI_NOT_FOUND; +} + /** * efi_load_image() - load an EFI image into memory * @boot_policy: true for request originating from the boot manager -- cgit From 3da0b28582004981d6ca6866130d2835c3cbf0d0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 6 Dec 2020 13:00:15 +0100 Subject: efi_loader: support EFI_LOAD_FILE_PROTOCOL Support loading images via the EFI_LOAD_FILE_PROTOCOL and EFI_LOAD_FILE2_PROTOCOL. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 49 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1983ca3f6b..9bd63b6e52 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1942,6 +1942,10 @@ efi_status_t efi_load_image_from_path(bool boot_policy, efi_handle_t device; efi_status_t ret; struct efi_device_path *dp; + struct efi_load_file_protocol *load_file_protocol = NULL; + efi_uintn_t buffer_size; + uint64_t addr, pages; + const efi_guid_t *guid; /* In case of failure nothing is returned */ *buffer = NULL; @@ -1952,7 +1956,50 @@ efi_status_t efi_load_image_from_path(bool boot_policy, &efi_simple_file_system_protocol_guid, &dp, &device)); if (ret == EFI_SUCCESS) return efi_load_image_from_file(file_path, buffer, size); - return EFI_NOT_FOUND; + + ret = EFI_CALL(efi_locate_device_path( + &efi_guid_load_file_protocol, &dp, &device)); + if (ret == EFI_SUCCESS) { + guid = &efi_guid_load_file_protocol; + } else if (!boot_policy) { + guid = &efi_guid_load_file2_protocol; + ret = EFI_CALL(efi_locate_device_path(guid, &dp, &device)); + } + if (ret != EFI_SUCCESS) + return EFI_NOT_FOUND; + ret = EFI_CALL(efi_handle_protocol(device, guid, + (void **)&load_file_protocol)); + if (ret != EFI_SUCCESS) + return EFI_NOT_FOUND; + buffer_size = 0; + ret = load_file_protocol->load_file(load_file_protocol, dp, + boot_policy, &buffer_size, + NULL); + if (ret != EFI_BUFFER_TOO_SMALL) + goto out; + pages = efi_size_in_pages(buffer_size); + ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, EFI_BOOT_SERVICES_DATA, + pages, &addr); + if (ret != EFI_SUCCESS) { + ret = EFI_OUT_OF_RESOURCES; + goto out; + } + ret = EFI_CALL(load_file_protocol->load_file( + load_file_protocol, dp, boot_policy, + &buffer_size, (void *)(uintptr_t)addr)); + if (ret != EFI_SUCCESS) + efi_free_pages(addr, pages); +out: + if (load_file_protocol) + EFI_CALL(efi_close_protocol(device, + &efi_guid_load_file2_protocol, + efi_root, NULL)); + if (ret == EFI_SUCCESS) { + *buffer = (void *)(uintptr_t)addr; + *size = buffer_size; + } + + return ret; } /** -- cgit From 6d78ca8360190a339eaf469d957eb0f89d840bc2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 8 Dec 2020 07:12:10 +0100 Subject: efi_selftest: clean up Makefile Bring all obj-y entries together. Sort *.o targets. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/Makefile | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 58fb43fcdf..706df0b27b 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -25,9 +25,11 @@ efi_selftest_crc32.o \ efi_selftest_devicepath_util.o \ efi_selftest_events.o \ efi_selftest_event_groups.o \ +efi_selftest_exception.o \ efi_selftest_exitbootservices.o \ efi_selftest_gop.o \ efi_selftest_loaded_image.o \ +efi_selftest_loadimage.o \ efi_selftest_manageprotocols.o \ efi_selftest_mem.o \ efi_selftest_memory.o \ @@ -35,6 +37,8 @@ efi_selftest_open_protocol.o \ efi_selftest_register_notify.o \ efi_selftest_reset.o \ efi_selftest_set_virtual_address_map.o \ +efi_selftest_startimage_exit.o \ +efi_selftest_startimage_return.o \ efi_selftest_textinput.o \ efi_selftest_textinputex.o \ efi_selftest_textoutput.o \ @@ -65,12 +69,6 @@ ifeq ($(CONFIG_BLK)$(CONFIG_DOS_PARTITION),yy) obj-y += efi_selftest_block_device.o endif -obj-y += \ -efi_selftest_exception.o \ -efi_selftest_loadimage.o \ -efi_selftest_startimage_exit.o \ -efi_selftest_startimage_return.o - targets += \ efi_miniapp_file_image_exception.h \ efi_miniapp_file_image_exit.h \ @@ -94,10 +92,10 @@ $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi $(obj)/../../tools/file2include $(obj)/efi_selftest_miniapp_return.efi > \ $(obj)/efi_miniapp_file_image_return.h -$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h - $(obj)/efi_selftest_exception.o: $(obj)/efi_miniapp_file_image_exception.h +$(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h + $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h -- cgit From 7f8e656338c442c300034bd5119a2b798a1b098c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 8 Dec 2020 15:55:01 +0100 Subject: efi_selftest: test EFI_LOAD_FILE_PROTOCOL A unit test is supplied to test the support for the EFI_LOAD_FILE_PROTOCOL and the EFI_LOAD_FILE2_PROTOCOL by the LoadImage() boot service. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/Makefile | 3 + lib/efi_selftest/efi_selftest_load_file.c | 475 ++++++++++++++++++++++++++++++ 2 files changed, 478 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_load_file.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 706df0b27b..426552bfa0 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -28,6 +28,7 @@ efi_selftest_event_groups.o \ efi_selftest_exception.o \ efi_selftest_exitbootservices.o \ efi_selftest_gop.o \ +efi_selftest_load_file.o \ efi_selftest_loaded_image.o \ efi_selftest_loadimage.o \ efi_selftest_manageprotocols.o \ @@ -94,6 +95,8 @@ $(obj)/efi_miniapp_file_image_return.h: $(obj)/efi_selftest_miniapp_return.efi $(obj)/efi_selftest_exception.o: $(obj)/efi_miniapp_file_image_exception.h +$(obj)/efi_selftest_load_file.o: $(obj)/efi_miniapp_file_image_exit.h + $(obj)/efi_selftest_loadimage.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h diff --git a/lib/efi_selftest/efi_selftest_load_file.c b/lib/efi_selftest/efi_selftest_load_file.c new file mode 100644 index 0000000000..4473e7c36e --- /dev/null +++ b/lib/efi_selftest/efi_selftest_load_file.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_load_file + * + * Copyright (c) 2020 Heinrich Schuchardt + * + * This test checks the handling of the LOAD_FILE and the LOAD_FILE2 protocol + * by the LoadImage() service. + */ + +#include +/* Include containing the miniapp.efi application */ +#include "efi_miniapp_file_image_exit.h" + +/* Block size of compressed disk image */ +#define COMPRESSED_DISK_IMAGE_BLOCK_SIZE 8 + +/* Binary logarithm of the block size */ +#define LB_BLOCK_SIZE 9 + +#define GUID_VENDOR \ + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \ + 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd1) + +#define GUID_VENDOR2 \ + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, \ + 0x08, 0x72, 0x81, 0x9c, 0x65, 0xfc, 0xbb, 0xd2) + +#define FILE_NAME_SIZE 16 + +static const efi_guid_t efi_st_guid_load_file_protocol = + EFI_LOAD_FILE_PROTOCOL_GUID; +static const efi_guid_t efi_st_guid_load_file2_protocol = + EFI_LOAD_FILE2_PROTOCOL_GUID; +static const efi_guid_t efi_st_guid_device_path = + EFI_DEVICE_PATH_PROTOCOL_GUID; + +static efi_handle_t image_handle; +static struct efi_boot_services *boottime; +static efi_handle_t handle_lf; +static efi_handle_t handle_lf2; + +/* One 8 byte block of the compressed disk image */ +struct line { + size_t addr; + char *line; +}; + +/* Compressed file image */ +struct compressed_file_image { + size_t length; + struct line lines[]; +}; + +static struct compressed_file_image img = EFI_ST_DISK_IMG; + +static int load_file_call_count; +static int load_file2_call_count; + +/* Decompressed file image */ +static u8 *image; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path d; +} dp_lf_prot = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path_file_path f; + u16 file_name[FILE_NAME_SIZE]; + struct efi_device_path e; +} dp_lf_file = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR, + }, + { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16), + } + }, + L"\\lf.efi", + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +struct efi_device_path *dp_lf_file_remainder = &dp_lf_file.f.dp; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path d; +} dp_lf2_prot = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR2, + }, + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +static struct { + struct efi_device_path_vendor v; + struct efi_device_path_file_path f; + u16 file_name[FILE_NAME_SIZE]; + struct efi_device_path e; +} dp_lf2_file = { + { + { + DEVICE_PATH_TYPE_HARDWARE_DEVICE, + DEVICE_PATH_SUB_TYPE_VENDOR, + sizeof(struct efi_device_path_vendor), + }, + GUID_VENDOR2, + }, + { + { + DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16), + } + }, + L"\\lf2.efi", + { + DEVICE_PATH_TYPE_END, + DEVICE_PATH_SUB_TYPE_END, + sizeof(struct efi_device_path), + }, +}; + +struct efi_device_path *dp_lf2_file_remainder = &dp_lf2_file.f.dp; + +/* + * Decompress the disk image. + * + * @image decompressed disk image + * @return status code + */ +static efi_status_t decompress(u8 **image) +{ + u8 *buf; + size_t i; + size_t addr; + size_t len; + efi_status_t ret; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, img.length, + (void **)&buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Out of memory\n"); + return ret; + } + boottime->set_mem(buf, img.length, 0); + + for (i = 0; ; ++i) { + if (!img.lines[i].line) + break; + addr = img.lines[i].addr; + len = COMPRESSED_DISK_IMAGE_BLOCK_SIZE; + if (addr + len > img.length) + len = img.length - addr; + boottime->copy_mem(buf + addr, img.lines[i].line, len); + } + *image = buf; + return ret; +} + +/* + * load_file() - LoadFile() service of a EFI_LOAD_FILE_PROTOCOL + * + * @this: instance of EFI_LOAD_FILE_PROTOCOL + * @file_path: remaining device path + * @boot_policy: true if called by boot manager + * @buffer_size: (required) buffer size + * @buffer: buffer to which the file is to be loaded + */ +efi_status_t EFIAPI load_file(struct efi_load_file_protocol *this, + struct efi_device_path *file_path, + bool boot_policy, + efi_uintn_t *buffer_size, + void *buffer) +{ + ++load_file_call_count; + if (memcmp(file_path, dp_lf_file_remainder, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16) + + sizeof(struct efi_device_path))) { + efi_st_error("Wrong remaining device path\n"); + return EFI_NOT_FOUND; + } + if (this->load_file != load_file) { + efi_st_error("wrong this\n"); + return EFI_INVALID_PARAMETER; + } + if (*buffer_size < img.length) { + *buffer_size = img.length; + return EFI_BUFFER_TOO_SMALL; + } + memcpy(buffer, image, img.length); + *buffer_size = img.length; + return EFI_SUCCESS; +} + + +/* + * load_file2() - LoadFile() service of a EFI_LOAD_FILE2_PROTOCOL + * + * @this: instance of EFI_LOAD_FILE2_PROTOCOL + * @file_path: remaining device path + * @boot_policy: true if called by boot manager + * @buffer_size: (required) buffer size + * @buffer: buffer to which the file is to be loaded + */ +efi_status_t EFIAPI load_file2(struct efi_load_file_protocol *this, + struct efi_device_path *file_path, + bool boot_policy, + efi_uintn_t *buffer_size, + void *buffer) +{ + ++load_file2_call_count; + if (memcmp(file_path, dp_lf2_file_remainder, + sizeof(struct efi_device_path_file_path) + + FILE_NAME_SIZE * sizeof(u16) + + sizeof(struct efi_device_path))) { + efi_st_error("Wrong remaining device path\n"); + return EFI_NOT_FOUND; + } + if (this->load_file != load_file2) { + efi_st_error("wrong this\n"); + return EFI_INVALID_PARAMETER; + } + if (boot_policy) { + efi_st_error("LOAD_FILE2 called with boot_policy = true"); + return EFI_INVALID_PARAMETER; + } + if (*buffer_size < img.length) { + *buffer_size = img.length; + return EFI_BUFFER_TOO_SMALL; + } + memcpy(buffer, image, img.length); + *buffer_size = img.length; + return EFI_SUCCESS; +} + +static struct efi_load_file_protocol lf_prot = {load_file}; +static struct efi_load_file_protocol lf2_prot = {load_file2}; + +/* + * Setup unit test. + * + * Install an EFI_LOAD_FILE_PROTOCOL and an EFI_LOAD_FILE2_PROTOCOL. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + image_handle = handle; + boottime = systable->boottime; + + /* Load the application image into memory */ + decompress(&image); + + ret = boottime->install_multiple_protocol_interfaces( + &handle_lf, + &efi_st_guid_device_path, + &dp_lf_prot, + &efi_st_guid_load_file_protocol, + &lf_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_multiple_protocol_interfaces( + &handle_lf2, + &efi_st_guid_device_path, + &dp_lf2_prot, + &efi_st_guid_load_file2_protocol, + &lf2_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_teardown(void) +{ + efi_status_t ret = EFI_ST_SUCCESS; + + if (handle_lf) { + ret = boottime->uninstall_multiple_protocol_interfaces( + handle_lf, + &efi_st_guid_device_path, + &dp_lf_prot, + &efi_st_guid_load_file_protocol, + &lf_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error( + "UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + } + if (handle_lf2) { + ret = boottime->uninstall_multiple_protocol_interfaces( + handle_lf2, + &efi_st_guid_device_path, + &dp_lf2_prot, + &efi_st_guid_load_file2_protocol, + &lf2_prot, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_error( + "UninstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + } + + if (image) { + ret = boottime->free_pool(image); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free image\n"); + return EFI_ST_FAILURE; + } + } + return ret; +} + +/* + * Execute unit test. + * + * Try loading an image via the EFI_LOAD_FILE_PROTOCOL and the + * EFI_LOAD_FILE2_PROTOCOL. Finally execute the image. + * + * @return: EFI_ST_SUCCESS for success + */ +static int efi_st_load_file_execute(void) +{ + efi_status_t ret; + efi_handle_t handle; + efi_uintn_t exit_data_size = 0; + u16 *exit_data = NULL; + u16 expected_text[] = EFI_ST_SUCCESS_STR; + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(true, image_handle, &dp_lf_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (load_file2_call_count || !load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + ret = boottime->unload_image(handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unload image\n"); + return EFI_ST_FAILURE; + } + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(false, image_handle, &dp_lf_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (load_file2_call_count || !load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + ret = boottime->unload_image(handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to unload image\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->load_image(true, image_handle, &dp_lf2_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_NOT_FOUND) { + efi_st_error( + "Boot manager should not use LOAD_FILE2_PROTOCOL\n"); + return EFI_ST_FAILURE; + } + + load_file_call_count = 0; + load_file2_call_count = 0; + handle = NULL; + ret = boottime->load_image(false, image_handle, &dp_lf2_file.v.dp, NULL, + 0, &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to load image\n"); + return EFI_ST_FAILURE; + } + if (!load_file2_call_count || load_file_call_count) { + efi_st_error("Wrong image loaded\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->start_image(handle, &exit_data_size, &exit_data); + if (ret != EFI_UNSUPPORTED) { + efi_st_error("Wrong return value from application\n"); + return EFI_ST_FAILURE; + } + if (!exit_data || exit_data_size != sizeof(expected_text) || + memcmp(exit_data, expected_text, sizeof(expected_text))) { + efi_st_error("Incorrect exit data\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(exit_data); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to free exit data\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(load_file_protocol) = { + .name = "load file protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = efi_st_load_file_setup, + .execute = efi_st_load_file_execute, + .teardown = efi_st_load_file_teardown, +}; -- cgit From f9ad240e65ac2f45d7b0acd770b5d79e50c3d92f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 10 Jan 2020 12:33:59 +0100 Subject: efi_loader: make efi_protocol_open() non-static Provide efi_protocol_open() as library function. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9bd63b6e52..03053e8660 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2779,7 +2779,7 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) * * Return: status code */ -static efi_status_t efi_protocol_open( +efi_status_t efi_protocol_open( struct efi_handler *handler, void **protocol_interface, void *agent_handle, void *controller_handle, uint32_t attributes) -- cgit From 264485131c59c1c8fa17fe742bbca65cef868d94 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 10 Jan 2020 12:36:01 +0100 Subject: efi_loader: link partition to block device We provide a UEFI driver for block devices. When ConnectController() is called for a handle with the EFI_BLOCK_IO_PROTOCOL this driver creates the partitions. When DisconnectController() is called the handles for the partitions have to be deleted. This requires that the child controllers (partitions) open the EFI_BLOCK_IO_PROTOCOL of the controller (block IO device) with attribute EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_disk.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 7bd1ccec45..496ef29dd8 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -376,6 +376,23 @@ static efi_status_t efi_disk_add_dev( /* Fill in object data */ if (part) { struct efi_device_path *node = efi_dp_part_node(desc, part); + struct efi_handler *handler; + void *protocol_interface; + + /* Parent must expose EFI_BLOCK_IO_PROTOCOL */ + ret = efi_search_protocol(parent, &efi_block_io_guid, &handler); + if (ret != EFI_SUCCESS) + goto error; + + /* + * Link the partition (child controller) to the block device + * (controller). + */ + ret = efi_protocol_open(handler, &protocol_interface, NULL, + &diskobj->header, + EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER); + if (ret != EFI_SUCCESS) + goto error; diskobj->dp = efi_dp_append_node(dp_parent, node); efi_free_pool(node); @@ -453,6 +470,9 @@ static efi_status_t efi_disk_add_dev( } } return EFI_SUCCESS; +error: + efi_delete_handle(&diskobj->header); + return ret; } /** -- cgit