From 7b9f8ad749260e11c8883fed53ae4dfefc98b2b3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:03 +0200 Subject: efi_loader: move efi_search_obj up in code To avoid a forward declaration move efi_search_obj before all protocol services functions. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 743b84864f..04a7859faa 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -690,6 +690,27 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) return EFI_EXIT(EFI_INVALID_PARAMETER); } +/* + * Find the internal EFI object for a handle. + * + * @handle handle to find + * @return EFI object + */ +static struct efi_object *efi_search_obj(void *handle) +{ + struct list_head *lhandle; + + list_for_each(lhandle, &efi_obj_list) { + struct efi_object *efiobj; + + efiobj = list_entry(lhandle, struct efi_object, link); + if (efiobj->handle == handle) + return efiobj; + } + + return NULL; +} + /* * Install protocol interface. * @@ -1355,26 +1376,6 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, panic("EFI application exited"); } -/* - * Find the internal EFI object for a handle. - * - * @handle handle to find - * @return EFI object - */ -static struct efi_object *efi_search_obj(void *handle) -{ - struct list_head *lhandle; - - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; - efiobj = list_entry(lhandle, struct efi_object, link); - if (efiobj->handle == handle) - return efiobj; - } - - return NULL; -} - /* * Unload an EFI image. * -- cgit v1.2.1 From b3d6090042d4de265c930358aec4d9b96bf3748a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:04 +0200 Subject: efi_loader: implement SetWatchdogTimer The watchdog is initialized with a 5 minute timeout period. It can be reset by SetWatchdogTimer. It is stopped by ExitBoottimeServices. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/Makefile | 2 +- lib/efi_loader/efi_boottime.c | 17 ++------- lib/efi_loader/efi_watchdog.c | 89 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 lib/efi_loader/efi_watchdog.c (limited to 'lib') diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index ddb978f650..83d879b686 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -17,7 +17,7 @@ endif obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o -obj-y += efi_file.o efi_variable.o efi_bootmgr.o +obj-y += efi_file.o efi_variable.o efi_bootmgr.o efi_watchdog.o obj-$(CONFIG_LCD) += efi_gop.o obj-$(CONFIG_DM_VIDEO) += efi_gop.o obj-$(CONFIG_PARTITIONS) += efi_disk.o diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 04a7859faa..c77da8a9c1 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -155,18 +155,6 @@ void efi_signal_event(struct efi_event *event) event->is_queued = false; } -/* - * Write a debug message for an EPI API service that is not implemented yet. - * - * @funcname function that is not yet implemented - * @return EFI_UNSUPPORTED - */ -static efi_status_t efi_unsupported(const char *funcname) -{ - debug("EFI: App called into unimplemented function %s\n", funcname); - return EFI_EXIT(EFI_UNSUPPORTED); -} - /* * Raise the task priority level. * @@ -1451,6 +1439,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle, bootm_disable_interrupts(); /* Give the payload some time to boot */ + efi_set_watchdog(0); WATCHDOG_RESET(); return EFI_EXIT(EFI_SUCCESS); @@ -1494,7 +1483,7 @@ static efi_status_t EFIAPI efi_stall(unsigned long microseconds) /* * Reset the watchdog timer. * - * This function implements the WatchdogTimer service. + * This function implements the SetWatchdogTimer service. * See the Unified Extensible Firmware Interface (UEFI) specification * for details. * @@ -1511,7 +1500,7 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, { EFI_ENTRY("%ld, 0x%"PRIx64", %ld, %p", timeout, watchdog_code, data_size, watchdog_data); - return efi_unsupported(__func__); + return EFI_EXIT(efi_set_watchdog(timeout)); } /* diff --git a/lib/efi_loader/efi_watchdog.c b/lib/efi_loader/efi_watchdog.c new file mode 100644 index 0000000000..35a45dedf8 --- /dev/null +++ b/lib/efi_loader/efi_watchdog.c @@ -0,0 +1,89 @@ +/* + * EFI watchdog + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +/* Conversion factor from seconds to multiples of 100ns */ +#define EFI_SECONDS_TO_100NS 10000000ULL + +static struct efi_event *watchdog_timer_event; + +/* + * Reset the system when the watchdog event is notified. + * + * @event: the watchdog event + * @context: not used + */ +static void EFIAPI efi_watchdog_timer_notify(struct efi_event *event, + void *context) +{ + EFI_ENTRY("%p, %p", event, context); + + printf("\nEFI: Watchdog timeout\n"); + EFI_CALL_VOID(efi_runtime_services.reset_system(EFI_RESET_COLD, + EFI_SUCCESS, 0, NULL)); + + EFI_EXIT(EFI_UNSUPPORTED); +} + +/* + * Reset the watchdog timer. + * + * This function is used by the SetWatchdogTimer service. + * + * @timeout: seconds before reset by watchdog + * @return: status code + */ +efi_status_t efi_set_watchdog(unsigned long timeout) +{ + efi_status_t r; + + if (timeout) + /* Reset watchdog */ + r = efi_set_timer(watchdog_timer_event, EFI_TIMER_RELATIVE, + EFI_SECONDS_TO_100NS * timeout); + else + /* Deactivate watchdog */ + r = efi_set_timer(watchdog_timer_event, EFI_TIMER_STOP, 0); + return r; +} + +/* + * Initialize the EFI watchdog. + * + * This function is called by efi_init_obj_list() + */ +int efi_watchdog_register(void) +{ + efi_status_t r; + + /* + * Create a timer event. + */ + r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + efi_watchdog_timer_notify, NULL, + &watchdog_timer_event); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to register watchdog event\n"); + return r; + } + /* + * The UEFI standard requires that the watchdog timer is set to five + * minutes when invoking an EFI boot option. + * + * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A + * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer + */ + r = efi_set_watchdog(300); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to set watchdog timer\n"); + return r; + } + return 0; +} -- cgit v1.2.1 From 30a0045a54e96e799b0694451a977dba572675fb Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:05 +0200 Subject: efi_selftest: provide test for watchdog timer The test verifies that resetting the watchdog timer ensures that it is not called during the timeout period. Testing that the watchdog timer actually executes a reset would require a test outside the efi_selftest framework. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 5 +- lib/efi_selftest/efi_selftest_watchdog.c | 185 +++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 lib/efi_selftest/efi_selftest_watchdog.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index e446046e02..3e5c9a6d16 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -21,6 +21,8 @@ CFLAGS_efi_selftest_tpl.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_tpl.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_util.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_util.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_watchdog.o := $(CFLAGS_EFI) +CFLAGS_REMOVE_efi_selftest_watchdog.o := $(CFLAGS_NON_EFI) obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ @@ -29,4 +31,5 @@ efi_selftest_events.o \ efi_selftest_exitbootservices.o \ efi_selftest_snp.o \ efi_selftest_tpl.o \ -efi_selftest_util.o +efi_selftest_util.o \ +efi_selftest_watchdog.o diff --git a/lib/efi_selftest/efi_selftest_watchdog.c b/lib/efi_selftest/efi_selftest_watchdog.c new file mode 100644 index 0000000000..f8c5404000 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_watchdog.c @@ -0,0 +1,185 @@ +/* + * efi_selftest_watchdog + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This unit test checks that the watchdog timer will not cause + * a system restart during the timeout period after a timer reset. + * + * Testing that the watchdog timer actually will reset the system + * after a timeout is not possible within the used framework. + */ + +#include + +/* + * This is the communication structure for the notification function. + */ +struct notify_context { + /* Status code returned when resetting watchdog */ + efi_status_t status; + /* Number of invocations of the notification function */ + unsigned int timer_ticks; +}; + +static struct efi_event *event_notify; +static struct efi_event *event_wait; +static struct efi_boot_services *boottime; +static struct notify_context notification_context; + +/* + * Notification function, increments the notfication count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the timeout + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + struct notify_context *notify_context = context; + efi_status_t ret = EFI_SUCCESS; + + if (!notify_context) + return; + + /* Reset watchdog timer to one second */ + ret = boottime->set_watchdog_timer(1, 0, 0, NULL); + if (ret != EFI_SUCCESS) + notify_context->status = ret; + /* Count number of calls */ + notify_context->timer_ticks++; +} + +/* + * Setup unit test. + * + * Create two timer events. + * One with EVT_NOTIFY_SIGNAL, the other with EVT_NOTIFY_WAIT. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + notification_context.status = EFI_SUCCESS; + notification_context.timer_ticks = 0; + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, notify, + (void *)¬ification_context, + &event_notify); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, + TPL_CALLBACK, notify, NULL, &event_wait); + if (ret != EFI_SUCCESS) { + efi_st_error("could not create event\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Close the events created in setup. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + + /* Set the watchdog timer to the five minute default value */ + ret = boottime->set_watchdog_timer(300, 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Setting watchdog timer failed\n"); + return EFI_ST_FAILURE; + } + if (event_notify) { + ret = boottime->close_event(event_notify); + event_notify = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("Could not close event\n"); + return EFI_ST_FAILURE; + } + } + if (event_wait) { + ret = boottime->close_event(event_wait); + event_wait = NULL; + if (ret != EFI_SUCCESS) { + efi_st_error("Could not close event\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Run a 600 ms periodic timer that resets the watchdog to one second + * on every timer tick. + * + * Run a 1350 ms single shot timer and check that the 600ms timer has + * been called 2 times. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + size_t index; + efi_status_t ret; + + /* Set the watchdog timeout to one second */ + ret = boottime->set_watchdog_timer(1, 0, 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Setting watchdog timer failed\n"); + return EFI_ST_FAILURE; + } + /* Set 600 ms timer */ + ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 6000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + /* Set 1350 ms timer */ + ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 13500000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->wait_for_event(1, &event_wait, &index); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not wait for event\n"); + return EFI_ST_FAILURE; + } + if (notification_context.status != EFI_SUCCESS) { + efi_st_error("Setting watchdog timer failed\n"); + return EFI_ST_FAILURE; + } + if (notification_context.timer_ticks != 2) { + efi_st_error("The timer was called %u times, expected 2.\n", + notification_context.timer_ticks); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(watchdog) = { + .name = "watchdog timer", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; -- cgit v1.2.1 From f58c5ecb87e0ab170dfa92cd0c1052dd18fffc2c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:06 +0200 Subject: efi_loader: new function utf8_to_utf16 Provide a conversion function from utf8 to utf16. Add missing #include in include/charset.h. Remove superfluous #include in lib/charset.c. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/charset.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/charset.c b/lib/charset.c index ff76e88c77..8cd17ea1cb 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -6,7 +6,6 @@ * SPDX-License-Identifier: GPL-2.0+ */ -#include #include #include @@ -99,3 +98,59 @@ uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size) return dest; } + +uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size) +{ + while (size--) { + int extension_bytes; + uint32_t code; + + extension_bytes = 0; + if (*src <= 0x7f) { + code = *src++; + /* Exit on zero byte */ + if (!code) + size = 0; + } else if (*src <= 0xbf) { + /* Illegal code */ + code = '?'; + } else if (*src <= 0xdf) { + code = *src++ & 0x1f; + extension_bytes = 1; + } else if (*src <= 0xef) { + code = *src++ & 0x0f; + extension_bytes = 2; + } else if (*src <= 0xf7) { + code = *src++ & 0x07; + extension_bytes = 3; + } else { + /* Illegal code */ + code = '?'; + } + + for (; extension_bytes && size; --size, --extension_bytes) { + if ((*src & 0xc0) == 0x80) { + code <<= 6; + code |= *src++ & 0x3f; + } else { + /* Illegal code */ + code = '?'; + ++src; + --size; + break; + } + } + + if (code < 0x10000) { + *dest++ = code; + } else { + /* + * Simplified expression for + * (((code - 0x10000) >> 10) & 0x3ff) | 0xd800 + */ + *dest++ = (code >> 10) + 0xd7c0; + *dest++ = (code & 0x3ff) | 0xdc00; + } + } + return dest; +} -- cgit v1.2.1 From fd4a1c491134c509b25507abfe5f86d58a3b5f0b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:10 +0200 Subject: efi_selftest: reformat code Remove superfluous spaces. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 45d8d3d384..c2c339a7be 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -25,8 +25,8 @@ static u16 reset_message[] = L"Selftest completed"; */ void efi_st_exit_boot_services(void) { - unsigned long map_size = 0; - unsigned long map_key; + unsigned long map_size = 0; + unsigned long map_key; unsigned long desc_size; u32 desc_version; efi_status_t ret; -- cgit v1.2.1 From 9a52a0f77da6bbc4a1b13bff1aceb376057af9b3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:11 +0200 Subject: efi_selftest: efi_st_memcmp should return 0 If the compared memory areas match the return value should be 0. We should not use the unrelated constant EFI_ST_SUCCESS. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c index 5cffe383d8..5f81f251c4 100644 --- a/lib/efi_selftest/efi_selftest_util.c +++ b/lib/efi_selftest/efi_selftest_util.c @@ -21,5 +21,5 @@ int efi_st_memcmp(const void *buf1, const void *buf2, size_t length) ++pos1; ++pos2; } - return EFI_ST_SUCCESS; + return 0; } -- cgit v1.2.1 From 1f66a12e237f7ce9dc9b997e7ce0b2a33893ce12 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:12 +0200 Subject: efi_selftest: deduplicate code Move duplicate code to the new function efi_st_do_tests. Suggested-by: Alexander Graf Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 71 ++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index c2c339a7be..73f074d9e1 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -9,6 +9,13 @@ #include #include +/* + * Constants for test step bitmap + */ +#define EFI_ST_SETUP 1 +#define EFI_ST_EXECUTE 2 +#define EFI_ST_TEARDOWN 4 + static const struct efi_system_table *systable; static const struct efi_boot_services *boottime; static const struct efi_runtime_services *runtime; @@ -133,6 +140,31 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures) return ret; } +/* + * Execute test steps of one phase. + * + * @phase test phase + * @steps steps to execute + * failures returns EFI_ST_SUCCESS if all test steps succeeded + */ +void efi_st_do_tests(unsigned int phase, unsigned int steps, + unsigned int *failures) +{ + struct efi_unit_test *test; + + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + if (test->phase != phase) + continue; + if (steps & EFI_ST_SETUP) + setup(test, failures); + if (steps & EFI_ST_EXECUTE) + execute(test, failures); + if (steps & EFI_ST_TEARDOWN) + teardown(test, failures); + } +} + /* * Execute selftest of the EFI API * @@ -153,7 +185,6 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures) efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, struct efi_system_table *systab) { - struct efi_unit_test *test; unsigned int failures = 0; systable = systab; @@ -169,41 +200,23 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, ll_entry_count(struct efi_unit_test, efi_unit_test)); /* Execute boottime tests */ - for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); - test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { - if (test->phase == EFI_EXECUTE_BEFORE_BOOTTIME_EXIT) { - setup(test, &failures); - execute(test, &failures); - teardown(test, &failures); - } - } + efi_st_do_tests(EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, + &failures); /* Execute mixed tests */ - for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); - test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { - if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT) - setup(test, &failures); - } + efi_st_do_tests(EFI_SETUP_BEFORE_BOOTTIME_EXIT, + EFI_ST_SETUP, &failures); efi_st_exit_boot_services(); - for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); - test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { - if (test->phase == EFI_SETUP_BEFORE_BOOTTIME_EXIT) { - execute(test, &failures); - teardown(test, &failures); - } - } + efi_st_do_tests(EFI_SETUP_BEFORE_BOOTTIME_EXIT, + EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); /* Execute runtime tests */ - for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); - test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { - if (test->phase == EFI_SETUP_AFTER_BOOTTIME_EXIT) { - setup(test, &failures); - execute(test, &failures); - teardown(test, &failures); - } - } + efi_st_do_tests(EFI_SETUP_AFTER_BOOTTIME_EXIT, + EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, + &failures); /* Give feedback */ efi_st_printf("\nSummary: %u failures\n\n", failures); -- cgit v1.2.1 From d78e40d651972ef061c960e4b7da7843383c2ec9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:13 +0200 Subject: efi_selftest: allow to select a single test for execution Environment variable efi_selftest is passed as load options to the selftest application. It is used to select a single test to be executed. The load options are an UTF8 string. Yet I decided to keep the name propertiy of the tests as char[] to reduce code size. Special value 'list' displays a list of all available tests. Tests get an on_request property. If this property is set the tests are only executed if explicitly requested. The invocation of efi_selftest is changed to reflect that bootefi selftest with efi_selftest = 'list' will call the Exit bootservice. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 88 ++++++++++++++++++++++++++++++--- lib/efi_selftest/efi_selftest_console.c | 10 ++++ lib/efi_selftest/efi_selftest_util.c | 9 ++++ 3 files changed, 99 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 73f074d9e1..b6bc4dd5c0 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -140,20 +140,59 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures) return ret; } +/* + * Check that a test exists. + * + * @testname: name of the test + * @return: test + */ +static struct efi_unit_test *find_test(const u16 *testname) +{ + struct efi_unit_test *test; + + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + if (!efi_st_strcmp_16_8(testname, test->name)) + return test; + } + efi_st_printf("\nTest '%ps' not found\n", testname); + return NULL; +} + +/* + * List all available tests. + */ +static void list_all_tests(void) +{ + struct efi_unit_test *test; + + /* List all tests */ + efi_st_printf("\nAvailable tests:\n"); + for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); + test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + efi_st_printf("'%s'%s\n", test->name, + test->on_request ? " - on request" : ""); + } +} + /* * Execute test steps of one phase. * + * @testname name of a single selected test or NULL * @phase test phase * @steps steps to execute * failures returns EFI_ST_SUCCESS if all test steps succeeded */ -void efi_st_do_tests(unsigned int phase, unsigned int steps, - unsigned int *failures) +void efi_st_do_tests(const u16 *testname, unsigned int phase, + unsigned int steps, unsigned int *failures) { struct efi_unit_test *test; for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + if (testname ? + efi_st_strcmp_16_8(testname, test->name) : test->on_request) + continue; if (test->phase != phase) continue; if (steps & EFI_ST_SETUP) @@ -186,6 +225,9 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, struct efi_system_table *systab) { unsigned int failures = 0; + const u16 *testname = NULL; + struct efi_loaded_image *loaded_image; + efi_status_t ret; systable = systab; boottime = systable->boottime; @@ -194,27 +236,57 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, con_out = systable->con_out; con_in = systable->con_in; + ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, + (void **)&loaded_image); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot open loaded image protocol"); + return ret; + } + + if (loaded_image->load_options) + testname = (u16 *)loaded_image->load_options; + + if (testname) { + if (!efi_st_strcmp_16_8(testname, "list") || + !find_test(testname)) { + list_all_tests(); + /* + * TODO: + * Once the Exit boottime service is correctly + * implemented we should call + * boottime->exit(image_handle, EFI_SUCCESS, 0, NULL); + * here, cf. + * https://lists.denx.de/pipermail/u-boot/2017-October/308720.html + */ + return EFI_SUCCESS; + } + } + efi_st_printf("\nTesting EFI API implementation\n"); - efi_st_printf("\nNumber of tests to execute: %u\n", - ll_entry_count(struct efi_unit_test, efi_unit_test)); + if (testname) + efi_st_printf("\nSelected test: '%ps'\n", testname); + else + efi_st_printf("\nNumber of tests to execute: %u\n", + ll_entry_count(struct efi_unit_test, + efi_unit_test)); /* Execute boottime tests */ - efi_st_do_tests(EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); /* Execute mixed tests */ - efi_st_do_tests(EFI_SETUP_BEFORE_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, EFI_ST_SETUP, &failures); efi_st_exit_boot_services(); - efi_st_do_tests(EFI_SETUP_BEFORE_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_SETUP_BEFORE_BOOTTIME_EXIT, EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); /* Execute runtime tests */ - efi_st_do_tests(EFI_SETUP_AFTER_BOOTTIME_EXIT, + efi_st_do_tests(testname, EFI_SETUP_AFTER_BOOTTIME_EXIT, EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, &failures); diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index 840e2290c6..6a7fd20da5 100644 --- a/lib/efi_selftest/efi_selftest_console.c +++ b/lib/efi_selftest/efi_selftest_console.c @@ -142,6 +142,7 @@ void efi_st_printf(const char *fmt, ...) const char *c; u16 *pos = buf; const char *s; + const u16 *u; va_start(args, fmt); @@ -179,9 +180,18 @@ void efi_st_printf(const char *fmt, ...) case 'p': ++c; switch (*c) { + /* MAC address */ case 'm': mac(va_arg(args, void*), &pos); break; + + /* u16 string */ + case 's': + u = va_arg(args, u16*); + /* Ensure string fits into buffer */ + for (; *u && pos < buf + 120; ++u) + *pos++ = *u; + break; default: --c; pointer(va_arg(args, void*), &pos); diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c index 5f81f251c4..1b17bf4d4b 100644 --- a/lib/efi_selftest/efi_selftest_util.c +++ b/lib/efi_selftest/efi_selftest_util.c @@ -23,3 +23,12 @@ int efi_st_memcmp(const void *buf1, const void *buf2, size_t length) } return 0; } + +int efi_st_strcmp_16_8(const u16 *buf1, const char *buf2) +{ + for (; *buf1 || *buf2; ++buf1, ++buf2) { + if (*buf1 != *buf2) + return *buf1 - *buf2; + } + return 0; +} -- cgit v1.2.1 From 7bbae6f2938382567fd86521ad15412c27e882f7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:16 +0200 Subject: efi_selftest: test reboot by watchdog A test is added that verifies that the watchdog timer actually causes a reboot upon timeout. The test is only executed on request using setenv efi_selftest watchdog reboot bootefi selftest Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_watchdog.c | 68 ++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest_watchdog.c b/lib/efi_selftest/efi_selftest_watchdog.c index f8c5404000..e4af38407f 100644 --- a/lib/efi_selftest/efi_selftest_watchdog.c +++ b/lib/efi_selftest/efi_selftest_watchdog.c @@ -5,11 +5,16 @@ * * SPDX-License-Identifier: GPL-2.0+ * - * This unit test checks that the watchdog timer will not cause - * a system restart during the timeout period after a timer reset. + * The 'watchdog timer' unit test checks that the watchdog timer + * will not cause a system restart during the timeout period after + * a timer reset. * - * Testing that the watchdog timer actually will reset the system - * after a timeout is not possible within the used framework. + * The 'watchdog reboot' unit test checks that the watchdog timer + * actually reboots the system after a timeout. The test is only + * executed on explicit request. Use the following commands: + * + * setenv efi_selftest watchdog reboot + * bootefi selftest */ #include @@ -28,6 +33,7 @@ static struct efi_event *event_notify; static struct efi_event *event_wait; static struct efi_boot_services *boottime; static struct notify_context notification_context; +static bool watchdog_reset; /* * Notification function, increments the notfication count if parameter @@ -88,6 +94,34 @@ static int setup(const efi_handle_t handle, return EFI_ST_SUCCESS; } +/* + * Execute the test resetting the watchdog in a timely manner. No reboot occurs. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup_timer(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + watchdog_reset = true; + return setup(handle, systable); +} + +/* + * Execute the test without resetting the watchdog. A system reboot occurs. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup_reboot(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + watchdog_reset = false; + return setup(handle, systable); +} + /* * Tear down unit test. * @@ -146,11 +180,14 @@ static int execute(void) efi_st_error("Setting watchdog timer failed\n"); return EFI_ST_FAILURE; } - /* Set 600 ms timer */ - ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 6000000); - if (ret != EFI_SUCCESS) { - efi_st_error("Could not set timer\n"); - return EFI_ST_FAILURE; + if (watchdog_reset) { + /* Set 600 ms timer */ + ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, + 6000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Could not set timer\n"); + return EFI_ST_FAILURE; + } } /* Set 1350 ms timer */ ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 13500000); @@ -176,10 +213,19 @@ static int execute(void) return EFI_ST_SUCCESS; } -EFI_UNIT_TEST(watchdog) = { +EFI_UNIT_TEST(watchdog1) = { .name = "watchdog timer", .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, - .setup = setup, + .setup = setup_timer, + .execute = execute, + .teardown = teardown, +}; + +EFI_UNIT_TEST(watchdog2) = { + .name = "watchdog reboot", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup_reboot, .execute = execute, .teardown = teardown, + .on_request = true, }; -- cgit v1.2.1 From 7406f824b8833447b15ef84b278b0c92bbe02922 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:19 +0200 Subject: efi_selftest: provide test for EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL The following services are tested: OutputString, TestString, SetAttribute. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 3 ++ lib/efi_selftest/efi_selftest_textoutput.c | 53 ++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_textoutput.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 3e5c9a6d16..88b998bd4c 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -17,6 +17,8 @@ CFLAGS_efi_selftest_exitbootservices.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_exitbootservices.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_snp.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_snp.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_textoutput.o := $(CFLAGS_EFI) +CFLAGS_REVMOE_efi_selftest_textoutput.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_tpl.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_tpl.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_util.o := $(CFLAGS_EFI) @@ -30,6 +32,7 @@ efi_selftest_console.o \ efi_selftest_events.o \ efi_selftest_exitbootservices.o \ efi_selftest_snp.o \ +efi_selftest_textoutput.o \ efi_selftest_tpl.o \ efi_selftest_util.o \ efi_selftest_watchdog.o diff --git a/lib/efi_selftest/efi_selftest_textoutput.c b/lib/efi_selftest/efi_selftest_textoutput.c new file mode 100644 index 0000000000..6e8c90cc8b --- /dev/null +++ b/lib/efi_selftest/efi_selftest_textoutput.c @@ -0,0 +1,53 @@ +/* + * efi_selftest_textoutput + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Test the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. + * + * The following services are tested: + * OutputString, TestString, SetAttribute. + */ + +#include + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + size_t foreground; + size_t background; + size_t attrib; + efi_status_t ret; + + /* SetAttribute */ + efi_st_printf("\nColor palette\n"); + for (foreground = 0; foreground < 0x10; ++foreground) { + for (background = 0; background < 0x80; background += 0x10) { + attrib = foreground | background; + con_out->set_attribute(con_out, attrib); + efi_st_printf("%p", (void *)attrib); + } + con_out->set_attribute(con_out, 0); + efi_st_printf("\n"); + } + /* TestString */ + ret = con_out->test_string(con_out, + L" !\"#$%&'()*+,-./0-9:;<=>?@A-Z[\\]^_`a-z{|}~\n"); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("TestString failed for ANSI characters\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(textoutput) = { + .name = "text output", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, +}; -- cgit v1.2.1 From 32fc2ac3810d87fe76b1e5671936e2404536e3ef Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 18 Oct 2017 18:13:20 +0200 Subject: efi_loader: set parent handle in efi_load_image The parent_handle of the loaded image must be set. Set the system table. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c77da8a9c1..b1050e5fb4 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1282,6 +1282,8 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, return EFI_EXIT(EFI_UNSUPPORTED); } + info->system_table = &systab; + info->parent_handle = parent_image; *image_handle = info; return EFI_EXIT(EFI_SUCCESS); -- cgit v1.2.1 From 9f0770ff9c04c43f71bba076203af61ac62e8f3c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:42 +0100 Subject: efi_loader: capitalize EFI_LOCATE_SEARCH_TYPE values Constants should be capitalized. So rename the values of enum efi_locate_search_type. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b1050e5fb4..1f0f6c3494 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -934,11 +934,11 @@ static int efi_search(enum efi_locate_search_type search_type, int i; switch (search_type) { - case all_handles: + case ALL_HANDLES: return 0; - case by_register_notify: + case BY_REGISTER_NOTIFY: return -1; - case by_protocol: + case BY_PROTOCOL: for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { const efi_guid_t *guid = efiobj->protocols[i].guid; if (guid && !guidcmp(guid, protocol)) -- cgit v1.2.1 From 927ca890b09fd7dd5fdf2214adcb10565f3573c9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:43 +0100 Subject: efi_selftest: test protocol management This unit test checks the following protocol services: InstallProtocolInterface, UninstallProtocolInterface, InstallMultipleProtocolsInterfaces, UninstallMultipleProtocolsInterfaces, HandleProtocol, ProtocolsPerHandle, LocateHandle, LocateHandleBuffer. As UninstallProtocolInterface and UninstallMultipleProtocolsInterfaces are not completely implemented a TODO message will shown for their failure. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 3 + lib/efi_selftest/efi_selftest_manageprotocols.c | 354 ++++++++++++++++++++++++ 2 files changed, 357 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_manageprotocols.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 88b998bd4c..acd184db4b 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -15,6 +15,8 @@ CFLAGS_efi_selftest_events.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_events.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_exitbootservices.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_exitbootservices.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_manageprotocols.o := $(CFLAGS_EFI) +CFLAGS_REMOVE_efi_selftest_manageprotocols.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_snp.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_snp.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_textoutput.o := $(CFLAGS_EFI) @@ -31,6 +33,7 @@ efi_selftest.o \ efi_selftest_console.o \ efi_selftest_events.o \ efi_selftest_exitbootservices.o \ +efi_selftest_manageprotocols.o \ efi_selftest_snp.o \ efi_selftest_textoutput.o \ efi_selftest_tpl.o \ diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c new file mode 100644 index 0000000000..e978dd7f2f --- /dev/null +++ b/lib/efi_selftest/efi_selftest_manageprotocols.c @@ -0,0 +1,354 @@ +/* + * efi_selftest_manageprotocols + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This unit test checks the following protocol services: + * InstallProtocolInterface, UninstallProtocolInterface, + * InstallMultipleProtocolsInterfaces, UninstallMultipleProtocolsInterfaces, + * HandleProtocol, ProtocolsPerHandle, + * LocateHandle, LocateHandleBuffer. + */ + +#include + +/* + * The test currently does not actually call the interface function. + * So this is just a dummy structure. + */ +struct interface { + void (EFIAPI * inc)(void); +}; + +static struct efi_boot_services *boottime; +static efi_guid_t guid1 = + EFI_GUID(0x2e7ca819, 0x21d3, 0x0a3a, + 0xf7, 0x91, 0x82, 0x1f, 0x7a, 0x83, 0x67, 0xaf); +static efi_guid_t guid2 = + EFI_GUID(0xf909f2bb, 0x90a8, 0x0d77, + 0x94, 0x0c, 0x3e, 0xa8, 0xea, 0x38, 0xd6, 0x6f); +static efi_guid_t guid3 = + EFI_GUID(0x06d641a3, 0xf4e7, 0xe0c9, + 0xe7, 0x8d, 0x41, 0x2d, 0x72, 0xa6, 0xb1, 0x24); +static efi_handle_t handle1; +static efi_handle_t handle2; +static struct interface interface1; +static struct interface interface2; +static struct interface interface3; +static struct interface interface4; + +/* + * Find a handle in an array. + * + * @handle: handle to find + * @count: number of entries in the array + * @buffer: array to search + */ +efi_status_t find_in_buffer(efi_handle_t handle, size_t count, + efi_handle_t *buffer) +{ + size_t i; + + for (i = 0; i < count; ++i) { + if (buffer[i] == handle) + return EFI_SUCCESS; + } + return EFI_NOT_FOUND; +} + +/* + * Setup unit test. + * + * Create two handles and install two out of three protocol interfaces on each + * of them: + * + * handle1 + * guid1 interface1 + * guid3 interface3 + * handle2 + * guid1 interface4 + * guid2 interface2 + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + efi_handle_t handle; + + boottime = systable->boottime; + + ret = boottime->install_protocol_interface(&handle1, &guid3, + EFI_NATIVE_INTERFACE, + &interface3); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + if (!handle1) { + efi_st_error("InstallProtocolInterface failed to create handle\n"); + return EFI_ST_FAILURE; + } + handle = handle1; + ret = boottime->install_protocol_interface(&handle1, &guid1, + EFI_NATIVE_INTERFACE, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + if (handle != handle1) { + efi_st_error("InstallProtocolInterface failed to use handle\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_multiple_protocol_interfaces(&handle2, + &guid1, &interface4, &guid2, &interface2, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallMultipleProtocolInterfaces failed\n"); + return EFI_ST_FAILURE; + } + if (!handle2 || handle1 == handle2) { + efi_st_error("InstallMultipleProtocolInterfaces failed to create handle\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + */ +static int execute(void) +{ + struct interface *interface; + efi_status_t ret; + efi_handle_t *buffer; + size_t buffer_size; + unsigned long int count = 0; + efi_guid_t **prot_buffer; + unsigned long int prot_count; + + /* + * Test HandleProtocol + */ + ret = boottime->handle_protocol(handle1, &guid3, (void **)&interface); + if (ret != EFI_SUCCESS) { + efi_st_error("HandleProtocol failed to retrieve interface\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface3) { + efi_st_error("HandleProtocol returned wrong interface\n"); + return EFI_ST_FAILURE; + } + ret = boottime->handle_protocol(handle1, &guid2, (void **)&interface); + if (ret == EFI_SUCCESS) { + efi_st_error("HandleProtocol returned not installed interface\n"); + return EFI_ST_FAILURE; + } + + /* + * Test LocateHandleBuffer with AllHandles + */ + ret = boottime->locate_handle_buffer(ALL_HANDLES, NULL, NULL, + &count, &buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer with AllHandles failed\n"); + return EFI_ST_FAILURE; + } + buffer_size = count; + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle2, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + + /* + * Test error handling in UninstallMultipleProtocols + * + * Try to uninstall more protocols than there are installed. + */ + ret = boottime->uninstall_multiple_protocol_interfaces( + handle2, + &guid1, &interface4, + &guid2, &interface2, + &guid3, &interface3, + NULL); + if (ret == EFI_SUCCESS) { + efi_st_todo("UninstallMultipleProtocolInterfaces did not catch error\n"); + return EFI_ST_FAILURE; + } + + /* + * Test LocateHandleBuffer with ByProtocol + */ + count = buffer_size; + ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, + &count, &buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + if (count != 2) { + efi_st_error("LocateHandleBuffer failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle2, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + + /* + * Test LocateHandle with ByProtocol + */ + count = buffer_size * sizeof(efi_handle_t); + ret = boottime->locate_handle(BY_PROTOCOL, &guid1, NULL, + &count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandle with ByProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (count / sizeof(efi_handle_t) != 2) { + efi_st_error("LocateHandle failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + buffer_size = count; + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandle failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + ret = find_in_buffer(handle2, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandle failed to locate new handles\n"); + return EFI_ST_FAILURE; + } + boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + + /* + * Test LocateProtocol + */ + ret = boottime->locate_protocol(&guid1, NULL, (void **)&interface); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateProtocol failed\n"); + return EFI_ST_FAILURE; + } + if (interface != &interface1 && interface != &interface4) { + efi_st_error("LocateProtocol failed to locate protocol\n"); + return EFI_ST_FAILURE; + } + + /* + * Test UninstallMultipleProtocols + */ + ret = boottime->uninstall_multiple_protocol_interfaces( + handle2, + &guid1, &interface4, + &guid2, &interface2, + NULL); + if (ret != EFI_SUCCESS) { + efi_st_todo("UninstallMultipleProtocolInterfaces failed\n"); + /* This test is known to fail due to missing implementation */ + } + /* + * Check that the protocols are really uninstalled. + */ + count = buffer_size; + ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, + &count, &buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateHandleBuffer failed\n"); + return EFI_ST_FAILURE; + } + if (count != 1) { + efi_st_todo("UninstallMultipleProtocolInterfaces failed to uninstall protocols\n"); + /* This test is known to fail due to missing implementation */ + } + ret = find_in_buffer(handle1, count, buffer); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate new handle\n"); + return EFI_ST_FAILURE; + } + boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0); + + /* + * Test ProtocolsPerHandle + */ + ret = boottime->protocols_per_handle(handle1, + &prot_buffer, &prot_count); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + if (prot_count != 2) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + if (efi_st_memcmp(prot_buffer[0], &guid1, 16) && + efi_st_memcmp(prot_buffer[1], &guid1, 16)) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + if (efi_st_memcmp(prot_buffer[0], &guid3, 16) && + efi_st_memcmp(prot_buffer[1], &guid3, 16)) { + efi_st_error("Failed to get protocols per handle\n"); + return EFI_ST_FAILURE; + } + + /* + * Uninstall remaining protocols + */ + ret = boottime->uninstall_protocol_interface(handle1, &guid1, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_todo("UninstallProtocolInterface failed\n"); + /* This test is known to fail due to missing implementation */ + } + ret = boottime->handle_protocol(handle1, &guid1, (void **)&interface); + if (ret == EFI_SUCCESS) { + efi_st_todo("UninstallProtocolInterface failed\n"); + /* This test is known to fail due to missing implementation */ + } + ret = boottime->uninstall_protocol_interface(handle1, &guid3, + &interface1); + if (ret != EFI_SUCCESS) { + efi_st_todo("UninstallProtocolInterface failed\n"); + /* This test is known to fail due to missing implementation */ + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(protserv) = { + .name = "manage protocols", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; -- cgit v1.2.1 From 1760ef574ace23086c94bb22041325daef8f8226 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:44 +0100 Subject: efi_loader: eliminate efi_install_protocol_interface_ext As we now have EFI_CALL there is no need for separate functions efi_install_protocol_interface_ext and efi_install_protocol_interface. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 52 +++++++++++++------------------------------ 1 file changed, 15 insertions(+), 37 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1f0f6c3494..518cf5a160 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -702,9 +702,9 @@ static struct efi_object *efi_search_obj(void *handle) /* * Install protocol interface. * - * This is the function for internal calls. For the API implementation of the - * InstallProtocolInterface service see function - * efi_install_protocol_interface_ext. + * This function implements the InstallProtocolInterface service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. * * @handle handle on which the protocol shall be installed * @protocol GUID of the protocol to be installed @@ -713,14 +713,17 @@ static struct efi_object *efi_search_obj(void *handle) * @protocol_interface interface of the protocol implementation * @return status code */ -static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, - const efi_guid_t *protocol, int protocol_interface_type, - void *protocol_interface) +static efi_status_t EFIAPI efi_install_protocol_interface( + void **handle, const efi_guid_t *protocol, + int protocol_interface_type, void *protocol_interface) { struct list_head *lhandle; int i; efi_status_t r; + EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type, + protocol_interface); + if (!handle || !protocol || protocol_interface_type != EFI_NATIVE_INTERFACE) { r = EFI_INVALID_PARAMETER; @@ -768,33 +771,7 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, } r = EFI_INVALID_PARAMETER; out: - return r; -} - -/* - * Install protocol interface. - * - * This function implements the InstallProtocolInterface service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. - * - * @handle handle on which the protocol shall be installed - * @protocol GUID of the protocol to be installed - * @protocol_interface_type type of the interface to be installed, - * always EFI_NATIVE_INTERFACE - * @protocol_interface interface of the protocol implementation - * @return status code - */ -static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, - const efi_guid_t *protocol, int protocol_interface_type, - void *protocol_interface) -{ - EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type, - protocol_interface); - - return EFI_EXIT(efi_install_protocol_interface(handle, protocol, - protocol_interface_type, - protocol_interface)); + return EFI_EXIT(r); } /* @@ -1787,9 +1764,10 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( if (!protocol) break; protocol_interface = va_arg(argptr, void*); - r = efi_install_protocol_interface(handle, protocol, - EFI_NATIVE_INTERFACE, - protocol_interface); + r = EFI_CALL(efi_install_protocol_interface( + handle, protocol, + EFI_NATIVE_INTERFACE, + protocol_interface)); if (r != EFI_SUCCESS) break; i++; @@ -2012,7 +1990,7 @@ static const struct efi_boot_services efi_boot_services = { .signal_event = efi_signal_event_ext, .close_event = efi_close_event, .check_event = efi_check_event, - .install_protocol_interface = efi_install_protocol_interface_ext, + .install_protocol_interface = efi_install_protocol_interface, .reinstall_protocol_interface = efi_reinstall_protocol_interface, .uninstall_protocol_interface = efi_uninstall_protocol_interface_ext, .handle_protocol = efi_handle_protocol, -- cgit v1.2.1 From cd534083cd230e6a38ac575b62a3fb3b93521e9a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:45 +0100 Subject: efi_loader: eliminate efi_uninstall_protocol_interface_ext As we now have EFI_CALL there is no need for separate functions efi_uninstall_protocol_interface_ext and efi_uninstall_protocol_interface. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 42 ++++++++++++------------------------------ 1 file changed, 12 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 518cf5a160..0290d213f2 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -800,22 +800,25 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, /* * Uninstall protocol interface. * - * This is the function for internal calls. For the API implementation of the - * UninstallProtocolInterface service see function - * efi_uninstall_protocol_interface_ext. + * This function implements the UninstallProtocolInterface service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. * * @handle handle from which the protocol shall be removed * @protocol GUID of the protocol to be removed * @protocol_interface interface to be removed * @return status code */ -static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, - const efi_guid_t *protocol, void *protocol_interface) +static efi_status_t EFIAPI efi_uninstall_protocol_interface( + void *handle, const efi_guid_t *protocol, + void *protocol_interface) { struct list_head *lhandle; int i; efi_status_t r = EFI_NOT_FOUND; + EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); + if (!handle || !protocol) { r = EFI_INVALID_PARAMETER; goto out; @@ -847,28 +850,7 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, } out: - return r; -} - -/* - * Uninstall protocol interface. - * - * This function implements the UninstallProtocolInterface service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. - * - * @handle handle from which the protocol shall be removed - * @protocol GUID of the protocol to be removed - * @protocol_interface interface to be removed - * @return status code - */ -static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, - const efi_guid_t *protocol, void *protocol_interface) -{ - EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); - - return EFI_EXIT(efi_uninstall_protocol_interface(handle, protocol, - protocol_interface)); + return EFI_EXIT(r); } /* @@ -1781,8 +1763,8 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( for (; i; --i) { protocol = va_arg(argptr, efi_guid_t*); protocol_interface = va_arg(argptr, void*); - efi_uninstall_protocol_interface(handle, protocol, - protocol_interface); + EFI_CALL(efi_uninstall_protocol_interface(handle, protocol, + protocol_interface)); } va_end(argptr); @@ -1992,7 +1974,7 @@ static const struct efi_boot_services efi_boot_services = { .check_event = efi_check_event, .install_protocol_interface = efi_install_protocol_interface, .reinstall_protocol_interface = efi_reinstall_protocol_interface, - .uninstall_protocol_interface = efi_uninstall_protocol_interface_ext, + .uninstall_protocol_interface = efi_uninstall_protocol_interface, .handle_protocol = efi_handle_protocol, .reserved = NULL, .register_protocol_notify = efi_register_protocol_notify, -- cgit v1.2.1 From 152cade32643fdbdd73614db4cfb159876b58262 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:47 +0100 Subject: efi_loader: replace UINTN by efi_uintn_t UINTN is used in the UEFI specification for unsigned integers matching the bitness of the CPU. Types in U-Boot should be lower case. The patch replaces it by efi_uintn_t. Suggested-by: Simon Glass Suggested-by: Rob Clark Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 12 ++++++------ lib/efi_selftest/efi_selftest_tpl.c | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0290d213f2..9523267156 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -21,7 +21,7 @@ DECLARE_GLOBAL_DATA_PTR; /* Task priority level */ -static UINTN efi_tpl = TPL_APPLICATION; +static efi_uintn_t efi_tpl = TPL_APPLICATION; /* This list contains all the EFI objects our payload has access to */ LIST_HEAD(efi_obj_list); @@ -165,9 +165,9 @@ void efi_signal_event(struct efi_event *event) * @new_tpl new value of the task priority level * @return old value of the task priority level */ -static unsigned long EFIAPI efi_raise_tpl(UINTN new_tpl) +static unsigned long EFIAPI efi_raise_tpl(efi_uintn_t new_tpl) { - UINTN old_tpl = efi_tpl; + efi_uintn_t old_tpl = efi_tpl; EFI_ENTRY("0x%zx", new_tpl); @@ -190,7 +190,7 @@ static unsigned long EFIAPI efi_raise_tpl(UINTN new_tpl) * * @old_tpl value of the task priority level to be restored */ -static void EFIAPI efi_restore_tpl(UINTN old_tpl) +static void EFIAPI efi_restore_tpl(efi_uintn_t old_tpl) { EFI_ENTRY("0x%zx", old_tpl); @@ -359,7 +359,7 @@ static struct efi_event efi_events[16]; * @event created event * @return status code */ -efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, +efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), @@ -409,7 +409,7 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, * @return status code */ static efi_status_t EFIAPI efi_create_event_ext( - uint32_t type, UINTN notify_tpl, + uint32_t type, efi_uintn_t notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, void *context), diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c index ddb67ed268..15d62903c0 100644 --- a/lib/efi_selftest/efi_selftest_tpl.c +++ b/lib/efi_selftest/efi_selftest_tpl.c @@ -113,7 +113,7 @@ static int execute(void) { size_t index; efi_status_t ret; - UINTN old_tpl; + efi_uintn_t old_tpl; /* Set 10 ms timer */ notification_count = 0; -- cgit v1.2.1 From f5a2a93892ff8a8f066bc9f84eb9f0cf35ba0c67 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:48 +0100 Subject: efi_loader: consistently use efi_uintn_t in boot services Consistenly use efi_uintn_t wherever the UEFI spec uses UINTN in boot services interfaces. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 38 ++++++++++++------------- lib/efi_loader/efi_memory.c | 20 ++++++------- lib/efi_selftest/efi_selftest.c | 6 ++-- lib/efi_selftest/efi_selftest_events.c | 2 +- lib/efi_selftest/efi_selftest_manageprotocols.c | 4 +-- lib/efi_selftest/efi_selftest_snp.c | 2 +- lib/efi_selftest/efi_selftest_tpl.c | 2 +- 7 files changed, 37 insertions(+), 37 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9523267156..5bf26114a1 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -217,12 +217,12 @@ static void EFIAPI efi_restore_tpl(efi_uintn_t old_tpl) * @return status code */ static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, - unsigned long pages, + efi_uintn_t pages, uint64_t *memory) { efi_status_t r; - EFI_ENTRY("%d, %d, 0x%lx, %p", type, memory_type, pages, memory); + EFI_ENTRY("%d, %d, 0x%zx, %p", type, memory_type, pages, memory); r = efi_allocate_pages(type, memory_type, pages, memory); return EFI_EXIT(r); } @@ -239,11 +239,11 @@ static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, * @return status code */ static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, - unsigned long pages) + efi_uintn_t pages) { efi_status_t r; - EFI_ENTRY("%"PRIx64", 0x%lx", memory, pages); + EFI_ENTRY("%"PRIx64", 0x%zx", memory, pages); r = efi_free_pages(memory, pages); return EFI_EXIT(r); } @@ -264,10 +264,10 @@ static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, * @return status code */ static efi_status_t EFIAPI efi_get_memory_map_ext( - unsigned long *memory_map_size, + efi_uintn_t *memory_map_size, struct efi_mem_desc *memory_map, - unsigned long *map_key, - unsigned long *descriptor_size, + efi_uintn_t *map_key, + efi_uintn_t *descriptor_size, uint32_t *descriptor_version) { efi_status_t r; @@ -292,12 +292,12 @@ static efi_status_t EFIAPI efi_get_memory_map_ext( * @return status code */ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, - unsigned long size, + efi_uintn_t size, void **buffer) { efi_status_t r; - EFI_ENTRY("%d, %ld, %p", pool_type, size, buffer); + EFI_ENTRY("%d, %zd, %p", pool_type, size, buffer); r = efi_allocate_pool(pool_type, size, buffer); return EFI_EXIT(r); } @@ -539,13 +539,13 @@ static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, * @index index of the event that was signaled * @return status code */ -static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, +static efi_status_t EFIAPI efi_wait_for_event(efi_uintn_t num_events, struct efi_event **event, - size_t *index) + efi_uintn_t *index) { int i, j; - EFI_ENTRY("%ld, %p, %p", num_events, event, index); + EFI_ENTRY("%zd, %p, %p", num_events, event, index); /* Check parameters */ if (!num_events || !event) @@ -925,10 +925,10 @@ static int efi_search(enum efi_locate_search_type search_type, static efi_status_t efi_locate_handle( enum efi_locate_search_type search_type, const efi_guid_t *protocol, void *search_key, - unsigned long *buffer_size, efi_handle_t *buffer) + efi_uintn_t *buffer_size, efi_handle_t *buffer) { struct list_head *lhandle; - unsigned long size = 0; + efi_uintn_t size = 0; /* Count how much space we need */ list_for_each(lhandle, &efi_obj_list) { @@ -977,7 +977,7 @@ static efi_status_t efi_locate_handle( static efi_status_t EFIAPI efi_locate_handle_ext( enum efi_locate_search_type search_type, const efi_guid_t *protocol, void *search_key, - unsigned long *buffer_size, efi_handle_t *buffer) + efi_uintn_t *buffer_size, efi_handle_t *buffer) { EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, buffer_size, buffer); @@ -1548,7 +1548,7 @@ static efi_status_t EFIAPI efi_close_protocol(void *handle, static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, const efi_guid_t *protocol, struct efi_open_protocol_info_entry **entry_buffer, - unsigned long *entry_count) + efi_uintn_t *entry_count) { EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer, entry_count); @@ -1569,7 +1569,7 @@ static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, */ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, efi_guid_t ***protocol_buffer, - unsigned long *protocol_buffer_count) + efi_uintn_t *protocol_buffer_count) { unsigned long buffer_size; struct efi_object *efiobj; @@ -1637,10 +1637,10 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, static efi_status_t EFIAPI efi_locate_handle_buffer( enum efi_locate_search_type search_type, const efi_guid_t *protocol, void *search_key, - unsigned long *no_handles, efi_handle_t **buffer) + efi_uintn_t *no_handles, efi_handle_t **buffer) { efi_status_t r; - unsigned long buffer_size = 0; + efi_uintn_t buffer_size = 0; EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, no_handles, buffer); diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index d47759e08e..0aa3e0881d 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -276,7 +276,7 @@ static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr) } efi_status_t efi_allocate_pages(int type, int memory_type, - unsigned long pages, uint64_t *memory) + efi_uintn_t pages, uint64_t *memory) { u64 len = pages << EFI_PAGE_SHIFT; efi_status_t r = EFI_SUCCESS; @@ -338,7 +338,7 @@ void *efi_alloc(uint64_t len, int memory_type) return NULL; } -efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) +efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) { uint64_t r = 0; @@ -351,7 +351,7 @@ efi_status_t efi_free_pages(uint64_t memory, unsigned long pages) return EFI_NOT_FOUND; } -efi_status_t efi_allocate_pool(int pool_type, unsigned long size, +efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) { efi_status_t r; @@ -392,16 +392,16 @@ efi_status_t efi_free_pool(void *buffer) return r; } -efi_status_t efi_get_memory_map(unsigned long *memory_map_size, - struct efi_mem_desc *memory_map, - unsigned long *map_key, - unsigned long *descriptor_size, - uint32_t *descriptor_version) +efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, + struct efi_mem_desc *memory_map, + efi_uintn_t *map_key, + efi_uintn_t *descriptor_size, + uint32_t *descriptor_version) { - ulong map_size = 0; + efi_uintn_t map_size = 0; int map_entries = 0; struct list_head *lhandle; - unsigned long provided_map_size = *memory_map_size; + efi_uintn_t provided_map_size = *memory_map_size; list_for_each(lhandle, &efi_mem) map_entries++; diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index b6bc4dd5c0..263b53f672 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -32,9 +32,9 @@ static u16 reset_message[] = L"Selftest completed"; */ void efi_st_exit_boot_services(void) { - unsigned long map_size = 0; - unsigned long map_key; - unsigned long desc_size; + efi_uintn_t map_size = 0; + efi_uintn_t map_key; + efi_uintn_t desc_size; u32 desc_version; efi_status_t ret; struct efi_mem_desc *memory_map; diff --git a/lib/efi_selftest/efi_selftest_events.c b/lib/efi_selftest/efi_selftest_events.c index 081f31257f..ad9490bd25 100644 --- a/lib/efi_selftest/efi_selftest_events.c +++ b/lib/efi_selftest/efi_selftest_events.c @@ -108,7 +108,7 @@ static int teardown(void) */ static int execute(void) { - size_t index; + efi_uintn_t index; efi_status_t ret; /* Set 10 ms timer */ diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c index e978dd7f2f..f20f1528d4 100644 --- a/lib/efi_selftest/efi_selftest_manageprotocols.c +++ b/lib/efi_selftest/efi_selftest_manageprotocols.c @@ -138,9 +138,9 @@ static int execute(void) efi_status_t ret; efi_handle_t *buffer; size_t buffer_size; - unsigned long int count = 0; + efi_uintn_t count = 0; efi_guid_t **prot_buffer; - unsigned long int prot_count; + efi_uintn_t prot_count; /* * Test HandleProtocol diff --git a/lib/efi_selftest/efi_selftest_snp.c b/lib/efi_selftest/efi_selftest_snp.c index bdd6ce20da..cc0705fb59 100644 --- a/lib/efi_selftest/efi_selftest_snp.c +++ b/lib/efi_selftest/efi_selftest_snp.c @@ -260,7 +260,7 @@ static int execute(void) { efi_status_t ret; struct efi_event *events[2]; - size_t index; + efi_uintn_t index; union { struct dhcp p; u8 b[PKTSIZE]; diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c index 15d62903c0..6ea0bb7177 100644 --- a/lib/efi_selftest/efi_selftest_tpl.c +++ b/lib/efi_selftest/efi_selftest_tpl.c @@ -111,7 +111,7 @@ static int teardown(void) */ static int execute(void) { - size_t index; + efi_uintn_t index; efi_status_t ret; efi_uintn_t old_tpl; -- cgit v1.2.1 From caf864e434b3f12bae0c7e5932045ff8c9383180 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:49 +0100 Subject: efi_loader: rework efi_locate_handle Check the parameters in efi_locate_handle. Use list_for_each_entry instead of list_for_each. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 44 +++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5bf26114a1..fdbdfc4670 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -896,6 +896,7 @@ static int efi_search(enum efi_locate_search_type search_type, case ALL_HANDLES: return 0; case BY_REGISTER_NOTIFY: + /* RegisterProtocolNotify is not implemented yet */ return -1; case BY_PROTOCOL: for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { @@ -927,16 +928,38 @@ static efi_status_t efi_locate_handle( const efi_guid_t *protocol, void *search_key, efi_uintn_t *buffer_size, efi_handle_t *buffer) { - struct list_head *lhandle; + struct efi_object *efiobj; efi_uintn_t size = 0; + /* Check parameters */ + switch (search_type) { + case ALL_HANDLES: + break; + case BY_REGISTER_NOTIFY: + if (!search_key) + return EFI_INVALID_PARAMETER; + /* RegisterProtocolNotify is not implemented yet */ + return EFI_UNSUPPORTED; + case BY_PROTOCOL: + if (!protocol) + return EFI_INVALID_PARAMETER; + break; + default: + return EFI_INVALID_PARAMETER; + } + + /* + * efi_locate_handle_buffer uses this function for + * the calculation of the necessary buffer size. + * So do not require a buffer for buffersize == 0. + */ + if (!buffer_size || (*buffer_size && !buffer)) + return EFI_INVALID_PARAMETER; + /* Count how much space we need */ - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; - efiobj = list_entry(lhandle, struct efi_object, link); - if (!efi_search(search_type, protocol, search_key, efiobj)) { + list_for_each_entry(efiobj, &efi_obj_list, link) { + if (!efi_search(search_type, protocol, search_key, efiobj)) size += sizeof(void*); - } } if (*buffer_size < size) { @@ -949,12 +972,9 @@ static efi_status_t efi_locate_handle( return EFI_NOT_FOUND; /* Then fill the array */ - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; - efiobj = list_entry(lhandle, struct efi_object, link); - if (!efi_search(search_type, protocol, search_key, efiobj)) { - *(buffer++) = efiobj->handle; - } + list_for_each_entry(efiobj, &efi_obj_list, link) { + if (!efi_search(search_type, protocol, search_key, efiobj)) + *buffer++ = efiobj->handle; } return EFI_SUCCESS; -- cgit v1.2.1 From 1b68153af1ff0af3828ad7de0d0319a456ff19f7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 6 Nov 2017 21:17:50 +0100 Subject: efi_loader: rework efi_search_obj EFI_HANDLEs are used both in boottime and in runtime services. efi_search_obj is a function that can be used to validate handles. So let's make it accessible via efi_loader.h. We can simplify the coding using list_for_each_entry. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index fdbdfc4670..2cc6d891c6 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -684,14 +684,11 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) * @handle handle to find * @return EFI object */ -static struct efi_object *efi_search_obj(void *handle) +struct efi_object *efi_search_obj(void *handle) { - struct list_head *lhandle; - - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; + struct efi_object *efiobj; - efiobj = list_entry(lhandle, struct efi_object, link); + list_for_each_entry(efiobj, &efi_obj_list, link) { if (efiobj->handle == handle) return efiobj; } -- cgit v1.2.1 From 62471e46cd12dd4c357b4fe6891668e3abbf5edf Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:42 +0200 Subject: efi_loader: fix typo efi_install_multiple_protocol_interfaces %s/occured/occurred/g Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- 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 2cc6d891c6..f64db41b03 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1775,7 +1775,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( if (r == EFI_SUCCESS) return EFI_EXIT(r); - /* If an error occured undo all changes. */ + /* If an error occurred undo all changes. */ va_start(argptr, handle); for (; i; --i) { protocol = va_arg(argptr, efi_guid_t*); -- cgit v1.2.1 From af1408e080e21b1bf04c24740ceb39f118c3293b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:43 +0200 Subject: efi_loader: debug output efi_install_protocol_interface efi_install_protocol_interface should provide the created or provided handle in the debug output. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index f64db41b03..397759397f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -732,6 +732,11 @@ static efi_status_t EFIAPI efi_install_protocol_interface( r = efi_create_handle(handle); if (r != EFI_SUCCESS) goto out; + debug("%sEFI: new handle %p\n", indent_string(nesting_level), + *handle); + } else { + debug("%sEFI: handle %p\n", indent_string(nesting_level), + *handle); } /* Find object. */ list_for_each(lhandle, &efi_obj_list) { -- cgit v1.2.1 From 843ce54c7470c58fa7251ad07abeed67b4fc56c4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:44 +0200 Subject: efi_loader implement UninstallMultipleProtocolInterfaces Implement UninstallMultipleProtocolInterfaces. The efi_uninstall_multipled_protocol_interfaces tries to uninstall protocols one by one. If an error occurs all uninstalled protocols are reinstalled. As the implementation efi_uninstall_protocol_interface is still incomplete the function will fail. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 397759397f..b79b3aed49 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1809,7 +1809,45 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( void *handle, ...) { EFI_ENTRY("%p", handle); - return EFI_EXIT(EFI_INVALID_PARAMETER); + + va_list argptr; + const efi_guid_t *protocol; + void *protocol_interface; + efi_status_t r = EFI_SUCCESS; + size_t i = 0; + + if (!handle) + return EFI_EXIT(EFI_INVALID_PARAMETER); + + va_start(argptr, handle); + for (;;) { + protocol = va_arg(argptr, efi_guid_t*); + if (!protocol) + break; + protocol_interface = va_arg(argptr, void*); + r = EFI_CALL(efi_uninstall_protocol_interface( + handle, protocol, + protocol_interface)); + if (r != EFI_SUCCESS) + break; + i++; + } + va_end(argptr); + if (r == EFI_SUCCESS) + return EFI_EXIT(r); + + /* If an error occurred undo all changes. */ + va_start(argptr, handle); + for (; i; --i) { + protocol = va_arg(argptr, efi_guid_t*); + protocol_interface = va_arg(argptr, void*); + EFI_CALL(efi_install_protocol_interface(&handle, protocol, + EFI_NATIVE_INTERFACE, + protocol_interface)); + } + va_end(argptr); + + return EFI_EXIT(r); } /* -- cgit v1.2.1 From 753edb131a856267ca06598be0697163dbe58a49 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:45 +0200 Subject: efi_loader: efi_gop: check calloc return value Calloc may return NULL. We have to check the return value. Fixes: be8d324191f efi_loader: Add GOP support Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_gop.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 411a8c9226..85b5391ed1 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -173,6 +173,10 @@ int efi_gop_register(void) } gopobj = calloc(1, sizeof(*gopobj)); + if (!gopobj) { + printf("ERROR: Out of memory\n"); + return 1; + } /* Fill in object data */ gopobj->parent.protocols[0].guid = &efi_gop_guid; -- cgit v1.2.1 From 93945f2c65ff80290fc2af4f5c5d9bb52ff9ffa5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:46 +0200 Subject: efi_loader: efi_disk: check return value of calloc Calloc may return NULL. We should check the return value. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index e61dbc8058..c6f0d732c1 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -196,6 +196,15 @@ efi_fs_from_path(struct efi_device_path *fp) return diskobj->volume; } +/* + * Create a device for a disk + * + * @name not used + * @if_typename interface name for block device + * @desc internal block device + * @dev_index device index for block device + * @offset offset into disk for simple partitions + */ static void efi_disk_add_dev(const char *name, const char *if_typename, struct blk_desc *desc, @@ -210,6 +219,10 @@ static void efi_disk_add_dev(const char *name, return; diskobj = calloc(1, sizeof(*diskobj)); + if (!diskobj) { + printf("ERROR: Out of memory\n"); + return; + } /* Fill in object data */ diskobj->dp = efi_dp_from_part(desc, part); -- cgit v1.2.1 From cb90ee97579daeacc3173d4c9694b53136a55981 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:47 +0200 Subject: efi_loader: efi_net: check return value of calloc Calloc may return NULL. So we must check the return value. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 432d9a99a2..a7b101e830 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -292,6 +292,10 @@ int efi_net_register(void) /* We only expose the "active" eth device, so one is enough */ netobj = calloc(1, sizeof(*netobj)); + if (!netobj) { + printf("ERROR: Out of memory\n"); + return 1; + } /* Fill in object data */ netobj->parent.protocols[0].guid = &efi_net_guid; -- cgit v1.2.1 From ff401d3f81bb8cfcec28162de07236a355aa3212 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:48 +0200 Subject: efi_loader: efi_dp_match should have const arguments efi_dp_match does not change its arguments. So they should be marked as const. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index f6e368e029..024877161b 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -68,7 +68,8 @@ struct efi_device_path *efi_dp_next(const struct efi_device_path *dp) * representing a device with one representing a file on the device, or * a device with a parent device. */ -int efi_dp_match(struct efi_device_path *a, struct efi_device_path *b) +int efi_dp_match(const struct efi_device_path *a, + const struct efi_device_path *b) { while (1) { int ret; -- cgit v1.2.1 From 2edab5e2e685a384261e6dd32676924feb33dfa8 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:49 +0200 Subject: efi_loader: make efi_create_handle non-static Export function efi_create_handle. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b79b3aed49..06340fd673 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -321,7 +321,13 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) return EFI_EXIT(r); } -static efi_status_t efi_create_handle(void **handle) +/* + * Create handle. + * + * @handle new handle + * @return status code + */ +efi_status_t efi_create_handle(void **handle) { struct efi_object *obj; efi_status_t r; -- cgit v1.2.1 From 085d07cd3b8c9a12d5a02c13b56ab92436c062ba Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:50 +0200 Subject: efi_loader: argument of efi_search_obj should be const The argument of efi_search_obj is not changed so it should be marked as const. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- 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 06340fd673..98477dfed6 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -690,7 +690,7 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) * @handle handle to find * @return EFI object */ -struct efi_object *efi_search_obj(void *handle) +struct efi_object *efi_search_obj(const void *handle) { struct efi_object *efiobj; -- cgit v1.2.1 From 1c38a7741c59d1213004a07c362ae7f07a3d9357 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:51 +0200 Subject: efi_loader: efi_gop: use correct types for parameters Use efi_uintn_t instead of unsigned long. EFI_GRAPHICS_OUTPUT_BLT_OPERATION is an enum. If we don't define an enum we have to pass it as u32. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_gop.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 85b5391ed1..7370eeee37 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -32,7 +32,7 @@ struct efi_gop_obj { }; static efi_status_t EFIAPI gop_query_mode(struct efi_gop *this, u32 mode_number, - unsigned long *size_of_info, + efi_uintn_t *size_of_info, struct efi_gop_mode_info **info) { struct efi_gop_obj *gopobj; @@ -56,17 +56,17 @@ static efi_status_t EFIAPI gop_set_mode(struct efi_gop *this, u32 mode_number) return EFI_EXIT(EFI_SUCCESS); } -static efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, - unsigned long operation, unsigned long sx, - unsigned long sy, unsigned long dx, - unsigned long dy, unsigned long width, - unsigned long height, unsigned long delta) +efi_status_t EFIAPI gop_blt(struct efi_gop *this, void *buffer, + u32 operation, efi_uintn_t sx, + efi_uintn_t sy, efi_uintn_t dx, + efi_uintn_t dy, efi_uintn_t width, + efi_uintn_t height, efi_uintn_t delta) { struct efi_gop_obj *gopobj = container_of(this, struct efi_gop_obj, ops); int i, j, line_len16, line_len32; void *fb; - EFI_ENTRY("%p, %p, %lx, %lx, %lx, %lx, %lx, %lx, %lx, %lx", this, + EFI_ENTRY("%p, %p, %u, %zu, %zu, %zu, %zu, %zu, %zu, %zu", this, buffer, operation, sx, sy, dx, dy, width, height, delta); if (operation != EFI_BLT_BUFFER_TO_VIDEO) -- cgit v1.2.1 From 49d62cb0937bfdb1774a2c5c244595d9a09815b3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:52 +0200 Subject: efi_selftest: test for graphics output protocol Supply a test for the graphics output protocol. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 3 ++ lib/efi_selftest/efi_selftest_gop.c | 95 +++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_gop.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index acd184db4b..1851c17db6 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -15,6 +15,8 @@ CFLAGS_efi_selftest_events.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_events.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_exitbootservices.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_exitbootservices.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_gop.o := $(CFLAGS_EFI) +CFLAGS_REMOVE_efi_selftest_gop.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_manageprotocols.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_manageprotocols.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_snp.o := $(CFLAGS_EFI) @@ -33,6 +35,7 @@ efi_selftest.o \ efi_selftest_console.o \ efi_selftest_events.o \ efi_selftest_exitbootservices.o \ +efi_selftest_gop.o \ efi_selftest_manageprotocols.o \ efi_selftest_snp.o \ efi_selftest_textoutput.o \ diff --git a/lib/efi_selftest/efi_selftest_gop.c b/lib/efi_selftest/efi_selftest_gop.c new file mode 100644 index 0000000000..2a0553b115 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_gop.c @@ -0,0 +1,95 @@ +/* + * efi_selftest_gop + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Test the graphical output protocol. + */ + +#include + +static struct efi_boot_services *boottime; +static efi_guid_t efi_gop_guid = EFI_GOP_GUID; +static struct efi_gop *gop; + +/* + * Setup unit test. + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&efi_gop_guid, NULL, (void **)&gop); + if (ret != EFI_SUCCESS) { + gop = NULL; + efi_st_printf("Graphical output protocol is not available.\n"); + } + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + u32 i, max_mode; + efi_uintn_t size; + struct efi_gop_mode_info *info; + + if (!gop) + return EFI_ST_SUCCESS; + + if (!gop->mode) { + efi_st_error("EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE missing\n"); + return EFI_ST_FAILURE; + } + max_mode = gop->mode->max_mode; + if (!max_mode) { + efi_st_error("No graphical mode available\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("Number of available modes: %u\n", max_mode); + + for (i = 0; i < max_mode; ++i) { + ret = gop->query_mode(gop, i, &size, &info); + if (ret != EFI_SUCCESS) { + efi_st_printf("Could not query mode %u\n", i); + return EFI_ST_FAILURE; + } + efi_st_printf("Mode %u: %u x %u\n", + i, info->width, info->height); + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(gop) = { + .name = "graphical output", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; -- cgit v1.2.1 From 3f79a2b532d8deafd5293f9f7e492d30fc6e339d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:53 +0200 Subject: efi_loader: helper functions for protocol management This patch provides helper functions to manage protocols. efi_search_protocol - find a protocol on a handle efi_add_protocol - install a protocol on a handle efi_remove_protocol - remove a protocol from a handle efi_remove_all_protocols - remove all protocols from a handle Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 119 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 98477dfed6..e372c8bb94 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -702,6 +702,125 @@ struct efi_object *efi_search_obj(const void *handle) return NULL; } +/* + * Find a protocol on a handle. + * + * @handle handle + * @protocol_guid GUID of the protocol + * @handler reference to the protocol + * @return status code + */ +efi_status_t efi_search_protocol(const void *handle, + const efi_guid_t *protocol_guid, + struct efi_handler **handler) +{ + struct efi_object *efiobj; + size_t i; + struct efi_handler *protocol; + + if (!handle || !protocol_guid) + return EFI_INVALID_PARAMETER; + efiobj = efi_search_obj(handle); + if (!efiobj) + return EFI_INVALID_PARAMETER; + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + protocol = &efiobj->protocols[i]; + if (!protocol->guid) + continue; + if (!guidcmp(protocol->guid, protocol_guid)) { + if (handler) + *handler = protocol; + return EFI_SUCCESS; + } + } + return EFI_NOT_FOUND; +} + +/* + * Install new protocol on a handle. + * + * @handle handle on which the protocol shall be installed + * @protocol GUID of the protocol to be installed + * @protocol_interface interface of the protocol implementation + * @return status code + */ +efi_status_t efi_add_protocol(const void *handle, const efi_guid_t *protocol, + void *protocol_interface) +{ + struct efi_object *efiobj; + struct efi_handler *handler; + efi_status_t ret; + size_t i; + + efiobj = efi_search_obj(handle); + if (!efiobj) + return EFI_INVALID_PARAMETER; + ret = efi_search_protocol(handle, protocol, NULL); + if (ret != EFI_NOT_FOUND) + return EFI_INVALID_PARAMETER; + handler = calloc(1, sizeof(struct efi_handler)); + if (!handler) + return EFI_OUT_OF_RESOURCES; + /* Install protocol in first empty slot. */ + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + handler = &efiobj->protocols[i]; + if (handler->guid) + continue; + handler->guid = protocol; + handler->protocol_interface = protocol_interface; + return EFI_SUCCESS; + } + return EFI_OUT_OF_RESOURCES; +} + +/* + * Delete protocol from a handle. + * + * @handle handle from which the protocol shall be deleted + * @protocol GUID of the protocol to be deleted + * @protocol_interface interface of the protocol implementation + * @return status code + */ +efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol, + void *protocol_interface) +{ + struct efi_handler *handler; + efi_status_t ret; + + ret = efi_search_protocol(handle, protocol, &handler); + if (ret != EFI_SUCCESS) + return ret; + if (handler->protocol_interface != protocol_interface) + return EFI_NOT_FOUND; + handler->guid = NULL; + handler->protocol_interface = NULL; + return EFI_SUCCESS; +} + +/* + * Delete all protocols from a handle. + * + * @handle handle from which the protocols shall be deleted + * @return status code + */ +efi_status_t efi_remove_all_protocols(const void *handle) +{ + struct efi_object *efiobj; + struct efi_handler *handler; + size_t i; + + efiobj = efi_search_obj(handle); + if (!efiobj) + return EFI_INVALID_PARAMETER; + + for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { + handler = &efiobj->protocols[i]; + handler->guid = NULL; + handler->protocol_interface = NULL; + } + return EFI_SUCCESS; +} + /* * Install protocol interface. * -- cgit v1.2.1 From 1202530d221936604e847fd7ce4bf8d8039d589b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:54 +0200 Subject: efi_loader: simplify efi_install_protocol_interface Use helper functio efi_add_protocol. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 38 ++------------------------------------ 1 file changed, 2 insertions(+), 36 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index e372c8bb94..900cb1aad8 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -839,8 +839,6 @@ static efi_status_t EFIAPI efi_install_protocol_interface( void **handle, const efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { - struct list_head *lhandle; - int i; efi_status_t r; EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type, @@ -863,40 +861,8 @@ static efi_status_t EFIAPI efi_install_protocol_interface( debug("%sEFI: handle %p\n", indent_string(nesting_level), *handle); } - /* Find object. */ - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; - efiobj = list_entry(lhandle, struct efi_object, link); - - if (efiobj->handle != *handle) - continue; - /* Check if protocol is already installed on the handle. */ - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - struct efi_handler *handler = &efiobj->protocols[i]; - - if (!handler->guid) - continue; - if (!guidcmp(handler->guid, protocol)) { - r = EFI_INVALID_PARAMETER; - goto out; - } - } - /* Install protocol in first empty slot. */ - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - struct efi_handler *handler = &efiobj->protocols[i]; - - if (handler->guid) - continue; - - handler->guid = protocol; - handler->protocol_interface = protocol_interface; - r = EFI_SUCCESS; - goto out; - } - r = EFI_OUT_OF_RESOURCES; - goto out; - } - r = EFI_INVALID_PARAMETER; + /* Add new protocol */ + r = efi_add_protocol(*handle, protocol, protocol_interface); out: return EFI_EXIT(r); } -- cgit v1.2.1 From 42cf12420b0e5664fa118f3d19e153f48740664b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:55 +0200 Subject: efi_loader: simplify efi_search Use helper function efi_search_protocol in efi_search. Add missing comments. Put default handling into default branch of switch statement. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 900cb1aad8..ff1f23356e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -983,24 +983,21 @@ static int efi_search(enum efi_locate_search_type search_type, const efi_guid_t *protocol, void *search_key, struct efi_object *efiobj) { - int i; + efi_status_t ret; switch (search_type) { case ALL_HANDLES: return 0; case BY_REGISTER_NOTIFY: - /* RegisterProtocolNotify is not implemented yet */ + /* TODO: RegisterProtocolNotify is not implemented yet */ return -1; case BY_PROTOCOL: - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - const efi_guid_t *guid = efiobj->protocols[i].guid; - if (guid && !guidcmp(guid, protocol)) - return 0; - } + ret = efi_search_protocol(efiobj->handle, protocol, NULL); + return (ret != EFI_SUCCESS); + default: + /* Invalid search type */ return -1; } - - return -1; } /* -- cgit v1.2.1 From 5810511dac980929dbfe57e25ccdf72d5b7e38e4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:56 +0200 Subject: efi_loader: simplify efi_uninstall_protocol_interface Use function efi_search_obj, efi_search_protocol and efi_remove_protocol to simplify the coding. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 38 +++++++++++--------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index ff1f23356e..f32ddd5022 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -906,9 +906,8 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface( void *handle, const efi_guid_t *protocol, void *protocol_interface) { - struct list_head *lhandle; - int i; - efi_status_t r = EFI_NOT_FOUND; + struct efi_handler *handler; + efi_status_t r; EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); @@ -917,31 +916,16 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface( goto out; } - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; - efiobj = list_entry(lhandle, struct efi_object, link); - - if (efiobj->handle != handle) - continue; - - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - struct efi_handler *handler = &efiobj->protocols[i]; - const efi_guid_t *hprotocol = handler->guid; - - if (!hprotocol) - continue; - if (!guidcmp(hprotocol, protocol)) { - if (handler->protocol_interface) { - r = EFI_ACCESS_DENIED; - } else { - handler->guid = 0; - r = EFI_SUCCESS; - } - goto out; - } - } + /* Find the protocol on the handle */ + r = efi_search_protocol(handle, protocol, &handler); + if (r != EFI_SUCCESS) + goto out; + if (handler->protocol_interface) { + /* TODO disconnect controllers */ + r = EFI_ACCESS_DENIED; + } else { + r = efi_remove_protocol(handle, protocol, protocol_interface); } - out: return EFI_EXIT(r); } -- cgit v1.2.1 From 9172cd91fa58da48f31259c51536aa8778bd72da Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:57 +0200 Subject: efi_loader: simplify efi_locate_protocol Use helper function efi_search_protocol. Do not print protocol guid twice in debug mode. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index f32ddd5022..9e8d8f486e 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1778,29 +1778,23 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, void **protocol_interface) { struct list_head *lhandle; - int i; + efi_status_t ret; EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface); if (!protocol || !protocol_interface) return EFI_EXIT(EFI_INVALID_PARAMETER); - EFI_PRINT_GUID("protocol", protocol); - list_for_each(lhandle, &efi_obj_list) { struct efi_object *efiobj; + struct efi_handler *handler; efiobj = list_entry(lhandle, struct efi_object, link); - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - struct efi_handler *handler = &efiobj->protocols[i]; - if (!handler->guid) - continue; - if (!guidcmp(handler->guid, protocol)) { - *protocol_interface = - handler->protocol_interface; - return EFI_EXIT(EFI_SUCCESS); - } + ret = efi_search_protocol(efiobj->handle, protocol, &handler); + if (ret == EFI_SUCCESS) { + *protocol_interface = handler->protocol_interface; + return EFI_EXIT(EFI_SUCCESS); } } *protocol_interface = NULL; -- cgit v1.2.1 From 48b66230eef074c7335eab8c82b1f9c561b54794 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:58 +0200 Subject: efi_loader: refactor efi_setup_loaded_image Use helper functions to add protocols. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9e8d8f486e..9b5512f086 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1193,34 +1193,45 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob struct efi_device_path *device_path, struct efi_device_path *file_path) { + efi_status_t ret; + obj->handle = info; + info->file_path = file_path; + if (device_path) + info->device_handle = efi_dp_find_obj(device_path, NULL); + + list_add_tail(&obj->link, &efi_obj_list); /* * When asking for the device path interface, return * bootefi_device_path */ - obj->protocols[0].guid = &efi_guid_device_path; - obj->protocols[0].protocol_interface = device_path; + ret = efi_add_protocol(obj->handle, &efi_guid_device_path, device_path); + if (ret != EFI_SUCCESS) + goto failure; /* * When asking for the loaded_image interface, just * return handle which points to loaded_image_info */ - obj->protocols[1].guid = &efi_guid_loaded_image; - obj->protocols[1].protocol_interface = info; - - obj->protocols[2].guid = &efi_guid_console_control; - obj->protocols[2].protocol_interface = (void *)&efi_console_control; + ret = efi_add_protocol(obj->handle, &efi_guid_loaded_image, info); + if (ret != EFI_SUCCESS) + goto failure; - obj->protocols[3].guid = &efi_guid_device_path_to_text_protocol; - obj->protocols[3].protocol_interface = - (void *)&efi_device_path_to_text; + ret = efi_add_protocol(obj->handle, &efi_guid_console_control, + (void *)&efi_console_control); + if (ret != EFI_SUCCESS) + goto failure; - info->file_path = file_path; - if (device_path) - info->device_handle = efi_dp_find_obj(device_path, NULL); + ret = efi_add_protocol(obj->handle, + &efi_guid_device_path_to_text_protocol, + (void *)&efi_device_path_to_text); + if (ret != EFI_SUCCESS) + goto failure; - list_add_tail(&obj->link, &efi_obj_list); + return; +failure: + printf("ERROR: Failure to install protocols for loaded image\n"); } /* -- cgit v1.2.1 From ebb4dd5bc3d39b3a2109970936c7e74556110915 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 26 Oct 2017 19:25:59 +0200 Subject: efi_loader: efi_console: use helper functions Use helper functions efi_created_handle and efi_add_protocol for creating the console handles and instaling the respective protocols. This change is needed if we want to move from an array of protocols to a linked list of protocols. Eliminate EFI_PROTOCOL_OBJECT which is not used anymore. Currently we have not defined protocol interfaces to be const. So efi_con_out and efi_console_control cannot be defined as const. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_console.c | 48 ++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 01732aafea..98497db612 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -46,6 +46,10 @@ static struct cout_mode efi_cout_modes[] = { }; const efi_guid_t efi_guid_console_control = CONSOLE_CONTROL_GUID; +const efi_guid_t efi_guid_text_output_protocol = + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID; +const efi_guid_t efi_guid_text_input_protocol = + EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID; #define cESC '\x1b' #define ESC "\x1b" @@ -81,7 +85,7 @@ static efi_status_t EFIAPI efi_cin_lock_std_in( return EFI_EXIT(EFI_UNSUPPORTED); } -const struct efi_console_control_protocol efi_console_control = { +struct efi_console_control_protocol efi_console_control = { .get_mode = efi_cin_get_mode, .set_mode = efi_cin_set_mode, .lock_std_in = efi_cin_lock_std_in, @@ -374,7 +378,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor( return EFI_EXIT(EFI_SUCCESS); } -const struct efi_simple_text_output_protocol efi_con_out = { +struct efi_simple_text_output_protocol efi_con_out = { .reset = efi_cout_reset, .output_string = efi_cout_output_string, .test_string = efi_cout_test_string, @@ -490,23 +494,38 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event, } -static struct efi_object efi_console_control_obj = - EFI_PROTOCOL_OBJECT(efi_guid_console_control, &efi_console_control); -static struct efi_object efi_console_output_obj = - EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID, &efi_con_out); -static struct efi_object efi_console_input_obj = - EFI_PROTOCOL_OBJECT(EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID, &efi_con_in); - /* This gets called from do_bootefi_exec(). */ int efi_console_register(void) { efi_status_t r; + struct efi_object *efi_console_control_obj; + struct efi_object *efi_console_output_obj; + struct efi_object *efi_console_input_obj; - /* Hook up to the device list */ - list_add_tail(&efi_console_control_obj.link, &efi_obj_list); - list_add_tail(&efi_console_output_obj.link, &efi_obj_list); - list_add_tail(&efi_console_input_obj.link, &efi_obj_list); + /* Create handles */ + r = efi_create_handle((void **)&efi_console_control_obj); + if (r != EFI_SUCCESS) + goto out_of_memory; + r = efi_add_protocol(efi_console_control_obj->handle, + &efi_guid_console_control, &efi_console_control); + if (r != EFI_SUCCESS) + goto out_of_memory; + r = efi_create_handle((void **)&efi_console_output_obj); + if (r != EFI_SUCCESS) + goto out_of_memory; + r = efi_add_protocol(efi_console_output_obj->handle, + &efi_guid_text_output_protocol, &efi_con_out); + if (r != EFI_SUCCESS) + goto out_of_memory; + r = efi_create_handle((void **)&efi_console_input_obj); + if (r != EFI_SUCCESS) + goto out_of_memory; + r = efi_add_protocol(efi_console_input_obj->handle, + &efi_guid_text_input_protocol, &efi_con_in); + if (r != EFI_SUCCESS) + goto out_of_memory; + /* Create console events */ r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify, NULL, &efi_con_in.wait_for_key); if (r != EFI_SUCCESS) { @@ -525,4 +544,7 @@ int efi_console_register(void) if (r != EFI_SUCCESS) printf("ERROR: Failed to set console timer\n"); return r; +out_of_memory: + printf("ERROR: Out of meemory\n"); + return r; } -- cgit v1.2.1 From b6e9e09770035b4606c408e800f28231dcca9e98 Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Wed, 22 Nov 2017 14:18:59 +1100 Subject: efi_loader: initialise partition_signature memory Zero partition_signature in the efi_device_path_hard_drive_path structure when signature_type is 0 (no signature) as required by the UEFI specification. This is required so that efi_dp_match() will work as expected when doing memcmp() comparisons. Previously uninitialised memory would cause it not match nodes when it should have when the signature type was not GUID. Corrects a problem where the loaded image protocol would not return a device path with MEDIA_DEVICE causing the OpenBSD bootloader to fail on rpi_3 and other targets. v2: Also handle signature_type 1 (MBR) as described in the specification Signed-off-by: Jonathan Gray Tested-by: Artturi Alm Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 024877161b..9027ae8efb 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -428,10 +428,27 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) hddp->partmap_type = 2; else hddp->partmap_type = 1; - hddp->signature_type = desc->sig_type; - if (hddp->signature_type != 0) + + switch (desc->sig_type) { + case SIG_TYPE_NONE: + default: + hddp->signature_type = 0; + memset(hddp->partition_signature, 0, + sizeof(hddp->partition_signature)); + break; + case SIG_TYPE_MBR: + hddp->signature_type = 1; + memset(hddp->partition_signature, 0, + sizeof(hddp->partition_signature)); + memcpy(hddp->partition_signature, &desc->mbr_sig, + sizeof(desc->mbr_sig)); + break; + case SIG_TYPE_GUID: + hddp->signature_type = 2; memcpy(hddp->partition_signature, &desc->guid_sig, sizeof(hddp->partition_signature)); + break; + } buf = &hddp[1]; } -- cgit v1.2.1 From 362f00f979fb6d2972bd682e4c533120ea7c84e8 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:06 +0100 Subject: efi_loader: helloworld.c: remove superfluous include Remove a superfluous include from helloworld.c Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/helloworld.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 03e65ab133..77130a36dd 100644 --- a/lib/efi_loader/helloworld.c +++ b/lib/efi_loader/helloworld.c @@ -8,7 +8,6 @@ */ #include -#include #include efi_status_t EFIAPI efi_main(efi_handle_t handle, -- cgit v1.2.1 From 0741226f65aa3ae52373ad8bddbb6c9537db3a91 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:07 +0100 Subject: efi_loader: size of media device path node represenation In the format specifier we want to specify the maximum width in case an ending \0 is missing. So slen must be used as precision and not as field width. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path_to_text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 62771338f0..98617cf163 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -153,7 +153,7 @@ static char *dp_media(char *s, struct efi_device_path *dp) struct efi_device_path_file_path *fp = (struct efi_device_path_file_path *)dp; int slen = (dp->length - sizeof(*dp)) / 2; - s += sprintf(s, "/%-*ls", slen, fp->str); + s += sprintf(s, "/%-.*ls", slen, fp->str); break; } default: -- cgit v1.2.1 From 908cf9a3ffdd611808d75e3c845774ba152c91a4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:08 +0100 Subject: efi_loader: efi_dp_str should print path not node efi_dp_str is meant to print a device path and not a device node. The old coding only worked because efi_convert_device_node_to_text was screwed up to expect paths instead of nodes. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path_to_text.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 98617cf163..ad248cb492 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -208,13 +208,6 @@ static uint16_t *efi_convert_device_node_to_text( return out; } -/* helper for debug prints.. efi_free_pool() the result. */ -uint16_t *efi_dp_str(struct efi_device_path *dp) -{ - return efi_convert_device_node_to_text(dp, true, true); -} - - static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( struct efi_device_path *device_node, bool display_only, @@ -251,6 +244,12 @@ static uint16_t EFIAPI *efi_convert_device_path_to_text( return buffer; } +/* helper for debug prints.. efi_free_pool() the result. */ +uint16_t *efi_dp_str(struct efi_device_path *dp) +{ + return EFI_CALL(efi_convert_device_path_to_text(dp, true, true)); +} + const struct efi_device_path_to_text_protocol efi_device_path_to_text = { .convert_device_node_to_text = efi_convert_device_node_to_text_ext, .convert_device_path_to_text = efi_convert_device_path_to_text, -- cgit v1.2.1 From 61aba1931a559a325c39f48d24a47de857d0da75 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:09 +0100 Subject: efi_loader: fix efi_convert_device_node_to_text We need to implement to different functions for the EFI_DEVICE_PATH_TO_TEXT_PROTOCOL: ConvertDeviceNodeToText ConvertDevicePathToText A recent patch screwed up efi_convert_device_node_to_text to expect a device path and not a node. The patch makes both service functions work again. efi_convert_device_node_to_text is renamed to efi_convert_single_device_node_to_text and efi_convert_device_node_to_text_ext is renamed to efi_convert_device_node_to_text to avoid future confusion. A test of ConvertDeviceNodeToText will be provided in a follow-up patch. Fixes: adae4313cdd efi_loader: flesh out device-path to text Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path_to_text.c | 154 ++++++++++++++++++------------- 1 file changed, 88 insertions(+), 66 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index ad248cb492..43af5dfd8d 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -12,12 +12,31 @@ #define MAC_OUTPUT_LEN 22 #define UNKNOWN_OUTPUT_LEN 23 +#define MAX_NODE_LEN 512 +#define MAX_PATH_LEN 1024 + const efi_guid_t efi_guid_device_path_to_text_protocol = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; +static u16 *efi_str_to_u16(char *str) +{ + efi_uintn_t len; + u16 *out; + efi_status_t ret; + + len = strlen(str) + 1; + ret = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, len * sizeof(u16), + (void **)&out); + if (ret != EFI_SUCCESS) + return NULL; + ascii2unicode(out, str); + out[len - 1] = 0; + return out; +} + static char *dp_unknown(char *s, struct efi_device_path *dp) { - s += sprintf(s, "/UNKNOWN(%04x,%04x)", dp->type, dp->sub_type); + s += sprintf(s, "UNKNOWN(%04x,%04x)", dp->type, dp->sub_type); return s; } @@ -27,7 +46,7 @@ static char *dp_hardware(char *s, struct efi_device_path *dp) case DEVICE_PATH_SUB_TYPE_MEMORY: { struct efi_device_path_memory *mdp = (struct efi_device_path_memory *)dp; - s += sprintf(s, "/MemoryMapped(0x%x,0x%llx,0x%llx)", + s += sprintf(s, "MemoryMapped(0x%x,0x%llx,0x%llx)", mdp->memory_type, mdp->start_address, mdp->end_address); @@ -36,7 +55,7 @@ static char *dp_hardware(char *s, struct efi_device_path *dp) case DEVICE_PATH_SUB_TYPE_VENDOR: { struct efi_device_path_vendor *vdp = (struct efi_device_path_vendor *)dp; - s += sprintf(s, "/VenHw(%pUl)", &vdp->guid); + s += sprintf(s, "VenHw(%pUl)", &vdp->guid); break; } default: @@ -52,7 +71,7 @@ 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)); + s += sprintf(s, "Acpi(PNP%04x", EISA_PNP_NUM(adp->hid)); if (adp->uid) s += sprintf(s, ",%d", adp->uid); s += sprintf(s, ")"); @@ -71,7 +90,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp) case DEVICE_PATH_SUB_TYPE_MSG_USB: { struct efi_device_path_usb *udp = (struct efi_device_path_usb *)dp; - s += sprintf(s, "/Usb(0x%x,0x%x)", udp->parent_port_number, + s += sprintf(s, "Usb(0x%x,0x%x)", udp->parent_port_number, udp->usb_interface); break; } @@ -82,7 +101,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp) if (mdp->if_type != 0 && mdp->if_type != 1) break; - s += sprintf(s, "/MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", + s += sprintf(s, "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)", mdp->mac.addr[0], mdp->mac.addr[1], mdp->mac.addr[2], mdp->mac.addr[3], mdp->mac.addr[4], mdp->mac.addr[5], @@ -94,7 +113,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp) struct efi_device_path_usb_class *ucdp = (struct efi_device_path_usb_class *)dp; - s += sprintf(s, "/USBClass(%x,%x,%x,%x,%x)", + s += sprintf(s, "USBClass(%x,%x,%x,%x,%x)", ucdp->vendor_id, ucdp->product_id, ucdp->device_class, ucdp->device_subclass, ucdp->device_protocol); @@ -108,7 +127,7 @@ static char *dp_msging(char *s, struct efi_device_path *dp) "SDCard" : "MMC"; struct efi_device_path_sd_mmc_path *sddp = (struct efi_device_path_sd_mmc_path *)dp; - s += sprintf(s, "/%s(Slot%u)", typename, sddp->slot_number); + s += sprintf(s, "%s(Slot%u)", typename, sddp->slot_number); break; } default: @@ -128,15 +147,15 @@ static char *dp_media(char *s, struct efi_device_path *dp) switch (hddp->signature_type) { case SIG_TYPE_MBR: - s += sprintf(s, "/HD(Part%d,Sig%08x)", + s += sprintf(s, "HD(Part%d,Sig%08x)", hddp->partition_number, *(uint32_t *)sig); break; case SIG_TYPE_GUID: - s += sprintf(s, "/HD(Part%d,Sig%pUl)", + s += sprintf(s, "HD(Part%d,Sig%pUl)", hddp->partition_number, sig); default: - s += sprintf(s, "/HD(Part%d,MBRType=%02x,SigType=%02x)", + s += sprintf(s, "HD(Part%d,MBRType=%02x,SigType=%02x)", hddp->partition_number, hddp->partmap_type, hddp->signature_type); } @@ -146,14 +165,16 @@ static char *dp_media(char *s, struct efi_device_path *dp) case DEVICE_PATH_SUB_TYPE_CDROM_PATH: { struct efi_device_path_cdrom_path *cddp = (struct efi_device_path_cdrom_path *)dp; - s += sprintf(s, "/CDROM(0x%x)", cddp->boot_entry); + s += sprintf(s, "CDROM(0x%x)", cddp->boot_entry); break; } case DEVICE_PATH_SUB_TYPE_FILE_PATH: { struct efi_device_path_file_path *fp = (struct efi_device_path_file_path *)dp; int slen = (dp->length - sizeof(*dp)) / 2; - s += sprintf(s, "/%-.*ls", slen, fp->str); + if (slen > MAX_NODE_LEN - 2) + slen = MAX_NODE_LEN - 2; + s += sprintf(s, "%-.*ls", slen, fp->str); break; } default: @@ -163,65 +184,59 @@ static char *dp_media(char *s, struct efi_device_path *dp) return s; } -static uint16_t *efi_convert_device_node_to_text( - struct efi_device_path *dp, - bool display_only, - bool allow_shortcuts) +/* + * Converts a single node to a char string. + * + * @buffer output buffer + * @dp device path or node + * @return end of string + */ +static char *efi_convert_single_device_node_to_text( + char *buffer, + struct efi_device_path *dp) { - unsigned long len; - efi_status_t r; - char buf[512]; /* this ought be be big enough for worst case */ - char *str = buf; - uint16_t *out; - - while (dp) { - switch (dp->type) { - case DEVICE_PATH_TYPE_HARDWARE_DEVICE: - str = dp_hardware(str, dp); - break; - case DEVICE_PATH_TYPE_ACPI_DEVICE: - str = dp_acpi(str, dp); - break; - case DEVICE_PATH_TYPE_MESSAGING_DEVICE: - str = dp_msging(str, dp); - break; - case DEVICE_PATH_TYPE_MEDIA_DEVICE: - str = dp_media(str, dp); - break; - default: - str = dp_unknown(str, dp); - } + char *str = buffer; - dp = efi_dp_next(dp); + switch (dp->type) { + case DEVICE_PATH_TYPE_HARDWARE_DEVICE: + str = dp_hardware(str, dp); + break; + case DEVICE_PATH_TYPE_ACPI_DEVICE: + str = dp_acpi(str, dp); + break; + case DEVICE_PATH_TYPE_MESSAGING_DEVICE: + str = dp_msging(str, dp); + break; + case DEVICE_PATH_TYPE_MEDIA_DEVICE: + str = dp_media(str, dp); + break; + default: + str = dp_unknown(str, dp); } - *str++ = '\0'; - - len = str - buf; - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, 2 * len, (void **)&out); - if (r != EFI_SUCCESS) - return NULL; - - ascii2unicode(out, buf); - out[len - 1] = 0; - - return out; + *str = '\0'; + return str; } -static uint16_t EFIAPI *efi_convert_device_node_to_text_ext( +static uint16_t EFIAPI *efi_convert_device_node_to_text( struct efi_device_path *device_node, bool display_only, bool allow_shortcuts) { - uint16_t *buffer; + char str[MAX_NODE_LEN]; + uint16_t *text = NULL; EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts); - buffer = efi_convert_device_node_to_text(device_node, display_only, - allow_shortcuts); + if (!device_node) + goto out; + efi_convert_single_device_node_to_text(str, device_node); + + text = efi_str_to_u16(str); +out: EFI_EXIT(EFI_SUCCESS); - return buffer; + return text; } static uint16_t EFIAPI *efi_convert_device_path_to_text( @@ -229,19 +244,26 @@ static uint16_t EFIAPI *efi_convert_device_path_to_text( bool display_only, bool allow_shortcuts) { - uint16_t *buffer; + uint16_t *text = NULL; + char buffer[MAX_PATH_LEN]; + char *str = buffer; EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts); - /* - * Our device paths are all of depth one. So its is sufficient to - * to convert the first node. - */ - buffer = efi_convert_device_node_to_text(device_path, display_only, - allow_shortcuts); + if (!device_path) + goto out; + while (device_path && + str + MAX_NODE_LEN < buffer + MAX_PATH_LEN) { + *str++ = '/'; + str = efi_convert_single_device_node_to_text(str, device_path); + device_path = efi_dp_next(device_path); + } + + text = efi_str_to_u16(buffer); +out: EFI_EXIT(EFI_SUCCESS); - return buffer; + return text; } /* helper for debug prints.. efi_free_pool() the result. */ @@ -251,6 +273,6 @@ uint16_t *efi_dp_str(struct efi_device_path *dp) } const struct efi_device_path_to_text_protocol efi_device_path_to_text = { - .convert_device_node_to_text = efi_convert_device_node_to_text_ext, + .convert_device_node_to_text = efi_convert_device_node_to_text, .convert_device_path_to_text = efi_convert_device_path_to_text, }; -- cgit v1.2.1 From ae2c85c1ce7d76793213aca95a0a7d2b61037499 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:10 +0100 Subject: efi_loader: reimplement LocateDevicePath The current implementation of efi_locate_device_path does not match the UEFI specification. It completely ignores the protocol parameters. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 106 ++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9b5512f086..565addfc3f 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1080,36 +1080,6 @@ static efi_status_t EFIAPI efi_locate_handle_ext( buffer_size, buffer)); } -/* - * Get the device path and handle of an device implementing a protocol. - * - * This function implements the LocateDevicePath service. - * See the Unified Extensible Firmware Interface (UEFI) specification - * for details. - * - * @protocol GUID of the protocol - * @device_path device path - * @device handle of the device - * @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_object *efiobj; - - EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device); - - efiobj = efi_dp_find_obj(*device_path, device_path); - if (!efiobj) - return EFI_EXIT(EFI_NOT_FOUND); - - *device = efiobj->handle; - - return EFI_EXIT(EFI_SUCCESS); -} - /* Collapses configuration table entries, removing index i */ static void efi_remove_configuration_table(int i) { @@ -1813,6 +1783,82 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, return EFI_EXIT(EFI_NOT_FOUND); } +/* + * Get the device path and handle of an device implementing a protocol. + * + * This function implements the LocateDevicePath service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @protocol GUID of the protocol + * @device_path device path + * @device handle of the device + * @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 || !device) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* Find end of device path */ + len = efi_dp_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_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; + *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); +} + /* * Install multiple protocol interfaces. * -- cgit v1.2.1 From bf19064bdc4187b1851d45ded9a93e4867193a9c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:11 +0100 Subject: efi_selftest: test EFI_DEVICE_PATH_TO_TEXT_PROTOCOL Provide a test for the EFI_DEVICE_PATH_TO_TEXT_PROTOCOL protocol. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 3 + lib/efi_selftest/efi_selftest_devicepath.c | 390 +++++++++++++++++++++++++++++ 2 files changed, 393 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_devicepath.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 1851c17db6..d280eca5c3 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -11,6 +11,8 @@ CFLAGS_efi_selftest.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_console.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_console.o := $(CFLAGS_NON_EFI) +CFLAGS_efi_selftest_devicepathe.o := $(CFLAGS_EFI) +CFLAGS_REMOVE_efi_selftest_devicepath.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_events.o := $(CFLAGS_EFI) CFLAGS_REMOVE_efi_selftest_events.o := $(CFLAGS_NON_EFI) CFLAGS_efi_selftest_exitbootservices.o := $(CFLAGS_EFI) @@ -33,6 +35,7 @@ CFLAGS_REMOVE_efi_selftest_watchdog.o := $(CFLAGS_NON_EFI) obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ efi_selftest_console.o \ +efi_selftest_devicepath.o \ efi_selftest_events.o \ efi_selftest_exitbootservices.o \ efi_selftest_gop.o \ diff --git a/lib/efi_selftest/efi_selftest_devicepath.c b/lib/efi_selftest/efi_selftest_devicepath.c new file mode 100644 index 0000000000..1ab54ebb37 --- /dev/null +++ b/lib/efi_selftest/efi_selftest_devicepath.c @@ -0,0 +1,390 @@ +/* + * efi_selftest_devicepath + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This unit test checks the following protocol services: + * DevicePathToText + */ + +#include + +static struct efi_boot_services *boottime; + +static efi_handle_t handle1; +static efi_handle_t handle2; +static efi_handle_t handle3; + +struct interface { + void (EFIAPI * inc)(void); +} interface; + +static efi_guid_t guid_device_path = DEVICE_PATH_GUID; + +static efi_guid_t guid_device_path_to_text_protocol = + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID; + +static efi_guid_t guid_protocol = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0x7d); + +static efi_guid_t guid_vendor1 = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xb1); + +static efi_guid_t guid_vendor2 = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xa2); + +static efi_guid_t guid_vendor3 = + EFI_GUID(0xdbca4c98, 0x6cb0, 0x694d, + 0x08, 0x72, 0x81, 0x9c, 0x65, 0x0c, 0xbb, 0xc3); + +static u8 *dp1; +static u8 *dp2; +static u8 *dp3; + +struct efi_device_path_to_text_protocol *device_path_to_text; + +/* + * Setup unit test. + * + * Create three handles. Install a new protocol on two of them and + * provice device paths. + * + * handle1 + * guid interface + * handle2 + * guid interface + * handle3 + * + * @handle: handle of the loaded image + * @systable: system table + */ +static int setup(const efi_handle_t img_handle, + const struct efi_system_table *systable) +{ + struct efi_device_path_vendor vendor_node; + struct efi_device_path end_node; + efi_status_t ret; + + boottime = systable->boottime; + + ret = boottime->locate_protocol(&guid_device_path_to_text_protocol, + NULL, (void **)&device_path_to_text); + if (ret != EFI_SUCCESS) { + device_path_to_text = NULL; + efi_st_error( + "Device path to text protocol is not available.\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->allocate_pool(EFI_LOADER_DATA, + sizeof(struct efi_device_path_vendor) + + sizeof(struct efi_device_path), + (void **)&dp1); + if (ret != EFI_SUCCESS) + goto out_of_memory; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, 2 * + sizeof(struct efi_device_path_vendor) + + sizeof(struct efi_device_path), + (void **)&dp2); + if (ret != EFI_SUCCESS) + goto out_of_memory; + + ret = boottime->allocate_pool(EFI_LOADER_DATA, 3 * + sizeof(struct efi_device_path_vendor) + + sizeof(struct efi_device_path), + (void **)&dp3); + if (ret != EFI_SUCCESS) + goto out_of_memory; + + vendor_node.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + vendor_node.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR; + vendor_node.dp.length = sizeof(struct efi_device_path_vendor); + + boottime->copy_mem(&vendor_node.guid, &guid_vendor1, + sizeof(efi_guid_t)); + boottime->copy_mem(dp1, &vendor_node, + sizeof(struct efi_device_path_vendor)); + boottime->copy_mem(dp2, &vendor_node, + sizeof(struct efi_device_path_vendor)); + boottime->copy_mem(dp3, &vendor_node, + sizeof(struct efi_device_path_vendor)); + + boottime->copy_mem(&vendor_node.guid, &guid_vendor2, + sizeof(efi_guid_t)); + boottime->copy_mem(dp2 + sizeof(struct efi_device_path_vendor), + &vendor_node, sizeof(struct efi_device_path_vendor)); + boottime->copy_mem(dp3 + sizeof(struct efi_device_path_vendor), + &vendor_node, sizeof(struct efi_device_path_vendor)); + + boottime->copy_mem(&vendor_node.guid, &guid_vendor3, + sizeof(efi_guid_t)); + boottime->copy_mem(dp3 + 2 * sizeof(struct efi_device_path_vendor), + &vendor_node, sizeof(struct efi_device_path_vendor)); + + end_node.type = DEVICE_PATH_TYPE_END; + end_node.sub_type = DEVICE_PATH_SUB_TYPE_END; + end_node.length = sizeof(struct efi_device_path); + boottime->copy_mem(dp1 + sizeof(struct efi_device_path_vendor), + &end_node, sizeof(struct efi_device_path)); + boottime->copy_mem(dp2 + 2 * sizeof(struct efi_device_path_vendor), + &end_node, sizeof(struct efi_device_path)); + boottime->copy_mem(dp3 + 3 * sizeof(struct efi_device_path_vendor), + &end_node, sizeof(struct efi_device_path)); + + ret = boottime->install_protocol_interface(&handle1, + &guid_device_path, + EFI_NATIVE_INTERFACE, + dp1); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle1, + &guid_protocol, + EFI_NATIVE_INTERFACE, + &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle2, + &guid_device_path, + EFI_NATIVE_INTERFACE, + dp2); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle2, + &guid_protocol, + EFI_NATIVE_INTERFACE, + &interface); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->install_protocol_interface(&handle3, + &guid_device_path, + EFI_NATIVE_INTERFACE, + dp3); + if (ret != EFI_SUCCESS) { + efi_st_error("InstallProtocolInterface failed\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; + +out_of_memory: + efi_st_error("Out of memory\n"); + return EFI_ST_FAILURE; +} + +/* + * Tear down unit test. + * + */ +static int teardown(void) +{ + efi_status_t ret; + + ret = boottime->uninstall_protocol_interface(&handle1, + &guid_device_path, + dp1); + if (ret != EFI_SUCCESS) + efi_st_todo("UninstallProtocolInterface failed\n"); + ret = boottime->uninstall_protocol_interface(&handle1, + &guid_protocol, + &interface); + if (ret != EFI_SUCCESS) + efi_st_todo("UninstallProtocolInterface failed\n"); + ret = boottime->uninstall_protocol_interface(&handle2, + &guid_device_path, + dp2); + if (ret != EFI_SUCCESS) + efi_st_todo("UninstallProtocolInterface failed\n"); + ret = boottime->uninstall_protocol_interface(&handle2, + &guid_protocol, + &interface); + if (ret != EFI_SUCCESS) + efi_st_todo("UninstallProtocolInterface failed\n"); + ret = boottime->uninstall_protocol_interface(&handle3, + &guid_device_path, + dp3); + if (ret != EFI_SUCCESS) + efi_st_todo("UninstallProtocolInterface failed\n"); + if (dp1) { + ret = boottime->free_pool(dp1); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + if (dp2) { + ret = boottime->free_pool(dp2); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + if (dp3) { + ret = boottime->free_pool(dp3); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + */ +static int execute(void) +{ + struct efi_device_path *remaining_dp; + void *handle; + /* + * This device path node ends with the letter 't' of 'u-boot'. + * The following '.bin' does not belong to the node but is + * helps to test the correct truncation. + */ + struct { + struct efi_device_path dp; + u16 text[12]; + } __packed dp_node = { + { DEVICE_PATH_TYPE_MEDIA_DEVICE, + DEVICE_PATH_SUB_TYPE_FILE_PATH, + sizeof(struct efi_device_path) + 12}, + L"u-boot.bin", + }; + u16 *string; + efi_status_t ret; + efi_uintn_t i, no_handles; + efi_handle_t *handles; + struct efi_device_path *dp; + + /* Display all available device paths */ + ret = boottime->locate_handle_buffer(BY_PROTOCOL, + &guid_device_path, + NULL, &no_handles, &handles); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot retrieve device path protocols.\n"); + return EFI_ST_FAILURE; + } + + efi_st_printf("Installed device path protocols:\n"); + for (i = 0; i < no_handles; ++i) { + ret = boottime->open_protocol(handles[i], &guid_device_path, + (void **)&dp, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + efi_st_error("Cannot open device path protocol.\n"); + return EFI_ST_FAILURE; + } + string = device_path_to_text->convert_device_path_to_text( + dp, true, false); + if (!string) { + efi_st_error("ConvertDevicePathToText failed\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("%ps\n", string); + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + ret = boottime->close_protocol(handles[i], &guid_device_path, + NULL, NULL); + if (ret != EFI_SUCCESS) + efi_st_todo("Cannot close device path protocol.\n"); + } + ret = boottime->free_pool(handles); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("\n"); + + /* Test ConvertDevicePathToText */ + string = device_path_to_text->convert_device_path_to_text( + (struct efi_device_path *)dp2, true, false); + if (!string) { + efi_st_error("ConvertDevicePathToText failed\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("dp2: %ps\n", string); + if (efi_st_strcmp_16_8( + string, + "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbb1)/VenHw(dbca4c98-6cb0-694d-0872-819c650cbba2)") + ) { + efi_st_error("Incorrect text from ConvertDevicePathToText\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + + /* Test ConvertDeviceNodeToText */ + string = device_path_to_text->convert_device_node_to_text( + (struct efi_device_path *)&dp_node, true, false); + if (!string) { + efi_st_error("ConvertDeviceNodeToText failed\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("dp_node: %ps\n", string); + ret = boottime->free_pool(string); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool failed\n"); + return EFI_ST_FAILURE; + } + if (efi_st_strcmp_16_8(string, "u-boot")) { + efi_st_error( + "Incorrect conversion by ConvertDeviceNodeToText\n"); + return EFI_ST_FAILURE; + } + + /* Test LocateDevicePath */ + remaining_dp = (struct efi_device_path *)dp3; + ret = boottime->locate_device_path(&guid_protocol, &remaining_dp, + &handle); + if (ret != EFI_SUCCESS) { + efi_st_error("LocateDevicePath failed\n"); + return EFI_ST_FAILURE; + } + if (handle != handle2) { + efi_st_error("LocateDevicePath returned wrong handle\n"); + return EFI_ST_FAILURE; + } + string = device_path_to_text->convert_device_path_to_text(remaining_dp, + true, false); + if (!string) { + efi_st_error("ConvertDevicePathToText failed\n"); + return EFI_ST_FAILURE; + } + efi_st_printf("remaining device path: %ps\n", string); + if (efi_st_strcmp_16_8(string, + "/VenHw(dbca4c98-6cb0-694d-0872-819c650cbbc3)") + ) { + efi_st_error("LocateDevicePath: wrong remaining device path\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(devicepath) = { + .name = "device path", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; -- cgit v1.2.1 From 4b9f7aaf7c33eee196b7d203b99c2cdf2eaec803 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:12 +0100 Subject: efi_loader: efi_disk: use efi_add_protocol Use efi_add_protocol to install protocols. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index c6f0d732c1..1d6cf3122f 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -213,33 +213,40 @@ static void efi_disk_add_dev(const char *name, unsigned int part) { struct efi_disk_obj *diskobj; + efi_status_t ret; /* Don't add empty devices */ if (!desc->lba) return; diskobj = calloc(1, sizeof(*diskobj)); - if (!diskobj) { - printf("ERROR: Out of memory\n"); - return; - } + if (!diskobj) + goto out_of_memory; + + /* Hook up to the device list */ + list_add_tail(&diskobj->parent.link, &efi_obj_list); /* Fill in object data */ diskobj->dp = efi_dp_from_part(desc, part); diskobj->part = part; - diskobj->parent.protocols[0].guid = &efi_block_io_guid; - diskobj->parent.protocols[0].protocol_interface = &diskobj->ops; - diskobj->parent.protocols[1].guid = &efi_guid_device_path; - diskobj->parent.protocols[1].protocol_interface = diskobj->dp; + diskobj->parent.handle = diskobj; + ret = efi_add_protocol(diskobj->parent.handle, &efi_block_io_guid, + &diskobj->ops); + if (ret != EFI_SUCCESS) + goto out_of_memory; + ret = efi_add_protocol(diskobj->parent.handle, &efi_guid_device_path, + diskobj->dp); + if (ret != EFI_SUCCESS) + goto out_of_memory; if (part >= 1) { diskobj->volume = efi_simple_file_system(desc, part, diskobj->dp); - diskobj->parent.protocols[2].guid = - &efi_simple_file_system_protocol_guid; - diskobj->parent.protocols[2].protocol_interface = - diskobj->volume; + ret = efi_add_protocol(diskobj->parent.handle, + &efi_simple_file_system_protocol_guid, + &diskobj->volume); + if (ret != EFI_SUCCESS) + goto out_of_memory; } - diskobj->parent.handle = diskobj; diskobj->ops = block_io_disk_template; diskobj->ifname = if_typename; diskobj->dev_index = dev_index; @@ -253,9 +260,9 @@ static void efi_disk_add_dev(const char *name, diskobj->media.io_align = desc->blksz; diskobj->media.last_block = desc->lba - offset; diskobj->ops.media = &diskobj->media; - - /* Hook up to the device list */ - list_add_tail(&diskobj->parent.link, &efi_obj_list); + return; +out_of_memory: + printf("ERROR: Out of memory\n"); } static int efi_disk_create_eltorito(struct blk_desc *desc, -- cgit v1.2.1 From 84d14568ca1a70ffd8925c357e3db2a6a8437922 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:13 +0100 Subject: efi_loader: efi_net: use efi_add_protocol Use efi_add_protocol to add protocols. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index a7b101e830..8b2f682351 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -292,20 +292,26 @@ int efi_net_register(void) /* We only expose the "active" eth device, so one is enough */ netobj = calloc(1, sizeof(*netobj)); - if (!netobj) { - printf("ERROR: Out of memory\n"); - return 1; - } + if (!netobj) + goto out_of_memory; + + /* Hook net up to the device list */ + list_add_tail(&netobj->parent.link, &efi_obj_list); /* Fill in object data */ - netobj->parent.protocols[0].guid = &efi_net_guid; - netobj->parent.protocols[0].protocol_interface = &netobj->net; - netobj->parent.protocols[1].guid = &efi_guid_device_path; - netobj->parent.protocols[1].protocol_interface = - efi_dp_from_eth(); - netobj->parent.protocols[2].guid = &efi_pxe_guid; - netobj->parent.protocols[2].protocol_interface = &netobj->pxe; netobj->parent.handle = &netobj->net; + r = efi_add_protocol(netobj->parent.handle, &efi_net_guid, + &netobj->net); + if (r != EFI_SUCCESS) + goto out_of_memory; + r = efi_add_protocol(netobj->parent.handle, &efi_guid_device_path, + efi_dp_from_eth()); + if (r != EFI_SUCCESS) + goto out_of_memory; + r = efi_add_protocol(netobj->parent.handle, &efi_pxe_guid, + &netobj->pxe); + if (r != EFI_SUCCESS) + goto out_of_memory; netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; netobj->net.start = efi_net_start; netobj->net.stop = efi_net_stop; @@ -330,9 +336,6 @@ int efi_net_register(void) if (dhcp_ack) netobj->pxe_mode.dhcp_ack = *dhcp_ack; - /* Hook net up to the device list */ - list_add_tail(&netobj->parent.link, &efi_obj_list); - /* * Create WaitForPacket event. */ @@ -365,4 +368,7 @@ int efi_net_register(void) } return 0; +out_of_memory: + printf("ERROR: Out of memory\n"); + return 1; } -- cgit v1.2.1 From 9449358a71b7dfd96ed9f3fbd276d4a19daef1b5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:14 +0100 Subject: efi_loader: efi_gop: use efi_add_protocol Use efi_add_protocol to add protocol. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_gop.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 7370eeee37..7b74d6ef33 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -132,6 +132,7 @@ int efi_gop_register(void) u32 bpix, col, row; u64 fb_base, fb_size; void *fb; + efi_status_t ret; #ifdef CONFIG_DM_VIDEO struct udevice *vdev; @@ -178,10 +179,17 @@ int efi_gop_register(void) return 1; } + /* Hook up to the device list */ + list_add_tail(&gopobj->parent.link, &efi_obj_list); + /* Fill in object data */ - gopobj->parent.protocols[0].guid = &efi_gop_guid; - gopobj->parent.protocols[0].protocol_interface = &gopobj->ops; gopobj->parent.handle = &gopobj->ops; + ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid, + &gopobj->ops); + if (ret != EFI_SUCCESS) { + printf("ERROR: Out of memory\n"); + return 1; + } gopobj->ops.query_mode = gop_query_mode; gopobj->ops.set_mode = gop_set_mode; gopobj->ops.blt = gop_blt; @@ -210,8 +218,5 @@ int efi_gop_register(void) gopobj->bpix = bpix; gopobj->fb = fb; - /* Hook up to the device list */ - list_add_tail(&gopobj->parent.link, &efi_obj_list); - return 0; } -- cgit v1.2.1 From 80286e8f811341e6054a85b69e2573a778ba42cf Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:15 +0100 Subject: efi_loader: simplify efi_open_protocol Use function efi_search_protocol. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 36 ++++++------------------------------ 1 file changed, 6 insertions(+), 30 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 565addfc3f..4cc5b1e620 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2051,8 +2051,7 @@ static efi_status_t EFIAPI efi_open_protocol( void **protocol_interface, void *agent_handle, void *controller_handle, uint32_t attributes) { - struct list_head *lhandle; - int i; + struct efi_handler *handler; efi_status_t r = EFI_INVALID_PARAMETER; EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol, @@ -2065,8 +2064,6 @@ static efi_status_t EFIAPI efi_open_protocol( goto out; } - EFI_PRINT_GUID("protocol", protocol); - switch (attributes) { case EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL: case EFI_OPEN_PROTOCOL_GET_PROTOCOL: @@ -2087,33 +2084,12 @@ static efi_status_t EFIAPI efi_open_protocol( goto out; } - list_for_each(lhandle, &efi_obj_list) { - struct efi_object *efiobj; - efiobj = list_entry(lhandle, struct efi_object, link); - - if (efiobj->handle != handle) - continue; - - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - struct efi_handler *handler = &efiobj->protocols[i]; - const efi_guid_t *hprotocol = handler->guid; - if (!hprotocol) - continue; - if (!guidcmp(hprotocol, protocol)) { - if (attributes != - EFI_OPEN_PROTOCOL_TEST_PROTOCOL) { - *protocol_interface = - handler->protocol_interface; - } - r = EFI_SUCCESS; - goto out; - } - } - goto unsupported; - } + r = efi_search_protocol(handle, protocol, &handler); + if (r != EFI_SUCCESS) + goto out; -unsupported: - r = EFI_UNSUPPORTED; + if (attributes != EFI_OPEN_PROTOCOL_TEST_PROTOCOL) + *protocol_interface = handler->protocol_interface; out: return EFI_EXIT(r); } -- cgit v1.2.1 From 72292aba4f0b4857f0951bd670d08d9d73b2d6b2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:16 +0100 Subject: efi_loader: simplify find_obj Use function efi_search_protocol(). Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path.c | 43 ++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 9027ae8efb..b4e2f933cb 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -128,32 +128,27 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path, struct efi_object *efiobj; list_for_each_entry(efiobj, &efi_obj_list, link) { - int i; - - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - struct efi_handler *handler = &efiobj->protocols[i]; - struct efi_device_path *obj_dp; - - if (!handler->guid) - break; - - if (guidcmp(handler->guid, &efi_guid_device_path)) - continue; - - obj_dp = handler->protocol_interface; - - do { - if (efi_dp_match(dp, obj_dp) == 0) { - if (rem) { - *rem = ((void *)dp) + - efi_dp_size(obj_dp); - } - return efiobj; + struct efi_handler *handler; + struct efi_device_path *obj_dp; + efi_status_t ret; + + ret = efi_search_protocol(efiobj->handle, + &efi_guid_device_path, &handler); + if (ret != EFI_SUCCESS) + continue; + obj_dp = handler->protocol_interface; + + do { + if (efi_dp_match(dp, obj_dp) == 0) { + if (rem) { + *rem = ((void *)dp) + + efi_dp_size(obj_dp); } + return efiobj; + } - obj_dp = shorten_path(efi_dp_next(obj_dp)); - } while (short_path && obj_dp); - } + obj_dp = shorten_path(efi_dp_next(obj_dp)); + } while (short_path && obj_dp); } return NULL; -- cgit v1.2.1 From 69fb6b1afcf37d3f68c6e0614658cfc023410e09 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:17 +0100 Subject: efi_loader: manage protocols in a linked list Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 107 ++++++++++++++++++++---------------------- lib/efi_loader/efi_disk.c | 1 + lib/efi_loader/efi_gop.c | 1 + lib/efi_loader/efi_net.c | 1 + 4 files changed, 54 insertions(+), 56 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 4cc5b1e620..54e9c27db1 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -339,6 +339,7 @@ efi_status_t efi_create_handle(void **handle) return r; memset(obj, 0, sizeof(struct efi_object)); obj->handle = obj; + INIT_LIST_HEAD(&obj->protocols); list_add_tail(&obj->link, &efi_obj_list); *handle = obj; return r; @@ -715,18 +716,17 @@ efi_status_t efi_search_protocol(const void *handle, struct efi_handler **handler) { struct efi_object *efiobj; - size_t i; - struct efi_handler *protocol; + struct list_head *lhandle; if (!handle || !protocol_guid) return EFI_INVALID_PARAMETER; efiobj = efi_search_obj(handle); if (!efiobj) return EFI_INVALID_PARAMETER; - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - protocol = &efiobj->protocols[i]; - if (!protocol->guid) - continue; + list_for_each(lhandle, &efiobj->protocols) { + struct efi_handler *protocol; + + protocol = list_entry(lhandle, struct efi_handler, link); if (!guidcmp(protocol->guid, protocol_guid)) { if (handler) *handler = protocol; @@ -750,7 +750,6 @@ efi_status_t efi_add_protocol(const void *handle, const efi_guid_t *protocol, struct efi_object *efiobj; struct efi_handler *handler; efi_status_t ret; - size_t i; efiobj = efi_search_obj(handle); if (!efiobj) @@ -761,16 +760,10 @@ efi_status_t efi_add_protocol(const void *handle, const efi_guid_t *protocol, handler = calloc(1, sizeof(struct efi_handler)); if (!handler) return EFI_OUT_OF_RESOURCES; - /* Install protocol in first empty slot. */ - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - handler = &efiobj->protocols[i]; - if (handler->guid) - continue; - handler->guid = protocol; - handler->protocol_interface = protocol_interface; - return EFI_SUCCESS; - } - return EFI_OUT_OF_RESOURCES; + handler->guid = protocol; + handler->protocol_interface = protocol_interface; + list_add_tail(&handler->link, &efiobj->protocols); + return EFI_SUCCESS; } /* @@ -790,10 +783,10 @@ efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol, ret = efi_search_protocol(handle, protocol, &handler); if (ret != EFI_SUCCESS) return ret; - if (handler->protocol_interface != protocol_interface) - return EFI_NOT_FOUND; - handler->guid = NULL; - handler->protocol_interface = NULL; + if (guidcmp(handler->guid, protocol)) + return EFI_INVALID_PARAMETER; + list_del(&handler->link); + free(handler); return EFI_SUCCESS; } @@ -806,17 +799,22 @@ efi_status_t efi_remove_protocol(const void *handle, const efi_guid_t *protocol, efi_status_t efi_remove_all_protocols(const void *handle) { struct efi_object *efiobj; - struct efi_handler *handler; - size_t i; + struct list_head *lhandle; + struct list_head *pos; efiobj = efi_search_obj(handle); if (!efiobj) return EFI_INVALID_PARAMETER; + list_for_each_safe(lhandle, pos, &efiobj->protocols) { + struct efi_handler *protocol; + efi_status_t ret; - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - handler = &efiobj->protocols[i]; - handler->guid = NULL; - handler->protocol_interface = NULL; + protocol = list_entry(lhandle, struct efi_handler, link); + + ret = efi_remove_protocol(handle, protocol->guid, + protocol->protocol_interface); + if (ret != EFI_SUCCESS) + return ret; } return EFI_SUCCESS; } @@ -1171,6 +1169,7 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob if (device_path) info->device_handle = efi_dp_find_obj(device_path, NULL); + INIT_LIST_HEAD(&obj->protocols); list_add_tail(&obj->link, &efi_obj_list); /* * When asking for the device path interface, return @@ -1648,8 +1647,7 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, { unsigned long buffer_size; struct efi_object *efiobj; - unsigned long i, j; - struct list_head *lhandle; + struct list_head *protocol_handle; efi_status_t r; EFI_ENTRY("%p, %p, %p", handle, protocol_buffer, @@ -1660,36 +1658,33 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, *protocol_buffer = NULL; *protocol_buffer_count = 0; - list_for_each(lhandle, &efi_obj_list) { - efiobj = list_entry(lhandle, struct efi_object, link); - if (efiobj->handle != handle) - continue; + efiobj = efi_search_obj(handle); + if (!efiobj) + return EFI_EXIT(EFI_INVALID_PARAMETER); - /* Count protocols */ - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); i++) { - if (efiobj->protocols[i].guid) - ++*protocol_buffer_count; - } - /* Copy guids */ - if (*protocol_buffer_count) { - buffer_size = sizeof(efi_guid_t *) * - *protocol_buffer_count; - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, - buffer_size, - (void **)protocol_buffer); - if (r != EFI_SUCCESS) - return EFI_EXIT(r); - j = 0; - for (i = 0; i < ARRAY_SIZE(efiobj->protocols); ++i) { - if (efiobj->protocols[i].guid) { - (*protocol_buffer)[j] = (void *) - efiobj->protocols[i].guid; - ++j; - } - } + /* Count protocols */ + list_for_each(protocol_handle, &efiobj->protocols) { + ++*protocol_buffer_count; + } + + /* Copy guids */ + if (*protocol_buffer_count) { + size_t j = 0; + + buffer_size = sizeof(efi_guid_t *) * *protocol_buffer_count; + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, buffer_size, + (void **)protocol_buffer); + if (r != EFI_SUCCESS) + return EFI_EXIT(r); + list_for_each(protocol_handle, &efiobj->protocols) { + struct efi_handler *protocol; + + protocol = list_entry(protocol_handle, + struct efi_handler, link); + (*protocol_buffer)[j] = (void *)protocol->guid; + ++j; } - break; } return EFI_EXIT(EFI_SUCCESS); diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 1d6cf3122f..af8db40e19 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -224,6 +224,7 @@ static void efi_disk_add_dev(const char *name, goto out_of_memory; /* Hook up to the device list */ + INIT_LIST_HEAD(&diskobj->parent.protocols); list_add_tail(&diskobj->parent.link, &efi_obj_list); /* Fill in object data */ diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 7b74d6ef33..498184d754 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -180,6 +180,7 @@ int efi_gop_register(void) } /* Hook up to the device list */ + INIT_LIST_HEAD(&gopobj->parent.protocols); list_add_tail(&gopobj->parent.link, &efi_obj_list); /* Fill in object data */ diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 8b2f682351..74a67c5365 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -296,6 +296,7 @@ int efi_net_register(void) goto out_of_memory; /* Hook net up to the device list */ + INIT_LIST_HEAD(&netobj->parent.protocols); list_add_tail(&netobj->parent.link, &efi_obj_list); /* Fill in object data */ -- cgit v1.2.1 From 17b96cb2ba38442ef8241cb4074864864c03122e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:18 +0100 Subject: efi_selftest: compile without special compiler flags As the selftest is not compiled as an EFI binary we do not need special compiler flags. This avoids the checkarmreloc error on vexpress_ca15_tc2. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index d280eca5c3..837e86228e 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -7,31 +7,6 @@ # This file only gets included with CONFIG_EFI_LOADER set, so all # object inclusion implicitly depends on it -CFLAGS_efi_selftest.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_console.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_console.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_devicepathe.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_devicepath.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_events.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_events.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_exitbootservices.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_exitbootservices.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_gop.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_gop.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_manageprotocols.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_manageprotocols.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_snp.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_snp.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_textoutput.o := $(CFLAGS_EFI) -CFLAGS_REVMOE_efi_selftest_textoutput.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_tpl.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_tpl.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_util.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_util.o := $(CFLAGS_NON_EFI) -CFLAGS_efi_selftest_watchdog.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_efi_selftest_watchdog.o := $(CFLAGS_NON_EFI) - obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ efi_selftest_console.o \ -- cgit v1.2.1 From c51e7df941c9d4a75d25505a9b0435f543edcf34 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:19 +0100 Subject: efi_selftest: add missing line feed Add a missing line feed for an error message. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 263b53f672..4e5a12c47c 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -239,7 +239,7 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, ret = boottime->handle_protocol(image_handle, &efi_guid_loaded_image, (void **)&loaded_image); if (ret != EFI_SUCCESS) { - efi_st_error("Cannot open loaded image protocol"); + efi_st_error("Cannot open loaded image protocol\n"); return ret; } -- cgit v1.2.1 From bbf75dd9345d0b1a7ec7a50016547eb7c759b7af Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:20 +0100 Subject: efi_loader: output load options in helloworld We need to test if we pass a valid image handle when loading and EFI application. This cannot be done in efi_selftest as it is not loaded as an image. So let's enhance helloworld a bit. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/helloworld.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 77130a36dd..e59c24c788 100644 --- a/lib/efi_loader/helloworld.c +++ b/lib/efi_loader/helloworld.c @@ -5,19 +5,52 @@ * Written by Simon Glass * * SPDX-License-Identifier: GPL-2.0+ + * + * This program demonstrates calling a boottime service. + * It writes a greeting and the load options to the console. */ #include #include +/* + * Entry point of the EFI application. + * + * @handle handle of the loaded image + * @systable system table + * @return status code + */ efi_status_t EFIAPI efi_main(efi_handle_t handle, struct efi_system_table *systable) { struct efi_simple_text_output_protocol *con_out = systable->con_out; struct efi_boot_services *boottime = systable->boottime; + struct efi_loaded_image *loaded_image; + const efi_guid_t loaded_image_guid = LOADED_IMAGE_GUID; + efi_status_t ret; con_out->output_string(con_out, L"Hello, world!\n"); - boottime->exit(handle, 0, 0, NULL); - return EFI_SUCCESS; + /* Get the loaded image protocol */ + ret = boottime->handle_protocol(handle, &loaded_image_guid, + (void **)&loaded_image); + if (ret != EFI_SUCCESS) { + con_out->output_string(con_out, + L"Cannot open loaded image protocol\n"); + goto out; + } + /* Output the load options */ + con_out->output_string(con_out, L"Load options: "); + if (loaded_image->load_options_size && loaded_image->load_options) + con_out->output_string(con_out, + (u16 *)loaded_image->load_options); + else + con_out->output_string(con_out, L""); + con_out->output_string(con_out, L"\n"); + +out: + boottime->exit(handle, ret, 0, NULL); + + /* We should never arrive here */ + return ret; } -- cgit v1.2.1 From ea54ad59286efe7e600f3e189036fa96989eace4 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:22 +0100 Subject: efi_loader: pass handle of loaded image The handle of a loaded image is the value of the handle member of the loaded image info object and not the address of the loaded image info. Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- 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 54e9c27db1..0fb2848ecf 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1317,7 +1317,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, info->system_table = &systab; info->parent_handle = parent_image; - *image_handle = info; + *image_handle = obj->handle; return EFI_EXIT(EFI_SUCCESS); } -- cgit v1.2.1 From 44549d62c31dc433366b4c5d6e58e0e3091e542b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 26 Nov 2017 14:05:23 +0100 Subject: efi_loader: helper function to add EFI object to list To avoid duplicate coding provide a helper function that initializes an EFI object and adds it to the EFI object list. efi_exit() is the only place where we dereference a handle to obtain a protocol interface. Add a comment to the function. Suggested-by: Alexander Graf Reviewed-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 40 +++++++++++++++++++++++++++++++++------- lib/efi_loader/efi_disk.c | 4 +--- lib/efi_loader/efi_gop.c | 4 +--- lib/efi_loader/efi_net.c | 4 +--- 4 files changed, 36 insertions(+), 16 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 0fb2848ecf..a37fb25638 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -321,6 +321,23 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) return EFI_EXIT(r); } +/* + * Add a new object to the object list. + * + * The protocols list is initialized. + * The object handle is set. + * + * @obj object to be added + */ +void efi_add_handle(struct efi_object *obj) +{ + if (!obj) + return; + INIT_LIST_HEAD(&obj->protocols); + obj->handle = obj; + list_add_tail(&obj->link, &efi_obj_list); +} + /* * Create handle. * @@ -337,11 +354,8 @@ efi_status_t efi_create_handle(void **handle) (void **)&obj); if (r != EFI_SUCCESS) return r; - memset(obj, 0, sizeof(struct efi_object)); - obj->handle = obj; - INIT_LIST_HEAD(&obj->protocols); - list_add_tail(&obj->link, &efi_obj_list); - *handle = obj; + efi_add_handle(obj); + *handle = obj->handle; return r; } @@ -1163,14 +1177,15 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob { efi_status_t ret; + /* Add internal object to object list */ + efi_add_handle(obj); + /* efi_exit() assumes that the handle points to the info */ obj->handle = info; info->file_path = file_path; if (device_path) info->device_handle = efi_dp_find_obj(device_path, NULL); - INIT_LIST_HEAD(&obj->protocols); - list_add_tail(&obj->link, &efi_obj_list); /* * When asking for the device path interface, return * bootefi_device_path @@ -1379,6 +1394,17 @@ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, efi_status_t exit_status, unsigned long exit_data_size, int16_t *exit_data) { + /* + * We require that the handle points to the original loaded + * image protocol interface. + * + * For getting the longjmp address this is safer than locating + * the protocol because the protocol may have been reinstalled + * pointing to another memory location. + * + * TODO: We should call the unload procedure of the loaded + * image protocol. + */ struct efi_loaded_image *loaded_image_info = (void*)image_handle; EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status, diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index af8db40e19..68ba2cf7b2 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -224,13 +224,11 @@ static void efi_disk_add_dev(const char *name, goto out_of_memory; /* Hook up to the device list */ - INIT_LIST_HEAD(&diskobj->parent.protocols); - list_add_tail(&diskobj->parent.link, &efi_obj_list); + efi_add_handle(&diskobj->parent); /* Fill in object data */ diskobj->dp = efi_dp_from_part(desc, part); diskobj->part = part; - diskobj->parent.handle = diskobj; ret = efi_add_protocol(diskobj->parent.handle, &efi_block_io_guid, &diskobj->ops); if (ret != EFI_SUCCESS) diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index 498184d754..3caddd5f84 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -180,11 +180,9 @@ int efi_gop_register(void) } /* Hook up to the device list */ - INIT_LIST_HEAD(&gopobj->parent.protocols); - list_add_tail(&gopobj->parent.link, &efi_obj_list); + efi_add_handle(&gopobj->parent); /* Fill in object data */ - gopobj->parent.handle = &gopobj->ops; ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid, &gopobj->ops); if (ret != EFI_SUCCESS) { diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 74a67c5365..8c5d5b492c 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -296,11 +296,9 @@ int efi_net_register(void) goto out_of_memory; /* Hook net up to the device list */ - INIT_LIST_HEAD(&netobj->parent.protocols); - list_add_tail(&netobj->parent.link, &efi_obj_list); + efi_add_handle(&netobj->parent); /* Fill in object data */ - netobj->parent.handle = &netobj->net; r = efi_add_protocol(netobj->parent.handle, &efi_net_guid, &netobj->net); if (r != EFI_SUCCESS) -- cgit v1.2.1 From c4574208b0bc7aa7d50407250074b1651de3c84c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 23 Nov 2017 22:21:58 +0100 Subject: efi_loader: comments for EFI_DEVICE_PATH_TO_TEXT_PROTOCOL Provide comments for efi_convert_device_node_to_text() and efi_convert_device_path_to_text(). Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path_to_text.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 43af5dfd8d..9e62e4a929 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -218,6 +218,18 @@ static char *efi_convert_single_device_node_to_text( return str; } +/* + * This function implements the ConvertDeviceNodeToText service of the + * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * device_node device node to be converted + * display_only true if the shorter text represenation shall be used + * allow_shortcuts true if shortcut forms may be used + * @return text represenation of the device path + * NULL if out of memory of device_path is NULL + */ static uint16_t EFIAPI *efi_convert_device_node_to_text( struct efi_device_path *device_node, bool display_only, @@ -239,6 +251,18 @@ out: return text; } +/* + * This function implements the ConvertDevicePathToText service of the + * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * device_path device path to be converted + * display_only true if the shorter text represenation shall be used + * allow_shortcuts true if shortcut forms may be used + * @return text represenation of the device path + * NULL if out of memory of device_path is NULL + */ static uint16_t EFIAPI *efi_convert_device_path_to_text( struct efi_device_path *device_path, bool display_only, -- cgit v1.2.1 From 1a0b4d22a99f9b296528118dec8211490f166ef9 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Thu, 30 Nov 2017 09:02:45 -0500 Subject: efi_loader: add missing breaks Otherwise with GUID partition types you would end up with things like: .../HD(Part0,Sig6252c819-4624-4995-8d16-abc9cd5d4130)/HD(Part0,MBRType=02,SigType=02) Signed-off-by: Rob Clark [agraf: rebased] Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path_to_text.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 9e62e4a929..7159c974d4 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -154,10 +154,12 @@ static char *dp_media(char *s, struct efi_device_path *dp) case SIG_TYPE_GUID: s += sprintf(s, "HD(Part%d,Sig%pUl)", hddp->partition_number, sig); + break; default: s += sprintf(s, "HD(Part%d,MBRType=%02x,SigType=%02x)", hddp->partition_number, hddp->partmap_type, hddp->signature_type); + break; } break; -- cgit v1.2.1 From c034b7fd419010116f2b6ac3b8e3b725f425d92c Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 1 Dec 2017 16:10:33 +0100 Subject: efi_loader: Fix partition offsets Commit 884bcf6f65 (efi_loader: use proper device-paths for partitions) tried to introduce the el torito scheme to all partition table types: Spawn individual disk objects for each partition on a disk. Unfortunately, that code ended up creating partitions with offset=0 which meant that anyone accessing these objects gets data from the raw block device instead of the partition. Furthermore, all the el torito logic to spawn devices for partitions was duplicated. So let's merge the two code paths and give partition disk objects good offsets to work from, so that payloads can actually make use of them. Fixes: 884bcf6f65 (efi_loader: use proper device-paths for partitions) Reported-by: Yousaf Kaukab Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 60 ++++++++++------------------------------------- 1 file changed, 13 insertions(+), 47 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 68ba2cf7b2..4e457a841b 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -264,21 +264,17 @@ out_of_memory: printf("ERROR: Out of memory\n"); } -static int efi_disk_create_eltorito(struct blk_desc *desc, - const char *if_typename, - int diskid, - const char *pdevname) +static int efi_disk_create_partitions(struct blk_desc *desc, + const char *if_typename, + int diskid, + const char *pdevname) { int disks = 0; -#if CONFIG_IS_ENABLED(ISO_PARTITION) char devname[32] = { 0 }; /* dp->str is u16[32] long */ disk_partition_t info; int part; - if (desc->part_type != PART_TYPE_ISO) - return 0; - - /* and devices for each partition: */ + /* Add devices for each partition */ for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) { if (part_get_info(desc, part, &info)) continue; @@ -289,10 +285,6 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, disks++; } - /* ... and add block device: */ - efi_disk_add_dev(devname, if_typename, desc, diskid, 0, 0); -#endif - return disks; } @@ -318,31 +310,18 @@ int efi_disk_register(void) uclass_next_device_check(&dev)) { struct blk_desc *desc = dev_get_uclass_platdata(dev); const char *if_typename = dev->driver->name; - disk_partition_t info; - int part; printf("Scanning disk %s...\n", dev->name); - /* add devices for each partition: */ - for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) { - if (part_get_info(desc, part, &info)) - continue; - efi_disk_add_dev(dev->name, if_typename, desc, - desc->devnum, 0, part); - } - - /* ... and add block device: */ + /* Add block device for the full device */ efi_disk_add_dev(dev->name, if_typename, desc, desc->devnum, 0, 0); disks++; - /* - * El Torito images show up as block devices in an EFI world, - * so let's create them here - */ - disks += efi_disk_create_eltorito(desc, if_typename, - desc->devnum, dev->name); + /* Partitions show up as block devices in EFI */ + disks += efi_disk_create_partitions(desc, if_typename, + desc->devnum, dev->name); } #else int i, if_type; @@ -361,8 +340,6 @@ int efi_disk_register(void) for (i = 0; i < 4; i++) { struct blk_desc *desc; char devname[32] = { 0 }; /* dp->str is u16[32] long */ - disk_partition_t info; - int part; desc = blk_get_devnum_by_type(if_type, i); if (!desc) @@ -373,24 +350,13 @@ int efi_disk_register(void) snprintf(devname, sizeof(devname), "%s%d", if_typename, i); - /* add devices for each partition: */ - for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) { - if (part_get_info(desc, part, &info)) - continue; - efi_disk_add_dev(devname, if_typename, desc, - i, 0, part); - } - - /* ... and add block device: */ + /* Add block device for the full device */ efi_disk_add_dev(devname, if_typename, desc, i, 0, 0); disks++; - /* - * El Torito images show up as block devices - * in an EFI world, so let's create them here - */ - disks += efi_disk_create_eltorito(desc, if_typename, - i, devname); + /* Partitions show up as block devices in EFI */ + disks += efi_disk_create_partitions(desc, if_typename, + i, devname); } } #endif -- cgit v1.2.1 From 3bb74f9800cdc4cf10a87f2725242c2565256654 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 1 Dec 2017 22:09:50 +0100 Subject: efi_loader helloworld.efi: Fix building with -Os Depending on your compiler, when compiling the hello world efi binary with -Os, gcc might think it's a smart idea to replace common patterns such as memory copies with explicit calls to memcpy(). While that sounds great at first, we don't have any memcpy() available in our helloworld build target. So let's indicate to gcc that we really do want to have the code be built as freestanding. Fixes: bbf75dd9 ("efi_loader: output load options in helloworld") Signed-off-by: Alexander Graf --- lib/efi_loader/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 83d879b686..2722265ee3 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -7,8 +7,8 @@ # This file only gets included with CONFIG_EFI_LOADER set, so all # object inclusion implicitly depends on it -CFLAGS_helloworld.o := $(CFLAGS_EFI) -CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) +CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding +CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) -Os ifneq ($(CONFIG_CMD_BOOTEFI_HELLO_COMPILE),) always += helloworld.efi -- cgit v1.2.1 From bb0bb91cf0aa2c13528fe39be2006f32f7b9c437 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 4 Dec 2017 16:33:51 +0100 Subject: efi_stub: Use efi_uintn_t Commit f5a2a93892f ("efi_loader: consistently use efi_uintn_t in boot services") changed the internal EFI API header without adapting its existing EFI stub users. Let's adapt the EFI stub as well. Fixes: f5a2a93892f ("efi_loader: consistently use efi_uintn_t in boot services") Signed-off-by: Alexander Graf Reviewed-by: Heinrich Schuchardt --- lib/efi/efi_stub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c index 1814960572..2e8d409d31 100644 --- a/lib/efi/efi_stub.c +++ b/lib/efi/efi_stub.c @@ -277,7 +277,7 @@ efi_status_t efi_main(efi_handle_t image, struct efi_system_table *sys_table) struct efi_boot_services *boot = sys_table->boottime; struct efi_mem_desc *desc; struct efi_entry_memmap map; - ulong key, desc_size, size; + efi_uintn_t key, desc_size, size; efi_status_t ret; u32 version; int cs32; -- cgit v1.2.1