From b33f246c0b6affe16c5df1459fe6d35c15a3c672 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Sep 2022 15:56:51 +0200 Subject: efi_selftest: export efi_st_get_config_table() We can use efi_st_get_config_table() in multiple unit tests. Export the function. Export system-table and boot-services. Signed-off-by: Heinrich Schuchardt --- lib/efi_selftest/efi_selftest.c | 38 ++++++++++++++++++------------------ lib/efi_selftest/efi_selftest_fdt.c | 17 ---------------- lib/efi_selftest/efi_selftest_util.c | 11 +++++++++++ 3 files changed, 30 insertions(+), 36 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 8e427b9e511..191da7fc451 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -14,8 +14,8 @@ #define EFI_ST_EXECUTE 2 #define EFI_ST_TEARDOWN 4 -static const struct efi_system_table *systable; -static const struct efi_boot_services *boottime; +const struct efi_system_table *st_systable; +const struct efi_boot_services *st_boottime; static const struct efi_runtime_services *runtime; static efi_handle_t handle; static u16 reset_message[] = u"Selftest completed"; @@ -41,7 +41,7 @@ void efi_st_exit_boot_services(void) /* Do not detach devices in ExitBootServices. We need the console. */ efi_st_keep_devices = true; - ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + ret = st_boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, &desc_version); if (ret != EFI_BUFFER_TOO_SMALL) { efi_st_error( @@ -50,19 +50,19 @@ void efi_st_exit_boot_services(void) } /* Allocate extra space for newly allocated memory */ map_size += sizeof(struct efi_mem_desc); - ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, + ret = st_boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, (void **)&memory_map); if (ret != EFI_SUCCESS) { efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); return; } - ret = boottime->get_memory_map(&map_size, memory_map, &map_key, + ret = st_boottime->get_memory_map(&map_size, memory_map, &map_key, &desc_size, &desc_version); if (ret != EFI_SUCCESS) { efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); return; } - ret = boottime->exit_boot_services(handle, map_key); + ret = st_boottime->exit_boot_services(handle, map_key); if (ret != EFI_SUCCESS) { efi_st_error("ExitBootServices did not return EFI_SUCCESS\n"); return; @@ -84,7 +84,7 @@ static int setup(struct efi_unit_test *test, unsigned int *failures) if (!test->setup) return EFI_ST_SUCCESS; efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name); - ret = test->setup(handle, systable); + ret = test->setup(handle, st_systable); if (ret != EFI_ST_SUCCESS) { efi_st_error("Setting up '%s' failed\n", test->name); ++*failures; @@ -240,8 +240,8 @@ void efi_st_do_tests(const u16 *testname, unsigned int phase, * All tests use a driver model and are run in three phases: * setup, execute, teardown. * - * A test may be setup and executed at boottime, - * it may be setup at boottime and executed at runtime, + * A test may be setup and executed at st_boottime, + * it may be setup at st_boottime and executed at runtime, * or it may be setup and executed at runtime. * * After executing all tests the system is reset. @@ -257,14 +257,14 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, struct efi_loaded_image *loaded_image; efi_status_t ret; - systable = systab; - boottime = systable->boottime; - runtime = systable->runtime; + st_systable = systab; + st_boottime = st_systable->boottime; + runtime = st_systable->runtime; handle = image_handle; - con_out = systable->con_out; - con_in = systable->con_in; + con_out = st_systable->con_out; + con_in = st_systable->con_in; - ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, + ret = st_boottime->handle_protocol(image_handle, &efi_guid_loaded_image, (void **)&loaded_image); if (ret != EFI_SUCCESS) { efi_st_error("Cannot open loaded image protocol\n"); @@ -280,9 +280,9 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, list_all_tests(); /* * TODO: - * Once the Exit boottime service is correctly + * Once the Exit st_boottime service is correctly * implemented we should call - * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); + * st_boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); * here, cf. * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html */ @@ -300,7 +300,7 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, efi_unit_test)); /* Allocate buffer for setup results */ - ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) * + ret = st_boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) * ll_entry_count(struct efi_unit_test, efi_unit_test), (void **)&setup_status); @@ -309,7 +309,7 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, return ret; } - /* Execute boottime tests */ + /* Execute st_boottime tests */ efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c index 114ac58bf5c..aa3b13ae3ab 100644 --- a/lib/efi_selftest/efi_selftest_fdt.c +++ b/lib/efi_selftest/efi_selftest_fdt.c @@ -144,23 +144,6 @@ static char *get_property(const u16 *property, const u16 *node) return NULL; } -/** - * efi_st_get_config_table() - get configuration table - * - * @guid: GUID of the configuration table - * Return: pointer to configuration table or NULL - */ -static void *efi_st_get_config_table(const efi_guid_t *guid) -{ - size_t i; - - for (i = 0; i < systab.nr_tables; i++) { - if (!guidcmp(guid, &systemtab->tables[i].guid)) - return systemtab->tables[i].table; - } - return NULL; -} - /* * Setup unit test. * diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c index dba02d6b567..7e03e0c9392 100644 --- a/lib/efi_selftest/efi_selftest_util.c +++ b/lib/efi_selftest/efi_selftest_util.c @@ -110,3 +110,14 @@ int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2) } return 0; } + +void *efi_st_get_config_table(const efi_guid_t *guid) +{ + size_t i; + + for (i = 0; i < st_systable->nr_tables; i++) { + if (!guidcmp(guid, &st_systable->tables[i].guid)) + return st_systable->tables[i].table; + } + return NULL; +} -- cgit v1.3.1 From 1e30e377a62fad6e22cdfabf9847662695f68ba8 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 3 Sep 2022 15:58:19 +0200 Subject: efi_selftest: unit test for EFI Conformance Profile Table Add a new unit test to test the integrity of the EFI Conformance Profile Table. Signed-off-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_ecpt.c | 76 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_ecpt.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 33536c9ec02..daac6c39682 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -49,6 +49,7 @@ efi_selftest_variables.o \ efi_selftest_variables_runtime.o \ efi_selftest_watchdog.o +obj-$(CONFIG_EFI_ECPT) += efi_selftest_ecpt.o obj-$(CONFIG_NET) += efi_selftest_snp.o obj-$(CONFIG_EFI_DEVICE_PATH_TO_TEXT) += efi_selftest_devicepath.o diff --git a/lib/efi_selftest/efi_selftest_ecpt.c b/lib/efi_selftest/efi_selftest_ecpt.c new file mode 100644 index 00000000000..e8cc13545db --- /dev/null +++ b/lib/efi_selftest/efi_selftest_ecpt.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_fdt + * + * Copyright (c) 2022 Heinrich Schuchardt + * + * Check the EFI_CONFORMANCE_PROFILE_TABLE + */ + +#include + +static const efi_guid_t guid_ecpt = EFI_CONFORMANCE_PROFILES_TABLE_GUID; +static const efi_guid_t guid_ebbr_2_0 = EFI_CONFORMANCE_PROFILE_EBBR_2_0_GUID; + +/* + * ecpt_find_guid() - find GUID in EFI Conformance Profile Table + * + * @ecpt: EFI Conformance Profile Table + * @guid: GUID to find + * Return: EFI_ST_SUCCESS for success + */ +static int ecpt_find_guid(struct efi_conformance_profiles_table *ecpt, + const efi_guid_t *guid) { + int i; + + for (i = 0; i < ecpt->number_of_profiles; ++i) { + if (!memcmp(&ecpt->conformance_profiles[i], guid, 16)) + return EFI_ST_SUCCESS; + } + efi_st_error("GUID %pU not found\n", guid); + return EFI_ST_FAILURE; +} + +/* + * Execute unit test. + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + struct efi_conformance_profiles_table *ecpt; + int expected_entries = 0; + + ecpt = efi_st_get_config_table(&guid_ecpt); + + if (!ecpt) { + efi_st_error("Missing EFI Conformance Profile Table\n"); + return EFI_ST_FAILURE; + } + + if (ecpt->version != EFI_CONFORMANCE_PROFILES_TABLE_VERSION) { + efi_st_error("Wrong table version\n"); + return EFI_ST_FAILURE; + } + + if (CONFIG_IS_ENABLED(EFI_EBBR_2_0_CONFORMANCE)) { + ++expected_entries; + if (ecpt_find_guid(ecpt, &guid_ebbr_2_0)) + return EFI_ST_FAILURE; + } + + if (ecpt->number_of_profiles != expected_entries) { + efi_st_error("Expected %d entries, found %d\n", + expected_entries, ecpt->number_of_profiles); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + + +EFI_UNIT_TEST(ecpt) = { + .name = "conformance profile table", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, +}; -- cgit v1.3.1 From 793254893954dc96437b5b5541aab84485bf78b1 Mon Sep 17 00:00:00 2001 From: Etienne Carriere Date: Wed, 7 Sep 2022 10:20:13 +0200 Subject: lib: efi_loader: don't delete invalid handles Change efi_delete_handle() to not free EFI handles twice. This change tries to resolved an issue seen since U-Boot v2022.07 in which ExitBootService() attempts to release some EFI handles twice. The issue was seen booting a EFI shell that invokes 'connect -r' and then boots a Linux kernel. Execution of connect command makes EFI subsystem to bind a block device for each root block devices EFI handles. However these EFI device handles are already bound to a driver and we can have 2 registered devices relating to the same EFI handler. On ExitBootService(), the loop removing the devices makes these EFI handles to be released twice which corrupts memory. This patch prevents the memory release operation caused by the issue but but does not resolve the underlying problem. Signed-off-by: Etienne Carriere Add log message. Reviewed-by: Heinrich Schuchardt Reviewed-by: Ilias Apalodimas --- lib/efi_loader/efi_boottime.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4da64b5d296..6f7333638ae 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -619,9 +619,14 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle) */ void efi_delete_handle(efi_handle_t handle) { - if (!handle) + efi_status_t ret; + + ret = efi_remove_all_protocols(handle); + if (ret == EFI_INVALID_PARAMETER) { + log_err("Can't remove invalid handle %p\n", handle); return; - efi_remove_all_protocols(handle); + } + list_del(&handle->link); free(handle); } -- cgit v1.3.1 From 8cf8ad353345cc4a92288b5136e7d714d2bdde4a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 9 Sep 2022 06:57:58 +0000 Subject: efi_driver: don't bind internal block devices UEFI block devices can either mirror U-Boot's internal devices or be provided by an EFI application like iPXE. When ConnectController() is invoked for the EFI_BLOCK_IO_PROTOCOL interface for such an application provided device we create a virtual U-Boot block device of type "efi_blk". Currently we do not call ConnectController() when handles for U-Boot's internal block devices are created. If an EFI application calls ConnectController() for a handle relating to an internal block device, we erroneously create an extra "efi_blk" block device. E.g. the UEFI shell has a command 'connect -r' which calls ConnectController() for all handles with device path protocol. In the Supported() method of our EFI_DRIVER_BINDING_PROTOCOL return EFI_UNSUPPORTED when dealing with an U-Boot internal device. Reported-by: Etienne Carriere Fixes: commit 05ef48a2484b ("efi_driver: EFI block driver") Signed-off-by: Heinrich Schuchardt Reviewed-by: Etienne Carriere Tested-by: Etienne Carriere Reviewed-by: Ilias Apalodimas --- lib/efi_driver/efi_uclass.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib') diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c index b01ce89c84e..74dd0032437 100644 --- a/lib/efi_driver/efi_uclass.c +++ b/lib/efi_driver/efi_uclass.c @@ -71,6 +71,15 @@ static efi_status_t EFIAPI efi_uc_supported( EFI_ENTRY("%p, %p, %ls", this, controller_handle, efi_dp_str(remaining_device_path)); + /* + * U-Boot internal devices install protocols interfaces without calling + * ConnectController(). Hence we should not bind an extra driver. + */ + if (controller_handle->dev) { + ret = EFI_UNSUPPORTED; + goto out; + } + ret = EFI_CALL(systab.boottime->open_protocol( controller_handle, bp->ops->protocol, &interface, this->driver_binding_handle, -- cgit v1.3.1