From 3cc6e3fe9509d2b5eee6a698126acdde4746f0c6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 27 Aug 2017 00:51:09 +0200 Subject: efi_loader: allow creating new handles In efi_install_protocol_interface support creating a new handle. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Tested-by: Rob Clark Reviewed-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9e741c3cf3c..c8f39b5b10a 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -266,6 +266,23 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) return EFI_EXIT(r); } +static efi_status_t efi_create_handle(void **handle) +{ + struct efi_object *obj; + efi_status_t r; + + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, + sizeof(struct efi_object), + (void **)&obj); + if (r != EFI_SUCCESS) + return r; + memset(obj, 0, sizeof(struct efi_object)); + obj->handle = obj; + list_add_tail(&obj->link, &efi_obj_list); + *handle = obj; + return r; +} + /* * Our event capabilities are very limited. Only a small limited * number of events is allowed to coexist. @@ -520,8 +537,9 @@ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, /* Create new handle if requested. */ if (!*handle) { - r = EFI_OUT_OF_RESOURCES; - goto out; + r = efi_create_handle(handle); + if (r != EFI_SUCCESS) + goto out; } /* Find object. */ list_for_each(lhandle, &efi_obj_list) { -- cgit v1.2.3 From 037ee6f91bb06fb664d57668effdea7656edce25 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 4 Oct 2017 12:37:02 +0200 Subject: efi_selftest: use efi_st_error for all error messages All error messages in the selftests should use efi_st_error. efi_st_error will print the file name and line number of the error. Splitting message texts due to lines being over 80 characters is avoided. This resolves the issue reported by Simon Glass in https://lists.denx.de/pipermail/u-boot/2017-September/307387.html Reported-by: Simon Glass Fixes: 623b3a579765 efi_selftest: provide an EFI selftest application Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index efec832e987..ff00254c219 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -35,8 +35,8 @@ void efi_st_exit_boot_services(void) ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, &desc_version); if (ret != EFI_BUFFER_TOO_SMALL) { - efi_st_printf("ERROR: GetMemoryMap did not return " - "EFI_BUFFER_TOO_SMALL\n"); + efi_st_error( + "GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); return; } /* Allocate extra space for newly allocated memory */ @@ -44,21 +44,18 @@ void efi_st_exit_boot_services(void) ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, (void **)&memory_map); if (ret != EFI_SUCCESS) { - efi_st_printf("ERROR: AllocatePool did not return " - "EFI_SUCCESS\n"); + efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); return; } ret = boottime->get_memory_map(&map_size, memory_map, &map_key, &desc_size, &desc_version); if (ret != EFI_SUCCESS) { - efi_st_printf("ERROR: GetMemoryMap did not return " - "EFI_SUCCESS\n"); + efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); return; } ret = boottime->exit_boot_services(handle, map_key); if (ret != EFI_SUCCESS) { - efi_st_printf("ERROR: ExitBootServices did not return " - "EFI_SUCCESS\n"); + efi_st_error("ExitBootServices did not return EFI_SUCCESS\n"); return; } efi_st_printf("\nBoot services terminated\n"); @@ -79,7 +76,7 @@ static int setup(struct efi_unit_test *test, unsigned int *failures) efi_st_printf("\nSetting up '%s'\n", test->name); ret = test->setup(handle, systable); if (ret) { - efi_st_printf("ERROR: Setting up '%s' failed\n", test->name); + efi_st_error("Setting up '%s' failed\n", test->name); ++*failures; } else { efi_st_printf("Setting up '%s' succeeded\n", test->name); @@ -102,7 +99,7 @@ static int execute(struct efi_unit_test *test, unsigned int *failures) efi_st_printf("\nExecuting '%s'\n", test->name); ret = test->execute(); if (ret) { - efi_st_printf("ERROR: Executing '%s' failed\n", test->name); + efi_st_error("Executing '%s' failed\n", test->name); ++*failures; } else { efi_st_printf("Executing '%s' succeeded\n", test->name); @@ -125,7 +122,7 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures) efi_st_printf("\nTearing down '%s'\n", test->name); ret = test->teardown(); if (ret) { - efi_st_printf("ERROR: Tearing down '%s' failed\n", test->name); + efi_st_error("Tearing down '%s' failed\n", test->name); ++*failures; } else { efi_st_printf("Tearing down '%s' succeeded\n", test->name); @@ -213,7 +210,8 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, efi_st_get_key(); runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, sizeof(reset_message), reset_message); - efi_st_printf("\nERROR: reset failed.\n"); + efi_st_printf("\n"); + efi_st_error("Reset failed.\n"); return EFI_UNSUPPORTED; } -- cgit v1.2.3 From e190e8972faf4d5b09e2a92fefc54a1832fd67da Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 4 Oct 2017 15:03:24 +0200 Subject: efi_loader: use type bool for event states Queued and signaled describe boolean states of events. So let's use type bool and rename the structure members to is_queued and is_signaled. Update the comments for is_queued and is_signaled. Reported-by: Simon Glass Signed-off-by: Heinrich Schuchardt Reviewed-by: Rob Clark Reviewed-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 32 ++++++++++++++++---------------- lib/efi_loader/efi_console.c | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c8f39b5b10a..cb688e16e93 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -164,14 +164,14 @@ static u64 efi_div10(u64 a) void efi_signal_event(struct efi_event *event) { if (event->notify_function) { - event->queued = 1; + event->is_queued = true; /* Check TPL */ if (efi_tpl >= event->notify_tpl) return; EFI_CALL_VOID(event->notify_function(event, event->notify_context)); } - event->queued = 0; + event->is_queued = false; } static efi_status_t efi_unsupported(const char *funcname) @@ -316,8 +316,8 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, efi_events[i].notify_context = notify_context; /* Disable timers on bootup */ efi_events[i].trigger_next = -1ULL; - efi_events[i].queued = 0; - efi_events[i].signaled = 0; + efi_events[i].is_queued = false; + efi_events[i].is_signaled = false; *event = &efi_events[i]; return EFI_SUCCESS; } @@ -350,7 +350,7 @@ void efi_timer_check(void) for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { if (!efi_events[i].type) continue; - if (efi_events[i].queued) + if (efi_events[i].is_queued) efi_signal_event(&efi_events[i]); if (!(efi_events[i].type & EVT_TIMER) || now < efi_events[i].trigger_next) @@ -366,7 +366,7 @@ void efi_timer_check(void) default: continue; } - efi_events[i].signaled = 1; + efi_events[i].is_signaled = true; efi_signal_event(&efi_events[i]); } WATCHDOG_RESET(); @@ -403,7 +403,7 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, } event->trigger_type = type; event->trigger_time = trigger_time; - event->signaled = 0; + event->is_signaled = false; return EFI_SUCCESS; } return EFI_INVALID_PARAMETER; @@ -440,14 +440,14 @@ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, known_event: if (!event[i]->type || event[i]->type & EVT_NOTIFY_SIGNAL) return EFI_EXIT(EFI_INVALID_PARAMETER); - if (!event[i]->signaled) + if (!event[i]->is_signaled) efi_signal_event(event[i]); } /* Wait for signal */ for (;;) { for (i = 0; i < num_events; ++i) { - if (event[i]->signaled) + if (event[i]->is_signaled) goto out; } /* Allow events to occur. */ @@ -459,7 +459,7 @@ out: * Reset the signal which is passed to the caller to allow periodic * events to occur. */ - event[i]->signaled = 0; + event[i]->is_signaled = false; if (index) *index = i; @@ -474,9 +474,9 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { if (event != &efi_events[i]) continue; - if (event->signaled) + if (event->is_signaled) break; - event->signaled = 1; + event->is_signaled = true; if (event->type & EVT_NOTIFY_SIGNAL) efi_signal_event(event); break; @@ -493,8 +493,8 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) if (event == &efi_events[i]) { event->type = 0; event->trigger_next = -1ULL; - event->queued = 0; - event->signaled = 0; + event->is_queued = false; + event->is_signaled = false; return EFI_EXIT(EFI_SUCCESS); } } @@ -512,9 +512,9 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) continue; if (!event->type || event->type & EVT_NOTIFY_SIGNAL) break; - if (!event->signaled) + if (!event->is_signaled) efi_signal_event(event); - if (event->signaled) + if (event->is_signaled) return EFI_EXIT(EFI_SUCCESS); return EFI_EXIT(EFI_NOT_READY); } diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index fd5398d61d9..1bdf36b4ae7 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -460,7 +460,7 @@ static void EFIAPI efi_console_timer_notify(struct efi_event *event, { EFI_ENTRY("%p, %p", event, context); if (tstc()) { - efi_con_in.wait_for_key->signaled = 1; + efi_con_in.wait_for_key->is_signaled = true; efi_signal_event(efi_con_in.wait_for_key); } EFI_EXIT(EFI_SUCCESS); -- cgit v1.2.3 From e67e7249c8000d72b4c4b985fdeb3e103d65aa9e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 4 Oct 2017 15:31:26 +0200 Subject: efi_selftest: make tests easier to read Rename counter to more illustrative names. Update notification function description. Simplify notification function. Add comment for arbitrary non-zero value. Document @return. Use constants for return values of setup, execute, teardown. Reported-by: Simon Glass Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 15 +++-- lib/efi_selftest/efi_selftest_events.c | 80 ++++++++++++---------- lib/efi_selftest/efi_selftest_exitbootservices.c | 46 +++++++------ lib/efi_selftest/efi_selftest_tpl.c | 85 +++++++++++++----------- 4 files changed, 126 insertions(+), 100 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index ff00254c219..45d8d3d384c 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -66,16 +66,17 @@ void efi_st_exit_boot_services(void) * * @test the test to be executed * @failures counter that will be incremented if a failure occurs + * @return EFI_ST_SUCCESS for success */ static int setup(struct efi_unit_test *test, unsigned int *failures) { int ret; if (!test->setup) - return 0; + return EFI_ST_SUCCESS; efi_st_printf("\nSetting up '%s'\n", test->name); ret = test->setup(handle, systable); - if (ret) { + if (ret != EFI_ST_SUCCESS) { efi_st_error("Setting up '%s' failed\n", test->name); ++*failures; } else { @@ -89,16 +90,17 @@ static int setup(struct efi_unit_test *test, unsigned int *failures) * * @test the test to be executed * @failures counter that will be incremented if a failure occurs + * @return EFI_ST_SUCCESS for success */ static int execute(struct efi_unit_test *test, unsigned int *failures) { int ret; if (!test->execute) - return 0; + return EFI_ST_SUCCESS; efi_st_printf("\nExecuting '%s'\n", test->name); ret = test->execute(); - if (ret) { + if (ret != EFI_ST_SUCCESS) { efi_st_error("Executing '%s' failed\n", test->name); ++*failures; } else { @@ -112,16 +114,17 @@ static int execute(struct efi_unit_test *test, unsigned int *failures) * * @test the test to be torn down * @failures counter that will be incremented if a failure occurs + * @return EFI_ST_SUCCESS for success */ static int teardown(struct efi_unit_test *test, unsigned int *failures) { int ret; if (!test->teardown) - return 0; + return EFI_ST_SUCCESS; efi_st_printf("\nTearing down '%s'\n", test->name); ret = test->teardown(); - if (ret) { + if (ret != EFI_ST_SUCCESS) { efi_st_error("Tearing down '%s' failed\n", test->name); ++*failures; } else { diff --git a/lib/efi_selftest/efi_selftest_events.c b/lib/efi_selftest/efi_selftest_events.c index c4f66952b9f..532f165d437 100644 --- a/lib/efi_selftest/efi_selftest_events.c +++ b/lib/efi_selftest/efi_selftest_events.c @@ -14,20 +14,22 @@ static struct efi_event *event_notify; static struct efi_event *event_wait; -static unsigned int counter; +static unsigned int timer_ticks; static struct efi_boot_services *boottime; /* - * Notification function, increments a counter. + * Notification function, increments the notfication count if parameter + * context is provided. * * @event notified event - * @context pointer to the counter + * @context pointer to the notification count */ static void EFIAPI notify(struct efi_event *event, void *context) { - if (!context) - return; - ++*(unsigned int *)context; + unsigned int *count = context; + + if (count) + ++*count; } /* @@ -38,6 +40,7 @@ static void EFIAPI notify(struct efi_event *event, void *context) * * @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) @@ -47,25 +50,27 @@ static int setup(const efi_handle_t handle, boottime = systable->boottime; ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, notify, (void *)&counter, + TPL_CALLBACK, notify, (void *)&timer_ticks, &event_notify); if (ret != EFI_SUCCESS) { efi_st_error("could not create event\n"); - return 1; + 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 1; + return EFI_ST_FAILURE; } - return 0; + return EFI_ST_SUCCESS; } /* * Tear down unit test. * * Close the events created in setup. + * + * @return: EFI_ST_SUCCESS for success */ static int teardown(void) { @@ -76,7 +81,7 @@ static int teardown(void) event_notify = NULL; if (ret != EFI_SUCCESS) { efi_st_error("could not close event\n"); - return 1; + return EFI_ST_FAILURE; } } if (event_wait) { @@ -84,10 +89,10 @@ static int teardown(void) event_wait = NULL; if (ret != EFI_SUCCESS) { efi_st_error("could not close event\n"); - return 1; + return EFI_ST_FAILURE; } } - return 0; + return EFI_ST_SUCCESS; } /* @@ -98,6 +103,8 @@ static int teardown(void) * * Run a 100 ms single shot timer and check that it is called once * while waiting for 100 ms periodic timer for two periods. + * + * @return: EFI_ST_SUCCESS for success */ static int execute(void) { @@ -105,85 +112,86 @@ static int execute(void) efi_status_t ret; /* Set 10 ms timer */ - counter = 0; + timer_ticks = 0; ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); if (ret != EFI_SUCCESS) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } /* Set 100 ms timer */ ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); if (ret != EFI_SUCCESS) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } + /* Set some arbitrary non-zero value to make change detectable. */ index = 5; ret = boottime->wait_for_event(1, &event_wait, &index); if (ret != EFI_SUCCESS) { efi_st_error("Could not wait for event\n"); - return 1; + return EFI_ST_FAILURE; } ret = boottime->check_event(event_wait); if (ret != EFI_NOT_READY) { efi_st_error("Signaled state was not cleared.\n"); efi_st_printf("ret = %u\n", (unsigned int)ret); - return 1; + return EFI_ST_FAILURE; } if (index != 0) { efi_st_error("WaitForEvent returned wrong index\n"); - return 1; + return EFI_ST_FAILURE; } - efi_st_printf("Counter periodic: %u\n", counter); - if (counter < 8 || counter > 12) { + efi_st_printf("Notification count periodic: %u\n", timer_ticks); + if (timer_ticks < 8 || timer_ticks > 12) { efi_st_error("Incorrect timing of events\n"); - return 1; + return EFI_ST_FAILURE; } ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); if (index != 0) { efi_st_error("Could not cancel timer\n"); - return 1; + return EFI_ST_FAILURE; } /* Set 10 ms timer */ - counter = 0; + timer_ticks = 0; ret = boottime->set_timer(event_notify, EFI_TIMER_RELATIVE, 100000); if (index != 0) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } /* Set 100 ms timer */ ret = boottime->set_timer(event_wait, EFI_TIMER_PERIODIC, 1000000); if (index != 0) { efi_st_error("Could not set timer\n"); - return 1; + 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 1; + return EFI_ST_FAILURE; } - efi_st_printf("Counter single shot: %u\n", counter); - if (counter != 1) { + efi_st_printf("Notification count single shot: %u\n", timer_ticks); + if (timer_ticks != 1) { efi_st_error("Single shot timer failed\n"); - return 1; + 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 1; + return EFI_ST_FAILURE; } - efi_st_printf("Stopped counter: %u\n", counter); - if (counter != 1) { + efi_st_printf("Notification count stopped timer: %u\n", timer_ticks); + if (timer_ticks != 1) { efi_st_error("Stopped timer fired\n"); - return 1; + return EFI_ST_FAILURE; } ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); if (index != 0) { efi_st_error("Could not cancel timer\n"); - return 1; + return EFI_ST_FAILURE; } - return 0; + return EFI_ST_SUCCESS; } EFI_UNIT_TEST(events) = { diff --git a/lib/efi_selftest/efi_selftest_exitbootservices.c b/lib/efi_selftest/efi_selftest_exitbootservices.c index 60271e61808..cddd11d52b0 100644 --- a/lib/efi_selftest/efi_selftest_exitbootservices.c +++ b/lib/efi_selftest/efi_selftest_exitbootservices.c @@ -1,5 +1,5 @@ /* - * efi_selftest_events + * efi_selftest_exitbootservices * * Copyright (c) 2017 Heinrich Schuchardt * @@ -13,19 +13,19 @@ static struct efi_boot_services *boottime; static struct efi_event *event_notify; -static unsigned int counter; +static unsigned int notification_count; /* - * Notification function, increments a counter. + * Notification function, increments the notification count. * * @event notified event - * @context pointer to the counter + * @context pointer to the notification count */ static void EFIAPI notify(struct efi_event *event, void *context) { - if (!context) - return; - ++*(unsigned int *)context; + unsigned int *count = context; + + ++*count; } /* @@ -35,6 +35,7 @@ static void EFIAPI notify(struct efi_event *event, void *context) * * @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) @@ -43,21 +44,24 @@ static int setup(const efi_handle_t handle, boottime = systable->boottime; - counter = 0; + notification_count = 0; ret = boottime->create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, - TPL_CALLBACK, notify, (void *)&counter, + TPL_CALLBACK, notify, + (void *)¬ification_count, &event_notify); if (ret != EFI_SUCCESS) { efi_st_error("could not create event\n"); - return 1; + return EFI_ST_FAILURE; } - return 0; + return EFI_ST_SUCCESS; } /* * Tear down unit test. * * Close the event created in setup. + * + * @return: EFI_ST_SUCCESS for success */ static int teardown(void) { @@ -68,10 +72,10 @@ static int teardown(void) event_notify = NULL; if (ret != EFI_SUCCESS) { efi_st_error("could not close event\n"); - return 1; + return EFI_ST_FAILURE; } } - return 0; + return EFI_ST_SUCCESS; } /* @@ -82,19 +86,21 @@ static int teardown(void) * * Call ExitBootServices again and check that the notification function is * not called again. + * + * @return: EFI_ST_SUCCESS for success */ static int execute(void) { - if (counter != 1) { - efi_st_error("ExitBootServices was not notified"); - return 1; + if (notification_count != 1) { + efi_st_error("ExitBootServices was not notified\n"); + return EFI_ST_FAILURE; } efi_st_exit_boot_services(); - if (counter != 1) { - efi_st_error("ExitBootServices was notified twice"); - return 1; + if (notification_count != 1) { + efi_st_error("ExitBootServices was notified twice\n"); + return EFI_ST_FAILURE; } - return 0; + return EFI_ST_SUCCESS; } EFI_UNIT_TEST(exitbootservices) = { diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c index 90ace0f51e1..5d13f3b52da 100644 --- a/lib/efi_selftest/efi_selftest_tpl.c +++ b/lib/efi_selftest/efi_selftest_tpl.c @@ -13,20 +13,20 @@ static struct efi_event *event_notify; static struct efi_event *event_wait; -static unsigned int counter; +static unsigned int notification_count; static struct efi_boot_services *boottime; /* - * Notification function, increments a counter. + * Notification function, increments the notification count. * * @event notified event - * @context pointer to the counter + * @context pointer to the notification count */ static void EFIAPI notify(struct efi_event *event, void *context) { - if (!context) - return; - ++*(unsigned int *)context; + unsigned int *count = context; + + ++*count; } /* @@ -37,6 +37,7 @@ static void EFIAPI notify(struct efi_event *event, void *context) * * @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) @@ -46,25 +47,28 @@ static int setup(const efi_handle_t handle, boottime = systable->boottime; ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, - TPL_CALLBACK, notify, (void *)&counter, + TPL_CALLBACK, notify, + (void *)¬ification_count, &event_notify); if (ret != EFI_SUCCESS) { efi_st_error("could not create event\n"); - return 1; + return EFI_ST_FAILURE; } ret = boottime->create_event(EVT_TIMER | EVT_NOTIFY_WAIT, TPL_HIGH_LEVEL, notify, NULL, &event_wait); if (ret != EFI_SUCCESS) { efi_st_error("could not create event\n"); - return 1; + return EFI_ST_FAILURE; } - return 0; + return EFI_ST_SUCCESS; } /* * Tear down unit test. * * Close the events created in setup. + * + * @return: EFI_ST_SUCCESS for success */ static int teardown(void) { @@ -75,7 +79,7 @@ static int teardown(void) event_notify = NULL; if (ret != EFI_SUCCESS) { efi_st_error("could not close event\n"); - return 1; + return EFI_ST_FAILURE; } } if (event_wait) { @@ -83,11 +87,11 @@ static int teardown(void) event_wait = NULL; if (ret != EFI_SUCCESS) { efi_st_error("could not close event\n"); - return 1; + return EFI_ST_FAILURE; } } boottime->restore_tpl(TPL_APPLICATION); - return 0; + return EFI_ST_SUCCESS; } /* @@ -101,6 +105,8 @@ static int teardown(void) * * Lower the TPL level and check that the queued notification * function is called. + * + * @return: EFI_ST_SUCCESS for success */ static int execute(void) { @@ -109,100 +115,103 @@ static int execute(void) UINTN old_tpl; /* Set 10 ms timer */ - counter = 0; + notification_count = 0; ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); if (ret != EFI_SUCCESS) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } /* Set 100 ms timer */ ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); if (ret != EFI_SUCCESS) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } index = 5; ret = boottime->wait_for_event(1, &event_wait, &index); if (ret != EFI_SUCCESS) { efi_st_error("Could not wait for event\n"); - return 1; + return EFI_ST_FAILURE; } ret = boottime->check_event(event_wait); if (ret != EFI_NOT_READY) { efi_st_error("Signaled state was not cleared.\n"); efi_st_printf("ret = %u\n", (unsigned int)ret); - return 1; + return EFI_ST_FAILURE; } if (index != 0) { efi_st_error("WaitForEvent returned wrong index\n"); - return 1; + return EFI_ST_FAILURE; } - efi_st_printf("Counter with TPL level TPL_APPLICATION: %u\n", counter); - if (counter < 8 || counter > 12) { + efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", + notification_count); + if (notification_count < 8 || notification_count > 12) { efi_st_error("Incorrect timing of events\n"); - return 1; + return EFI_ST_FAILURE; } ret = boottime->set_timer(event_notify, EFI_TIMER_STOP, 0); if (index != 0) { efi_st_error("Could not cancel timer\n"); - return 1; + return EFI_ST_FAILURE; } /* Raise TPL level */ old_tpl = boottime->raise_tpl(TPL_CALLBACK); if (old_tpl != TPL_APPLICATION) { efi_st_error("Initial TPL level was not TPL_APPLICATION"); - return 1; + return EFI_ST_FAILURE; } /* Set 10 ms timer */ - counter = 0; + notification_count = 0; ret = boottime->set_timer(event_notify, EFI_TIMER_PERIODIC, 100000); if (index != 0) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } /* Set 100 ms timer */ ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000000); if (ret != EFI_SUCCESS) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } do { ret = boottime->check_event(event_wait); } while (ret == EFI_NOT_READY); if (ret != EFI_SUCCESS) { efi_st_error("Could not check event\n"); - return 1; + return EFI_ST_FAILURE; } - efi_st_printf("Counter with TPL level TPL_CALLBACK: %u\n", counter); - if (counter != 0) { + efi_st_printf("Notification count with TPL level TPL_CALLBACK: %u\n", + notification_count); + if (notification_count != 0) { efi_st_error("Suppressed timer fired\n"); - return 1; + return EFI_ST_FAILURE; } /* Set 1 ms timer */ ret = boottime->set_timer(event_wait, EFI_TIMER_RELATIVE, 1000); if (ret != EFI_SUCCESS) { efi_st_error("Could not set timer\n"); - return 1; + return EFI_ST_FAILURE; } /* Restore the old TPL level */ boottime->restore_tpl(TPL_APPLICATION); ret = boottime->wait_for_event(1, &event_wait, &index); if (ret != EFI_SUCCESS) { efi_st_error("Could not wait for event\n"); - return 1; + return EFI_ST_FAILURE; } - efi_st_printf("Counter with TPL level TPL_APPLICATION: %u\n", counter); - if (counter < 1) { + efi_st_printf("Notification count with TPL level TPL_APPLICATION: %u\n", + notification_count); + if (notification_count < 1) { efi_st_error("Queued timer event did not fire\n"); - return 1; + return EFI_ST_FAILURE; } ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); if (index != 0) { efi_st_error("Could not cancel timer\n"); - return 1; + return EFI_ST_FAILURE; } - return 0; + return EFI_ST_SUCCESS; } EFI_UNIT_TEST(tpl) = { -- cgit v1.2.3 From 332468f7fca8d6089367083f4386478793e3b544 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 21 Sep 2017 18:30:11 +0200 Subject: efi_loader: provide function comments for boot services Provide comments describing the boot service functions. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 640 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 638 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index cb688e16e93..df75dd90322 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -161,6 +161,19 @@ static u64 efi_div10(u64 a) return ret; } +/* + * Queue an EFI event. + * + * This function queues the notification function of the event for future + * execution. + * + * The notification function is called if the task priority level of the + * event is higher than the current task priority level. + * + * For the SignalEvent service see efi_signal_event_ext. + * + * @event event to signal + */ void efi_signal_event(struct efi_event *event) { if (event->notify_function) { @@ -174,12 +187,28 @@ 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. + * + * This function implements the RaiseTpl service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @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) { UINTN old_tpl = efi_tpl; @@ -196,6 +225,15 @@ static unsigned long EFIAPI efi_raise_tpl(UINTN new_tpl) return old_tpl; } +/* + * Lower the task priority level. + * + * This function implements the RestoreTpl service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @old_tpl value of the task priority level to be restored + */ static void EFIAPI efi_restore_tpl(UINTN old_tpl) { EFI_ENTRY("0x%zx", old_tpl); @@ -209,6 +247,19 @@ static void EFIAPI efi_restore_tpl(UINTN old_tpl) EFI_EXIT(EFI_SUCCESS); } +/* + * Allocate memory pages. + * + * This function implements the AllocatePages service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @type type of allocation to be performed + * @memory_type usage type of the allocated memory + * @pages number of pages to be allocated + * @memory allocated memory + * @return status code + */ static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, unsigned long pages, uint64_t *memory) @@ -220,6 +271,17 @@ static efi_status_t EFIAPI efi_allocate_pages_ext(int type, int memory_type, return EFI_EXIT(r); } +/* + * Free memory pages. + * + * This function implements the FreePages service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @memory start of the memory area to be freed + * @pages number of pages to be freed + * @return status code + */ static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, unsigned long pages) { @@ -230,6 +292,21 @@ static efi_status_t EFIAPI efi_free_pages_ext(uint64_t memory, return EFI_EXIT(r); } +/* + * Get map describing memory usage. + * + * This function implements the GetMemoryMap service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @memory_map_size on entry the size, in bytes, of the memory map buffer, + * on exit the size of the copied memory map + * @memory_map buffer to which the memory map is written + * @map_key key for the memory map + * @descriptor_size size of an individual memory descriptor + * @descriptor_version version number of the memory descriptor structure + * @return status code + */ static efi_status_t EFIAPI efi_get_memory_map_ext( unsigned long *memory_map_size, struct efi_mem_desc *memory_map, @@ -246,6 +323,18 @@ static efi_status_t EFIAPI efi_get_memory_map_ext( return EFI_EXIT(r); } +/* + * Allocate memory from pool. + * + * This function implements the AllocatePool service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @pool_type type of the pool from which memory is to be allocated + * @size number of bytes to be allocated + * @buffer allocated memory + * @return status code + */ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, unsigned long size, void **buffer) @@ -257,6 +346,16 @@ static efi_status_t EFIAPI efi_allocate_pool_ext(int pool_type, return EFI_EXIT(r); } +/* + * Free memory from pool. + * + * This function implements the FreePool service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @buffer start of memory to be freed + * @return status code + */ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) { efi_status_t r; @@ -289,6 +388,21 @@ static efi_status_t efi_create_handle(void **handle) */ static struct efi_event efi_events[16]; +/* + * Create an event. + * + * This function is used inside U-Boot code to create an event. + * + * For the API function implementing the CreateEvent service see + * efi_create_event_ext. + * + * @type type of the event to create + * @notify_tpl task priority level of the event + * @notify_function notification function of the event + * @notify_context pointer passed to the notification function + * @event created event + * @return status code + */ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, void (EFIAPI *notify_function) ( struct efi_event *event, @@ -324,6 +438,20 @@ efi_status_t efi_create_event(uint32_t type, UINTN notify_tpl, return EFI_OUT_OF_RESOURCES; } +/* + * Create an event. + * + * This function implements the CreateEvent service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @type type of the event to create + * @notify_tpl task priority level of the event + * @notify_function notification function of the event + * @notify_context pointer passed to the notification function + * @event created event + * @return status code + */ static efi_status_t EFIAPI efi_create_event_ext( uint32_t type, UINTN notify_tpl, void (EFIAPI *notify_function) ( @@ -339,8 +467,11 @@ static efi_status_t EFIAPI efi_create_event_ext( /* + * Check if a timer event has occurred or a queued notification function should + * be called. + * * Our timers have to work without interrupts, so we check whenever keyboard - * input or disk accesses happen if enough time elapsed for it to fire. + * input or disk accesses happen if enough time elapsed for them to fire. */ void efi_timer_check(void) { @@ -372,6 +503,17 @@ void efi_timer_check(void) WATCHDOG_RESET(); } +/* + * Set the trigger time for a timer event or stop the event. + * + * This is the function for internal usage in U-Boot. For the API function + * implementing the SetTimer service see efi_set_timer_ext. + * + * @event event for which the timer is set + * @type type of the timer + * @trigger_time trigger period in multiples of 100ns + * @return status code + */ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time) { @@ -409,6 +551,18 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, return EFI_INVALID_PARAMETER; } +/* + * Set the trigger time for a timer event or stop the event. + * + * This function implements the SetTimer service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @event event for which the timer is set + * @type type of the timer + * @trigger_time trigger period in multiples of 100ns + * @return status code + */ static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, enum efi_timer_delay type, uint64_t trigger_time) @@ -417,6 +571,18 @@ static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, return EFI_EXIT(efi_set_timer(event, type, trigger_time)); } +/* + * Wait for events to be signaled. + * + * This function implements the WaitForEvent service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @num_events number of events to be waited for + * @events events to be waited for + * @index index of the event that was signaled + * @return status code + */ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, struct efi_event **event, unsigned long *index) @@ -466,6 +632,18 @@ out: return EFI_EXIT(EFI_SUCCESS); } +/* + * Signal an EFI event. + * + * This function implements the SignalEvent service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * This functions sets the signaled state of the event and queues the + * notification function for execution. + * + * @event event to signal + */ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { int i; @@ -484,6 +662,16 @@ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) return EFI_EXIT(EFI_SUCCESS); } +/* + * Close an EFI event. + * + * This function implements the CloseEvent service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @event event to close + * @return status code + */ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) { int i; @@ -501,6 +689,18 @@ static efi_status_t EFIAPI efi_close_event(struct efi_event *event) return EFI_EXIT(EFI_INVALID_PARAMETER); } +/* + * Check if an event is signaled. + * + * This function implements the CheckEvent service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * If an event is not signaled yet the notification function is queued. + * + * @event event to check + * @return status code + */ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) { int i; @@ -521,6 +721,20 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) return EFI_EXIT(EFI_INVALID_PARAMETER); } +/* + * 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. + * + * @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(void **handle, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) @@ -579,6 +793,20 @@ 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, efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) @@ -591,6 +819,20 @@ static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, protocol_interface)); } +/* + * Reinstall protocol interface. + * + * This function implements the ReinstallProtocolInterface service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle on which the protocol shall be + * reinstalled + * @protocol GUID of the protocol to be installed + * @old_interface interface to be removed + * @new_interface interface to be installed + * @return status code + */ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, efi_guid_t *protocol, void *old_interface, void *new_interface) @@ -600,6 +842,18 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, return EFI_EXIT(EFI_ACCESS_DENIED); } +/* + * 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. + * + * @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, efi_guid_t *protocol, void *protocol_interface) { @@ -641,6 +895,18 @@ 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, efi_guid_t *protocol, void *protocol_interface) { @@ -650,6 +916,19 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, protocol_interface)); } +/* + * Register an event for notification when a protocol is installed. + * + * This function implements the RegisterProtocolNotify service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @protocol GUID of the protocol whose installation shall be + * notified + * @event event to be signaled upon installation of the protocol + * @registration key for retrieving the registration information + * @return status code + */ static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, struct efi_event *event, void **registration) @@ -658,6 +937,17 @@ static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, return EFI_EXIT(EFI_OUT_OF_RESOURCES); } +/* + * Determine if an EFI handle implements a protocol. + * + * See the documentation of the LocateHandle service in the UEFI specification. + * + * @search_type selection criterion + * @protocol GUID of the protocol + * @search_key registration key + * @efiobj handle + * @return 0 if the handle implements the protocol + */ static int efi_search(enum efi_locate_search_type search_type, efi_guid_t *protocol, void *search_key, struct efi_object *efiobj) @@ -681,6 +971,19 @@ static int efi_search(enum efi_locate_search_type search_type, return -1; } +/* + * Locate handles implementing a protocol. + * + * This function is meant for U-Boot internal calls. For the API implementation + * of the LocateHandle service see efi_locate_handle_ext. + * + * @search_type selection criterion + * @protocol GUID of the protocol + * @search_key registration key + * @buffer_size size of the buffer to receive the handles in bytes + * @buffer buffer to receive the relevant handles + * @return status code + */ static efi_status_t efi_locate_handle( enum efi_locate_search_type search_type, efi_guid_t *protocol, void *search_key, @@ -719,6 +1022,20 @@ static efi_status_t efi_locate_handle( return EFI_SUCCESS; } +/* + * Locate handles implementing a protocol. + * + * This function implements the LocateHandle service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @search_type selection criterion + * @protocol GUID of the protocol + * @search_key registration key + * @buffer_size size of the buffer to receive the handles in bytes + * @buffer buffer to receive the relevant handles + * @return 0 if the handle implements the protocol + */ static efi_status_t EFIAPI efi_locate_handle_ext( enum efi_locate_search_type search_type, efi_guid_t *protocol, void *search_key, @@ -731,6 +1048,18 @@ 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(efi_guid_t *protocol, struct efi_device_path **device_path, efi_handle_t *device) @@ -759,6 +1088,16 @@ static void efi_remove_configuration_table(int i) systab.nr_tables--; } +/* + * Adds, updates, or removes a configuration table. + * + * This function is used for internal calls. For the API implementation of the + * InstallConfigurationTable service see efi_install_configuration_table_ext. + * + * @guid GUID of the installed table + * @table table to be installed + * @return status code + */ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table) { int i; @@ -789,6 +1128,17 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table return EFI_SUCCESS; } +/* + * Adds, updates, or removes a configuration table. + * + * This function implements the InstallConfigurationTable service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @guid GUID of the installed table + * @table table to be installed + * @return status code + */ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, void *table) { @@ -796,8 +1146,15 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, return EFI_EXIT(efi_install_configuration_table(guid, table)); } -/* Initialize a loaded_image_info + loaded_image_info object with correct +/* + * Initialize a loaded_image_info + loaded_image_info object with correct * protocols, boot-device, etc. + * + * @info loaded image info to be passed to the enty point of the + * image + * @obj internal object associated with the loaded image + * @device_path device path of the loaded image + * @file_path file path of the loaded image */ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *obj, struct efi_device_path *device_path, @@ -832,6 +1189,12 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob list_add_tail(&obj->link, &efi_obj_list); } +/* + * Load an image using a file path. + * + * @file_path the path of the image to load + * @buffer buffer containing the loaded image + */ efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, void **buffer) { @@ -873,6 +1236,22 @@ error: return ret; } +/* + * Load an EFI image into memory. + * + * This function implements the LoadImage service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @boot_policy true for request originating from the boot manager + * @parent_image the calles's image handle + * @file_path the path of the image to load + * @source_buffer memory location from which the image is installed + * @source_size size of the memory area from which the image is + * installed + * @image_handle handle for the newly installed image + * @return status code + */ static efi_status_t EFIAPI efi_load_image(bool boot_policy, efi_handle_t parent_image, struct efi_device_path *file_path, @@ -926,6 +1305,17 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, return EFI_EXIT(EFI_SUCCESS); } +/* + * Call the entry point of an image. + * + * This function implements the StartImage service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @image_handle handle of the image + * @exit_data_size size of the buffer + * @exit_data buffer to receive the exit data of the called image + */ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, unsigned long *exit_data_size, s16 **exit_data) @@ -954,6 +1344,18 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, return EFI_EXIT(EFI_SUCCESS); } +/* + * Leave an EFI application or driver. + * + * This function implements the Exit service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @image_handle handle of the application or driver that is exiting + * @exit_status status code + * @exit_data_size size of the buffer in bytes + * @exit_data buffer with data describing an error + */ 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) @@ -978,6 +1380,12 @@ 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; @@ -992,6 +1400,16 @@ static struct efi_object *efi_search_obj(void *handle) return NULL; } +/* + * Unload an EFI image. + * + * This function implements the UnloadImage service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @image_handle handle of the image to be unloaded + * @return status code + */ static efi_status_t EFIAPI efi_unload_image(void *image_handle) { struct efi_object *efiobj; @@ -1004,6 +1422,9 @@ static efi_status_t EFIAPI efi_unload_image(void *image_handle) return EFI_EXIT(EFI_SUCCESS); } +/* + * Fix up caches for EFI payloads if necessary. + */ static void efi_exit_caches(void) { #if defined(CONFIG_ARM) && !defined(CONFIG_ARM64) @@ -1016,6 +1437,17 @@ static void efi_exit_caches(void) #endif } +/* + * Stop boot services. + * + * This function implements the ExitBootServices service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @image_handle handle of the loaded image + * @map_key key of the memory map + * @return status code + */ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle, unsigned long map_key) { @@ -1051,6 +1483,16 @@ static efi_status_t EFIAPI efi_exit_boot_services(void *image_handle, return EFI_EXIT(EFI_SUCCESS); } +/* + * Get next value of the counter. + * + * This function implements the NextMonotonicCount service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @count returned value of the counter + * @return status code + */ static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count) { static uint64_t mono = 0; @@ -1059,6 +1501,16 @@ static efi_status_t EFIAPI efi_get_next_monotonic_count(uint64_t *count) return EFI_EXIT(EFI_SUCCESS); } +/* + * Sleep. + * + * This function implements the Stall sercive. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @microseconds period to sleep in microseconds + * @return status code + */ static efi_status_t EFIAPI efi_stall(unsigned long microseconds) { EFI_ENTRY("%ld", microseconds); @@ -1066,6 +1518,18 @@ static efi_status_t EFIAPI efi_stall(unsigned long microseconds) return EFI_EXIT(EFI_SUCCESS); } +/* + * Reset the watchdog timer. + * + * This function implements the WatchdogTimer service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @timeout seconds before reset by watchdog + * @watchdog_code code to be logged when resetting + * @data_size size of buffer in bytes + * @watchdog_data buffer with data describing the reset reason + */ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, uint64_t watchdog_code, unsigned long data_size, @@ -1076,6 +1540,19 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, return efi_unsupported(__func__); } +/* + * Connect a controller to a driver. + * + * This function implements the ConnectController service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @controller_handle handle of the controller + * @driver_image_handle handle of the driver + * @remain_device_path device path of a child controller + * @recursive true to connect all child controllers + * @return status code + */ static efi_status_t EFIAPI efi_connect_controller( efi_handle_t controller_handle, efi_handle_t *driver_image_handle, @@ -1087,6 +1564,18 @@ static efi_status_t EFIAPI efi_connect_controller( return EFI_EXIT(EFI_NOT_FOUND); } +/* + * Disconnect a controller from a driver. + * + * This function implements the DisconnectController service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @controller_handle handle of the controller + * @driver_image_handle handle of the driver + * @child_handle handle of the child to destroy + * @return status code + */ static efi_status_t EFIAPI efi_disconnect_controller(void *controller_handle, void *driver_image_handle, void *child_handle) @@ -1096,6 +1585,19 @@ static efi_status_t EFIAPI efi_disconnect_controller(void *controller_handle, return EFI_EXIT(EFI_INVALID_PARAMETER); } +/* + * Close a protocol. + * + * This function implements the CloseProtocol service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle on which the protocol shall be closed + * @protocol GUID of the protocol to close + * @agent_handle handle of the driver + * @controller_handle handle of the controller + * @return status code + */ static efi_status_t EFIAPI efi_close_protocol(void *handle, efi_guid_t *protocol, void *agent_handle, @@ -1106,6 +1608,19 @@ static efi_status_t EFIAPI efi_close_protocol(void *handle, return EFI_EXIT(EFI_NOT_FOUND); } +/* + * Provide information about then open status of a protocol on a handle + * + * This function implements the OpenProtocolInformation service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle for which the information shall be retrieved + * @protocol GUID of the protocol + * @entry_buffer buffer to receive the open protocol information + * @entry_count number of entries available in the buffer + * @return status code + */ static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, efi_guid_t *protocol, struct efi_open_protocol_info_entry **entry_buffer, @@ -1116,6 +1631,17 @@ static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, return EFI_EXIT(EFI_NOT_FOUND); } +/* + * Get protocols installed on a handle. + * + * This function implements the ProtocolsPerHandleService. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle for which the information is retrieved + * @protocol_buffer buffer with protocol GUIDs + * @protocol_buffer_count number of entries in the buffer + */ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, efi_guid_t ***protocol_buffer, unsigned long *protocol_buffer_count) @@ -1169,6 +1695,20 @@ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, return EFI_EXIT(EFI_SUCCESS); } +/* + * Locate handles implementing a protocol. + * + * This function implements the LocateHandleBuffer service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @search_type selection criterion + * @protocol GUID of the protocol + * @search_key registration key + * @no_handles number of returned handles + * @buffer buffer with the returned handles + * @return status code + */ static efi_status_t EFIAPI efi_locate_handle_buffer( enum efi_locate_search_type search_type, efi_guid_t *protocol, void *search_key, @@ -1202,6 +1742,17 @@ out: return EFI_EXIT(r); } +/* + * Find an interface implementing a protocol. + * + * This function implements the LocateProtocol service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @protocol GUID of the protocol + * @registration registration key passed to the notification function + * @protocol_interface interface implementing the protocol + */ static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, void *registration, void **protocol_interface) @@ -1237,6 +1788,18 @@ static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, return EFI_EXIT(EFI_NOT_FOUND); } +/* + * Install multiple protocol interfaces. + * + * This function implements the MultipleProtocolInterfaces service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle on which the protocol interfaces shall be installed + * @... NULL terminated argument list with pairs of protocol GUIDS and + * interfaces + * @return status code + */ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( void **handle, ...) { @@ -1281,6 +1844,18 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( return EFI_EXIT(r); } +/* + * Uninstall multiple protocol interfaces. + * + * This function implements the UninstallMultipleProtocolInterfaces service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle from which the protocol interfaces shall be removed + * @... NULL terminated argument list with pairs of protocol GUIDS and + * interfaces + * @return status code + */ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( void *handle, ...) { @@ -1288,6 +1863,18 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( return EFI_EXIT(EFI_INVALID_PARAMETER); } +/* + * Calculate cyclic redundancy code. + * + * This function implements the CalculateCrc32 service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @data buffer with data + * @data_size size of buffer in bytes + * @crc32_p cyclic redundancy code + * @return status code + */ static efi_status_t EFIAPI efi_calculate_crc32(void *data, unsigned long data_size, uint32_t *crc32_p) @@ -1297,6 +1884,17 @@ static efi_status_t EFIAPI efi_calculate_crc32(void *data, return EFI_EXIT(EFI_SUCCESS); } +/* + * Copy memory. + * + * This function implements the CopyMem service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @destination destination of the copy operation + * @source source of the copy operation + * @length number of bytes to copy + */ static void EFIAPI efi_copy_mem(void *destination, void *source, unsigned long length) { @@ -1304,12 +1902,38 @@ static void EFIAPI efi_copy_mem(void *destination, void *source, memcpy(destination, source, length); } +/* + * Fill memory with a byte value. + * + * This function implements the SetMem service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @buffer buffer to fill + * @size size of buffer in bytes + * @value byte to copy to the buffer + */ static void EFIAPI efi_set_mem(void *buffer, unsigned long size, uint8_t value) { EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value); memset(buffer, value, size); } +/* + * Open protocol interface on a handle. + * + * This function implements the OpenProtocol interface. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle on which the protocol shall be opened + * @protocol GUID of the protocol + * @protocol_interface interface implementing the protocol + * @agent_handle handle of the driver + * @controller_handle handle of the controller + * @attributes attributes indicating how to open the protocol + * @return status code + */ static efi_status_t EFIAPI efi_open_protocol( void *handle, efi_guid_t *protocol, void **protocol_interface, void *agent_handle, @@ -1382,6 +2006,18 @@ out: return EFI_EXIT(r); } +/* + * Get interface of a protocol on a handle. + * + * This function implements the HandleProtocol service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @handle handle on which the protocol shall be opened + * @protocol GUID of the protocol + * @protocol_interface interface implementing the protocol + * @return status code + */ static efi_status_t EFIAPI efi_handle_protocol(void *handle, efi_guid_t *protocol, void **protocol_interface) -- cgit v1.2.3 From 7d963323a25f87f701aab6ced99a912230f19776 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:14:14 +0200 Subject: efi_loader: replace efi_div10 by do_div We should use the existing 64bit division instead of reinventing the wheel. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index df75dd90322..66ce92f6548 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -128,39 +129,6 @@ const char *__efi_nesting_dec(void) return indent_string(--nesting_level); } -/* Low 32 bit */ -#define EFI_LOW32(a) (a & 0xFFFFFFFFULL) -/* High 32 bit */ -#define EFI_HIGH32(a) (a >> 32) - -/* - * 64bit division by 10 implemented as multiplication by 1 / 10 - * - * Decimals of one tenth: 0x1 / 0xA = 0x0.19999... - */ -#define EFI_TENTH 0x199999999999999A -static u64 efi_div10(u64 a) -{ - u64 prod; - u64 rem; - u64 ret; - - ret = EFI_HIGH32(a) * EFI_HIGH32(EFI_TENTH); - prod = EFI_HIGH32(a) * EFI_LOW32(EFI_TENTH); - rem = EFI_LOW32(prod); - ret += EFI_HIGH32(prod); - prod = EFI_LOW32(a) * EFI_HIGH32(EFI_TENTH); - rem += EFI_LOW32(prod); - ret += EFI_HIGH32(prod); - prod = EFI_LOW32(a) * EFI_LOW32(EFI_TENTH); - rem += EFI_HIGH32(prod); - ret += EFI_HIGH32(rem); - /* Round to nearest integer */ - if (rem >= (1 << 31)) - ++ret; - return ret; -} - /* * Queue an EFI event. * @@ -523,7 +491,7 @@ efi_status_t efi_set_timer(struct efi_event *event, enum efi_timer_delay type, * The parameter defines a multiple of 100ns. * We use multiples of 1000ns. So divide by 10. */ - trigger_time = efi_div10(trigger_time); + do_div(trigger_time, 10); for (i = 0; i < ARRAY_SIZE(efi_events); ++i) { if (event != &efi_events[i]) -- cgit v1.2.3 From f7c78176d6925726d654cd84eb866c7b39da1b13 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:35:51 +0200 Subject: efi_loader: call EFI_EXIT in efi_copy_mem, efi_set_mem EFI_ENTRY and EFI_EXIT calls must match. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass 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 66ce92f6548..b8b98f2c4af 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1868,6 +1868,7 @@ static void EFIAPI efi_copy_mem(void *destination, void *source, { EFI_ENTRY("%p, %p, %ld", destination, source, length); memcpy(destination, source, length); + EFI_EXIT(EFI_SUCCESS); } /* @@ -1885,6 +1886,7 @@ static void EFIAPI efi_set_mem(void *buffer, unsigned long size, uint8_t value) { EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value); memset(buffer, value, size); + EFI_EXIT(EFI_SUCCESS); } /* -- cgit v1.2.3 From fc05a9590689b70fffdb9914e9867ea53fd579fa Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:35:52 +0200 Subject: efi_loader: parameters of CopyMem and SetMem The UEFI spec defines the length parameters of CopyMem and SetMem as UINTN. We should size_t here. The source buffer of CopyMem should be marked as const. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index b8b98f2c4af..c48ff2cd2a8 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1863,10 +1863,10 @@ static efi_status_t EFIAPI efi_calculate_crc32(void *data, * @source source of the copy operation * @length number of bytes to copy */ -static void EFIAPI efi_copy_mem(void *destination, void *source, - unsigned long length) +static void EFIAPI efi_copy_mem(void *destination, const void *source, + size_t length) { - EFI_ENTRY("%p, %p, %ld", destination, source, length); + EFI_ENTRY("%p, %p, %ld", destination, source, (unsigned long)length); memcpy(destination, source, length); EFI_EXIT(EFI_SUCCESS); } @@ -1882,9 +1882,9 @@ static void EFIAPI efi_copy_mem(void *destination, void *source, * @size size of buffer in bytes * @value byte to copy to the buffer */ -static void EFIAPI efi_set_mem(void *buffer, unsigned long size, uint8_t value) +static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) { - EFI_ENTRY("%p, %ld, 0x%x", buffer, size, value); + EFI_ENTRY("%p, %ld, 0x%x", buffer, (unsigned long)size, value); memset(buffer, value, size); EFI_EXIT(EFI_SUCCESS); } -- cgit v1.2.3 From 5a9682d0ddd9328eb581b18a8b263c3834943942 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:35:53 +0200 Subject: efi_loader: pass GUIDs as const efi_guid_t * We need to call some boottime services internally. Our GUIDs are stored as const efi_guid_t *. The boottime services never change GUIDs. So we can define the parameters as const efi_guid_t *. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c48ff2cd2a8..e5adc17faba 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -704,7 +704,7 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event) * @return status code */ static efi_status_t EFIAPI efi_install_protocol_interface(void **handle, - efi_guid_t *protocol, int protocol_interface_type, + const efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { struct list_head *lhandle; @@ -776,7 +776,7 @@ out: * @return status code */ static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, - efi_guid_t *protocol, int protocol_interface_type, + const efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { EFI_ENTRY("%p, %pUl, %d, %p", handle, protocol, protocol_interface_type, @@ -802,7 +802,7 @@ static efi_status_t EFIAPI efi_install_protocol_interface_ext(void **handle, * @return status code */ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, - efi_guid_t *protocol, void *old_interface, + const efi_guid_t *protocol, void *old_interface, void *new_interface) { EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface, @@ -823,7 +823,7 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface(void *handle, * @return status code */ static efi_status_t EFIAPI efi_uninstall_protocol_interface(void *handle, - efi_guid_t *protocol, void *protocol_interface) + const efi_guid_t *protocol, void *protocol_interface) { struct list_head *lhandle; int i; @@ -876,7 +876,7 @@ out: * @return status code */ static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, - efi_guid_t *protocol, void *protocol_interface) + const efi_guid_t *protocol, void *protocol_interface) { EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); @@ -897,9 +897,10 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface_ext(void *handle, * @registration key for retrieving the registration information * @return status code */ -static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, - struct efi_event *event, - void **registration) +static efi_status_t EFIAPI efi_register_protocol_notify( + const efi_guid_t *protocol, + struct efi_event *event, + void **registration) { EFI_ENTRY("%pUl, %p, %p", protocol, event, registration); return EFI_EXIT(EFI_OUT_OF_RESOURCES); @@ -917,7 +918,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify(efi_guid_t *protocol, * @return 0 if the handle implements the protocol */ static int efi_search(enum efi_locate_search_type search_type, - efi_guid_t *protocol, void *search_key, + const efi_guid_t *protocol, void *search_key, struct efi_object *efiobj) { int i; @@ -954,7 +955,7 @@ 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, - efi_guid_t *protocol, void *search_key, + const efi_guid_t *protocol, void *search_key, unsigned long *buffer_size, efi_handle_t *buffer) { struct list_head *lhandle; @@ -1006,7 +1007,7 @@ static efi_status_t efi_locate_handle( */ static efi_status_t EFIAPI efi_locate_handle_ext( enum efi_locate_search_type search_type, - efi_guid_t *protocol, void *search_key, + const efi_guid_t *protocol, void *search_key, unsigned long *buffer_size, efi_handle_t *buffer) { EFI_ENTRY("%d, %pUl, %p, %p, %p", search_type, protocol, search_key, @@ -1028,7 +1029,8 @@ static efi_status_t EFIAPI efi_locate_handle_ext( * @device handle of the device * @return status code */ -static efi_status_t EFIAPI efi_locate_device_path(efi_guid_t *protocol, +static efi_status_t EFIAPI efi_locate_device_path( + const efi_guid_t *protocol, struct efi_device_path **device_path, efi_handle_t *device) { @@ -1567,7 +1569,7 @@ static efi_status_t EFIAPI efi_disconnect_controller(void *controller_handle, * @return status code */ static efi_status_t EFIAPI efi_close_protocol(void *handle, - efi_guid_t *protocol, + const efi_guid_t *protocol, void *agent_handle, void *controller_handle) { @@ -1590,7 +1592,7 @@ static efi_status_t EFIAPI efi_close_protocol(void *handle, * @return status code */ static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, - efi_guid_t *protocol, + const efi_guid_t *protocol, struct efi_open_protocol_info_entry **entry_buffer, unsigned long *entry_count) { @@ -1679,7 +1681,7 @@ 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, - efi_guid_t *protocol, void *search_key, + const efi_guid_t *protocol, void *search_key, unsigned long *no_handles, efi_handle_t **buffer) { efi_status_t r; @@ -1721,7 +1723,7 @@ out: * @registration registration key passed to the notification function * @protocol_interface interface implementing the protocol */ -static efi_status_t EFIAPI efi_locate_protocol(efi_guid_t *protocol, +static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, void *registration, void **protocol_interface) { @@ -1774,7 +1776,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( EFI_ENTRY("%p", handle); va_list argptr; - efi_guid_t *protocol; + const efi_guid_t *protocol; void *protocol_interface; efi_status_t r = EFI_SUCCESS; int i = 0; @@ -1905,7 +1907,7 @@ static void EFIAPI efi_set_mem(void *buffer, size_t size, uint8_t value) * @return status code */ static efi_status_t EFIAPI efi_open_protocol( - void *handle, efi_guid_t *protocol, + void *handle, const efi_guid_t *protocol, void **protocol_interface, void *agent_handle, void *controller_handle, uint32_t attributes) { @@ -1989,7 +1991,7 @@ out: * @return status code */ static efi_status_t EFIAPI efi_handle_protocol(void *handle, - efi_guid_t *protocol, + const efi_guid_t *protocol, void **protocol_interface) { return efi_open_protocol(handle, protocol, protocol_interface, NULL, -- cgit v1.2.3 From ca379e1bf16e59841f15ed34088eb1362bf2bd35 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:35:54 +0200 Subject: efi_loader: wrong type in wait_for_event The UEFI spec defines parameter index of WaitForEvent as UINTN*. So we should use size_t here. I deliberately do not use UINTN because I hold a following patch that will eliminate UINTN because uppercase types to not match the U-Boot coding style. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 2 +- lib/efi_selftest/efi_selftest_events.c | 2 +- lib/efi_selftest/efi_selftest_tpl.c | 2 +- 3 files 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 e5adc17faba..976d5822f7d 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -553,7 +553,7 @@ static efi_status_t EFIAPI efi_set_timer_ext(struct efi_event *event, */ static efi_status_t EFIAPI efi_wait_for_event(unsigned long num_events, struct efi_event **event, - unsigned long *index) + size_t *index) { int i, j; diff --git a/lib/efi_selftest/efi_selftest_events.c b/lib/efi_selftest/efi_selftest_events.c index 532f165d437..b2cdc150da2 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) { - unsigned long index; + size_t index; efi_status_t ret; /* Set 10 ms timer */ diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c index 5d13f3b52da..0b78ee75956 100644 --- a/lib/efi_selftest/efi_selftest_tpl.c +++ b/lib/efi_selftest/efi_selftest_tpl.c @@ -110,7 +110,7 @@ static int teardown(void) */ static int execute(void) { - unsigned long index; + size_t index; efi_status_t ret; UINTN old_tpl; -- cgit v1.2.3 From bdecf974f168af49f5deb2d325e7ad8f3ad4a52e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:35:57 +0200 Subject: efi_loader: fill simple network protocol revision Provide the simple network protocol revision. This revision number could be used to identify backwards compatible enhancements of the protocol. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 91f1e4a69e1..fb23bcf6332 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -228,6 +228,7 @@ int efi_net_register(void) netobj->parent.protocols[2].guid = &efi_pxe_guid; netobj->parent.protocols[2].protocol_interface = &netobj->pxe; netobj->parent.handle = &netobj->net; + netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION; netobj->net.start = efi_net_start; netobj->net.stop = efi_net_stop; netobj->net.initialize = efi_net_initialize; -- cgit v1.2.3 From 5d4a5ea964e523a29ec077b6f95537956c366c1f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:35:58 +0200 Subject: efi_loader: efi_net: hwaddr_size = 6 The length of a MAC address is 6. We have to set this length in the EFI_SIMPLE_NETWORK_MODE structure of the EFI_SIMPLE_NETWORK_PROTOCOL. Without this patch iPXE fails to initialize the network with error message SNP MAC(001e0633bcbf,0x0) has invalid hardware address length 0 Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index fb23bcf6332..9def34cf934 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -245,6 +245,7 @@ int efi_net_register(void) netobj->net.mode = &netobj->net_mode; netobj->net_mode.state = EFI_NETWORK_STARTED; memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6); + netobj->net_mode.hwaddr_size = ARP_HLEN; netobj->net_mode.max_packet_size = PKTSIZE; netobj->pxe.mode = &netobj->pxe_mode; -- cgit v1.2.3 From 61da678c394583a4731178858e9b9312f05c758b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:35:59 +0200 Subject: efi_net: return EFI_UNSUPPORTED where appropriate U-Boot does not implement all functions of the simple network protocol. The unimplemented functions return either of EFI_SUCCESS and EFI_INVALID_PARAMETER. The UEFI spec foresees to return EFI_UNSUPPORTED in these cases. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 9def34cf934..569bf367a84 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -78,9 +78,7 @@ static efi_status_t EFIAPI efi_net_receive_filters( EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable, reset_mcast_filter, mcast_filter_count, mcast_filter); - /* XXX Do we care? */ - - return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(EFI_UNSUPPORTED); } static efi_status_t EFIAPI efi_net_station_address( @@ -89,7 +87,7 @@ static efi_status_t EFIAPI efi_net_station_address( { EFI_ENTRY("%p, %x, %p", this, reset, new_mac); - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_EXIT(EFI_UNSUPPORTED); } static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, @@ -98,7 +96,7 @@ static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, { EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table); - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_EXIT(EFI_UNSUPPORTED); } static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this, @@ -118,7 +116,7 @@ static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this, EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size, buffer); - return EFI_EXIT(EFI_INVALID_PARAMETER); + return EFI_EXIT(EFI_UNSUPPORTED); } static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, -- cgit v1.2.3 From a0549ef6073e346eb0cbbae1395d4db446b7b05e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:36:00 +0200 Subject: efi_loader: use events for efi_net_receive A timer event is defined. The timer handler cares for receiving new packets. efi_timer_check is called both in efi_net_transmit and efi_net_receive to enable events during network communication. Calling efi_timer_check in efi_net_get_status is implemented in a separate patch. [agraf] This patch is needed to make efi_net_get_status() actually report incoming packets. Signed-off-by: Heinrich Schuchardt [agraf: fix spelling in comment] Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 53 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 569bf367a84..37047891c91 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -19,6 +19,11 @@ static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID; static struct efi_pxe_packet *dhcp_ack; static bool new_rx_packet; static void *new_tx_packet; +/* + * The notification function of this event is called in every timer cycle + * to check if a new network packet has been received. + */ +static struct efi_event *network_timer_event; struct efi_net_obj { /* Generic EFI object parent class data */ @@ -143,6 +148,8 @@ static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size, buffer_size, buffer, src_addr, dest_addr, protocol); + efi_timer_check(); + if (header_size) { /* We would need to create the header if header_size != 0 */ return EFI_EXIT(EFI_INVALID_PARAMETER); @@ -174,9 +181,7 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size, buffer_size, buffer, src_addr, dest_addr, protocol); - push_packet = efi_net_push; - eth_rx(); - push_packet = NULL; + efi_timer_check(); if (!new_rx_packet) return EFI_EXIT(EFI_NOT_READY); @@ -204,10 +209,32 @@ void efi_net_set_dhcp_ack(void *pkt, int len) memcpy(dhcp_ack, pkt, min(len, maxsize)); } +/* + * Check if a new network packet has been received. + * + * This notification function is called in every timer cycle. + * + * @event the event for which this notification function is registered + * @context event context - not used in this function + */ +static void EFIAPI efi_network_timer_notify(struct efi_event *event, + void *context) +{ + EFI_ENTRY("%p, %p", event, context); + + if (!new_rx_packet) { + push_packet = efi_net_push; + eth_rx(); + push_packet = NULL; + } + EFI_EXIT(EFI_SUCCESS); +} + /* This gets called from do_bootefi_exec(). */ int efi_net_register(void) { struct efi_net_obj *netobj; + efi_status_t r; if (!eth_get_dev()) { /* No eth device active, don't expose any */ @@ -253,5 +280,25 @@ int efi_net_register(void) /* Hook net up to the device list */ list_add_tail(&netobj->parent.link, &efi_obj_list); + /* + * Create a timer event. + * + * The notification function is used to check if a new network packet + * has been received. + */ + r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK, + efi_network_timer_notify, NULL, + &network_timer_event); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to register network event\n"); + return r; + } + /* Network is time critical, create event in every timer cyle */ + r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to set network timer\n"); + return r; + } + return 0; } -- cgit v1.2.3 From e5c21603fce2e6143f7312211eaed47c16510ea3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:36:01 +0200 Subject: efi_loader: implement WaitForPacket event The WaitForPacket event informs that a network package has been received by the SimpleNetworkProtocol. Signed-off-by: Heinrich Schuchardt [agraf: Move is_signaled = true line into efi_net_push()] Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 37047891c91..cd46d2db534 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -24,6 +24,10 @@ static void *new_tx_packet; * to check if a new network packet has been received. */ static struct efi_event *network_timer_event; +/* + * This event is signaled when a packet has been received. + */ +static struct efi_event *wait_for_packet; struct efi_net_obj { /* Generic EFI object parent class data */ @@ -171,6 +175,7 @@ static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, static void efi_net_push(void *pkt, int len) { new_rx_packet = true; + wait_for_packet->is_signaled = true; } static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, @@ -280,6 +285,17 @@ int efi_net_register(void) /* Hook net up to the device list */ list_add_tail(&netobj->parent.link, &efi_obj_list); + /* + * Create WaitForPacket event. + */ + r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, + efi_network_timer_notify, NULL, + &wait_for_packet); + if (r != EFI_SUCCESS) { + printf("ERROR: Failed to register network event\n"); + return r; + } + netobj->net.wait_for_packet = wait_for_packet; /* * Create a timer event. * -- cgit v1.2.3 From 891b3d9051690d0ba39da4eda1d15773ebfee2b6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:36:02 +0200 Subject: efi_loader: fix efi_net_get_status The returned interrupt status was wrong. As out transmit buffer is empty we need to always set EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT. When we have received a packet we need to set EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT. Furthermore we should call efi_timer_check() to handle events. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index cd46d2db534..b16463ba1a1 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -133,9 +133,14 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, { EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); - /* We send packets synchronously, so nothing is outstanding */ - if (int_status) - *int_status = 0; + efi_timer_check(); + + if (int_status) { + /* We send packets synchronously, so nothing is outstanding */ + *int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; + if (new_rx_packet) + *int_status |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT; + } if (txbuf) *txbuf = new_tx_packet; -- cgit v1.2.3 From 8db174d651e3f92ddb9660f1f8b8755b902c3c11 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:36:03 +0200 Subject: efi_loader: size fields in SimpleNetworkProtocol The size fields in the Simple Network Protocol are all UINTN in the UEFI spec. So use size_t. Provide a function description of the receive function. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index b16463ba1a1..4546b436031 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -150,12 +150,13 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, } static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, - ulong header_size, ulong buffer_size, void *buffer, + size_t header_size, size_t buffer_size, void *buffer, struct efi_mac_address *src_addr, struct efi_mac_address *dest_addr, u16 *protocol) { - EFI_ENTRY("%p, %lx, %lx, %p, %p, %p, %p", this, header_size, - buffer_size, buffer, src_addr, dest_addr, protocol); + EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this, + (unsigned long)header_size, (unsigned long)buffer_size, + buffer, src_addr, dest_addr, protocol); efi_timer_check(); @@ -183,8 +184,23 @@ static void efi_net_push(void *pkt, int len) wait_for_packet->is_signaled = true; } +/* + * Receive a packet from a network interface. + * + * This function implements the Receive service of the Simple Network Protocol. + * See the UEFI spec for details. + * + * @this the instance of the Simple Network Protocol + * @header_size size of the media header + * @buffer_size size of the buffer to receive the packet + * @buffer buffer to receive the packet + * @src_addr source MAC address + * @dest_addr destination MAC address + * @protocol protocol + * @return status code + */ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, - ulong *header_size, ulong *buffer_size, void *buffer, + size_t *header_size, size_t *buffer_size, void *buffer, struct efi_mac_address *src_addr, struct efi_mac_address *dest_addr, u16 *protocol) { -- cgit v1.2.3 From 336d9dfc0a3b2245945a9fca9312c4266d186866 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:36:04 +0200 Subject: efi_loader: fill return values in SimpleNetworkProtocol In the receive function all return values should be filled. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 4546b436031..432d9a99a2b 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -204,6 +204,10 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, struct efi_mac_address *src_addr, struct efi_mac_address *dest_addr, u16 *protocol) { + struct ethernet_hdr *eth_hdr; + size_t hdr_size = sizeof(struct ethernet_hdr); + u16 protlen; + EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size, buffer_size, buffer, src_addr, dest_addr, protocol); @@ -211,13 +215,32 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, if (!new_rx_packet) return EFI_EXIT(EFI_NOT_READY); - + /* Check that we at least received an Ethernet header */ + if (net_rx_packet_len < sizeof(struct ethernet_hdr)) { + new_rx_packet = false; + return EFI_EXIT(EFI_NOT_READY); + } + /* Fill export parameters */ + eth_hdr = (struct ethernet_hdr *)net_rx_packet; + protlen = ntohs(eth_hdr->et_protlen); + if (protlen == 0x8100) { + hdr_size += 4; + protlen = ntohs(*(u16 *)&net_rx_packet[hdr_size - 2]); + } + if (header_size) + *header_size = hdr_size; + if (dest_addr) + memcpy(dest_addr, eth_hdr->et_dest, ARP_HLEN); + if (src_addr) + memcpy(src_addr, eth_hdr->et_src, ARP_HLEN); + if (protocol) + *protocol = protlen; if (*buffer_size < net_rx_packet_len) { /* Packet doesn't fit, try again with bigger buf */ *buffer_size = net_rx_packet_len; return EFI_EXIT(EFI_BUFFER_TOO_SMALL); } - + /* Copy packet */ memcpy(buffer, net_rx_packet, net_rx_packet_len); *buffer_size = net_rx_packet_len; new_rx_packet = false; -- cgit v1.2.3 From 1b6332597f23ea71b94a9ce65e15a0d3f5ea23ed Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:36:06 +0200 Subject: efi_selftest: allow printing MAC addresses Add %pm as format string to print a MAC address. This is helpful when analyzing network problems. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_console.c | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index 7b5b724a617..840e2290c60 100644 --- a/lib/efi_selftest/efi_selftest_console.c +++ b/lib/efi_selftest/efi_selftest_console.c @@ -12,6 +12,37 @@ struct efi_simple_text_output_protocol *con_out; struct efi_simple_input_interface *con_in; +/* + * Print a MAC address to an u16 string + * + * @pointer: mac address + * @buf: pointer to buffer address + * on return position of terminating zero word + */ +static void mac(void *pointer, u16 **buf) +{ + int i, j; + u16 c; + u8 *p = (u8 *)pointer; + u8 byte; + u16 *pos = *buf; + + for (i = 0; i < ARP_HLEN; ++i) { + if (i) + *pos++ = ':'; + byte = p[i]; + for (j = 4; j >= 0; j -= 4) { + c = (byte >> j) & 0x0f; + c += '0'; + if (c > '9') + c += 'a' - '9' - 1; + *pos++ = c; + } + } + *pos = 0; + *buf = pos; +} + /* * Print a pointer to an u16 string * @@ -146,7 +177,15 @@ void efi_st_printf(const char *fmt, ...) int2dec(va_arg(args, s32), &pos); break; case 'p': - pointer(va_arg(args, void*), &pos); + ++c; + switch (*c) { + case 'm': + mac(va_arg(args, void*), &pos); + break; + default: + --c; + pointer(va_arg(args, void*), &pos); + } break; case 's': s = va_arg(args, const char *); -- cgit v1.2.3 From 5ca23ed5bc63832baa24a6107537fdd229c458ae Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Oct 2017 16:36:07 +0200 Subject: efi_loader: supply EFI network test This patch provides an EFI application to check the correct function of the Simple Network Protocol implementation. It sends a DHCP request and analyzes the DHCP offer. Different error conditions including a 10s timeout are checked. A successful execution will look like this: => bootefi nettest Scanning disk ide.blk#0... Found 1 disks WARNING: Invalid device tree, expect boot to fail Network test DHCP Discover DHCP reply received from 192.168.76.2 (52:55:c0:a8:4c:02) as broadcast message. OK. The test was completed successfully. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 8 +- lib/efi_selftest/efi_selftest_snp.c | 424 +++++++++++++++++++++++++++++++++++ lib/efi_selftest/efi_selftest_util.c | 25 +++ 3 files changed, 456 insertions(+), 1 deletion(-) create mode 100644 lib/efi_selftest/efi_selftest_snp.c create mode 100644 lib/efi_selftest/efi_selftest_util.c (limited to 'lib') diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 30f19609330..e446046e022 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -15,12 +15,18 @@ 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_snp.o := $(CFLAGS_EFI) +CFLAGS_REMOVE_efi_selftest_snp.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) obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ efi_selftest_console.o \ efi_selftest_events.o \ efi_selftest_exitbootservices.o \ -efi_selftest_tpl.o +efi_selftest_snp.o \ +efi_selftest_tpl.o \ +efi_selftest_util.o diff --git a/lib/efi_selftest/efi_selftest_snp.c b/lib/efi_selftest/efi_selftest_snp.c new file mode 100644 index 00000000000..638be0147df --- /dev/null +++ b/lib/efi_selftest/efi_selftest_snp.c @@ -0,0 +1,424 @@ +/* + * efi_selftest_snp + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * This unit test covers the Simple Network Protocol as well as + * the CopyMem and SetMem boottime services. + * + * A DHCP discover message is sent. The test is successful if a + * DHCP reply is received. + * + * TODO: Once ConnectController and DisconnectController are implemented + * we should connect our code as controller. + */ + +#include + +/* + * MAC address for broadcasts + */ +static const u8 BROADCAST_MAC[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + +struct dhcp_hdr { + u8 op; +#define BOOTREQUEST 1 +#define BOOTREPLY 2 + u8 htype; +# define HWT_ETHER 1 + u8 hlen; +# define HWL_ETHER 6 + u8 hops; + u32 xid; + u16 secs; + u16 flags; +#define DHCP_FLAGS_UNICAST 0x0000 +#define DHCP_FLAGS_BROADCAST 0x0080 + u32 ciaddr; + u32 yiaddr; + u32 siaddr; + u32 giaddr; + u8 chaddr[16]; + u8 sname[64]; + u8 file[128]; +}; + +/* + * Message type option. + */ +#define DHCP_MESSAGE_TYPE 0x35 +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +struct dhcp { + struct ethernet_hdr eth_hdr; + struct ip_udp_hdr ip_udp; + struct dhcp_hdr dhcp_hdr; + u8 opt[128]; +} __packed; + +static struct efi_boot_services *boottime; +static struct efi_simple_network *net; +static struct efi_event *timer; +static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID; +/* IP packet ID */ +static unsigned int net_ip_id; + +/* + * Compute the checksum of the IP header. We cover even values of length only. + * We cannot use net/checksum.c due to different CFLAGS values. + * + * @buf: IP header + * @len: length of header in bytes + * @return: checksum + */ +static unsigned int efi_ip_checksum(const void *buf, size_t len) +{ + size_t i; + u32 sum = 0; + const u16 *pos = buf; + + for (i = 0; i < len; i += 2) + sum += *pos++; + + sum = (sum >> 16) + (sum & 0xffff); + sum += sum >> 16; + sum = ~sum & 0xffff; + + return sum; +} + +/* + * Transmit a DHCPDISCOVER message. + */ +static efi_status_t send_dhcp_discover(void) +{ + efi_status_t ret; + struct dhcp p = {}; + + /* + * Fill ethernet header + */ + boottime->copy_mem(p.eth_hdr.et_dest, (void *)BROADCAST_MAC, ARP_HLEN); + boottime->copy_mem(p.eth_hdr.et_src, &net->mode->current_address, + ARP_HLEN); + p.eth_hdr.et_protlen = htons(PROT_IP); + /* + * Fill IP header + */ + p.ip_udp.ip_hl_v = 0x45; + p.ip_udp.ip_len = htons(sizeof(struct dhcp) - + sizeof(struct ethernet_hdr)); + p.ip_udp.ip_id = htons(++net_ip_id); + p.ip_udp.ip_off = htons(IP_FLAGS_DFRAG); + p.ip_udp.ip_ttl = 0xff; /* time to live */ + p.ip_udp.ip_p = IPPROTO_UDP; + boottime->set_mem(&p.ip_udp.ip_dst, 4, 0xff); + p.ip_udp.ip_sum = efi_ip_checksum(&p.ip_udp, IP_HDR_SIZE); + + /* + * Fill UDP header + */ + p.ip_udp.udp_src = htons(68); + p.ip_udp.udp_dst = htons(67); + p.ip_udp.udp_len = htons(sizeof(struct dhcp) - + sizeof(struct ethernet_hdr) - + sizeof(struct ip_hdr)); + /* + * Fill DHCP header + */ + p.dhcp_hdr.op = BOOTREQUEST; + p.dhcp_hdr.htype = HWT_ETHER; + p.dhcp_hdr.hlen = HWL_ETHER; + p.dhcp_hdr.flags = htons(DHCP_FLAGS_UNICAST); + boottime->copy_mem(&p.dhcp_hdr.chaddr, + &net->mode->current_address, ARP_HLEN); + /* + * Fill options + */ + p.opt[0] = 0x63; /* DHCP magic cookie */ + p.opt[1] = 0x82; + p.opt[2] = 0x53; + p.opt[3] = 0x63; + p.opt[4] = DHCP_MESSAGE_TYPE; + p.opt[5] = 0x01; /* length */ + p.opt[6] = DHCPDISCOVER; + p.opt[7] = 0x39; /* maximum message size */ + p.opt[8] = 0x02; /* length */ + p.opt[9] = 0x02; /* 576 bytes */ + p.opt[10] = 0x40; + p.opt[11] = 0xff; /* end of options */ + + /* + * Transmit DHCPDISCOVER message. + */ + ret = net->transmit(net, 0, sizeof(struct dhcp), &p, NULL, NULL, 0); + if (ret != EFI_SUCCESS) + efi_st_error("Sending a DHCP request failed\n"); + else + efi_st_printf("DHCP Discover\n"); + return ret; +} + +/* + * Setup unit test. + * + * Create a 1 s periodic timer. + * Start the network driver. + * + * @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; + + /* + * Create a timer event. + */ + ret = boottime->create_event(EVT_TIMER, TPL_CALLBACK, NULL, NULL, + &timer); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create event\n"); + return EFI_ST_FAILURE; + } + /* + * Set timer period to 1s. + */ + ret = boottime->set_timer(timer, EFI_TIMER_PERIODIC, 10000000); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate simple network protocol\n"); + return EFI_ST_FAILURE; + } + /* + * Find an interface implementing the SNP protocol. + */ + ret = boottime->locate_protocol(&efi_net_guid, NULL, (void **)&net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to locate simple network protocol\n"); + return EFI_ST_FAILURE; + } + /* + * Check hardware address size. + */ + if (!net->mode) { + efi_st_error("Mode not provided\n"); + return EFI_ST_FAILURE; + } + if (net->mode->hwaddr_size != ARP_HLEN) { + efi_st_error("HwAddressSize = %u, expected %u\n", + net->mode->hwaddr_size, ARP_HLEN); + return EFI_ST_FAILURE; + } + /* + * Check that WaitForPacket event exists. + */ + if (!net->wait_for_packet) { + efi_st_error("WaitForPacket event missing\n"); + return EFI_ST_FAILURE; + } + /* + * Initialize network adapter. + */ + ret = net->initialize(net, 0, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to initialize network adapter\n"); + return EFI_ST_FAILURE; + } + /* + * Start network adapter. + */ + ret = net->start(net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to start network adapter\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * A DHCP discover message is sent. The test is successful if a + * DHCP reply is received within 10 seconds. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + struct efi_event *events[2]; + size_t index; + union { + struct dhcp p; + u8 b[PKTSIZE]; + } buffer; + struct efi_mac_address srcaddr; + struct efi_mac_address destaddr; + size_t buffer_size; + u8 *addr; + /* + * The timeout is to occur after 10 s. + */ + unsigned int timeout = 10; + + /* + * Send DHCP discover message + */ + ret = send_dhcp_discover(); + if (ret != EFI_SUCCESS) + return EFI_ST_FAILURE; + + /* + * If we would call WaitForEvent only with the WaitForPacket event, + * our code would block until a packet is received which might never + * occur. By calling WaitFor event with both a timer event and the + * WaitForPacket event we can escape this blocking situation. + * + * If the timer event occurs before we have received a DHCP reply + * a further DHCP discover message is sent. + */ + events[0] = timer; + events[1] = net->wait_for_packet; + for (;;) { + /* + * Wait for packet to be received or timer event. + */ + boottime->wait_for_event(2, events, &index); + if (index == 0) { + /* + * The timer event occurred. Check for timeout. + */ + --timeout; + if (!timeout) { + efi_st_error("Timeout occurred\n"); + return EFI_ST_FAILURE; + } + /* + * Send further DHCP discover message + */ + ret = send_dhcp_discover(); + if (ret != EFI_SUCCESS) + return EFI_ST_FAILURE; + continue; + } + /* + * Receive packet + */ + buffer_size = sizeof(buffer); + net->receive(net, NULL, &buffer_size, &buffer, + &srcaddr, &destaddr, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to receive packet"); + return EFI_ST_FAILURE; + } + /* + * Check the packet is meant for this system. + * Unfortunately QEMU ignores the broadcast flag. + * So we have to check for broadcasts too. + */ + if (efi_st_memcmp(&destaddr, &net->mode->current_address, + ARP_HLEN) && + efi_st_memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN)) + continue; + /* + * Check this is a DHCP reply + */ + if (buffer.p.eth_hdr.et_protlen != ntohs(PROT_IP) || + buffer.p.ip_udp.ip_hl_v != 0x45 || + buffer.p.ip_udp.ip_p != IPPROTO_UDP || + buffer.p.ip_udp.udp_src != ntohs(67) || + buffer.p.ip_udp.udp_dst != ntohs(68) || + buffer.p.dhcp_hdr.op != BOOTREPLY) + continue; + /* + * We successfully received a DHCP reply. + */ + break; + } + + /* + * Write a log message. + */ + addr = (u8 *)&buffer.p.ip_udp.ip_src; + efi_st_printf("DHCP reply received from %u.%u.%u.%u (%pm) ", + addr[0], addr[1], addr[2], addr[3], &srcaddr); + if (!efi_st_memcmp(&destaddr, BROADCAST_MAC, ARP_HLEN)) + efi_st_printf("as broadcast message.\n"); + else + efi_st_printf("as unicast message.\n"); + + return EFI_ST_SUCCESS; +} + +/* + * Tear down unit test. + * + * Close the timer event created in setup. + * Shut down the network adapter. + * + * @return: EFI_ST_SUCCESS for success + */ +static int teardown(void) +{ + efi_status_t ret; + int exit_status = EFI_ST_SUCCESS; + + if (timer) { + /* + * Stop timer. + */ + ret = boottime->set_timer(timer, EFI_TIMER_STOP, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to stop timer"); + exit_status = EFI_ST_FAILURE; + } + /* + * Close timer event. + */ + ret = boottime->close_event(timer); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close event"); + exit_status = EFI_ST_FAILURE; + } + } + if (net) { + /* + * Stop network adapter. + */ + ret = net->stop(net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to stop network adapter\n"); + exit_status = EFI_ST_FAILURE; + } + /* + * Shut down network adapter. + */ + ret = net->shutdown(net); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to shut down network adapter\n"); + exit_status = EFI_ST_FAILURE; + } + } + + return exit_status; +} + +EFI_UNIT_TEST(snp) = { + .name = "simple network protocol", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, + .teardown = teardown, +}; diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c new file mode 100644 index 00000000000..c9c295e2fbe --- /dev/null +++ b/lib/efi_selftest/efi_selftest_util.c @@ -0,0 +1,25 @@ +/* + * efi_selftest_util + * + * Copyright (c) 2017 Heinrich Schuchardt + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Utility functions + */ + +#include + +int efi_st_memcmp(const void *buf1, const void *buf2, size_t length) +{ + const u8 *pos1 = buf1; + const u8 *pos2 = buf2; + + for (; length; --length) { + if (*pos1 != *pos2) + return pos1 - pos2; + ++pos1; + ++pos2; + } + return EFI_ST_SUCCESS; +} -- cgit v1.2.3 From c155dfeb1e17181998e66830b677baa8983daf6b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 6 Oct 2017 20:39:13 +0200 Subject: efi_selftest: efi_st_memcmp return difference of bytes If the memory regions are different efi_st_memcmp currently returns the difference of the addresses. Insted the difference of the first differing byte pair should be returned. 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 c9c295e2fbe..5cffe383d8d 100644 --- a/lib/efi_selftest/efi_selftest_util.c +++ b/lib/efi_selftest/efi_selftest_util.c @@ -17,7 +17,7 @@ int efi_st_memcmp(const void *buf1, const void *buf2, size_t length) for (; length; --length) { if (*pos1 != *pos2) - return pos1 - pos2; + return *pos1 - *pos2; ++pos1; ++pos2; } -- cgit v1.2.3 From 7f8ec5b63e5a8774bfcadafbc0d9583686b00455 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 8 Oct 2017 06:57:25 +0200 Subject: efi_selftest: avoid dereferencing NULL in tpl test The task priority levels test uses two events one passes the notification counter as context. The other passes NULL. Both use the same notification function. So we need to check for NULL here. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_tpl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c index 0b78ee75956..b8c0e70262d 100644 --- a/lib/efi_selftest/efi_selftest_tpl.c +++ b/lib/efi_selftest/efi_selftest_tpl.c @@ -26,7 +26,8 @@ static void EFIAPI notify(struct efi_event *event, void *context) { unsigned int *count = context; - ++*count; + if (count) + ++*count; } /* -- cgit v1.2.3 From 1a2c8d2f609237664fcda944c251ce693e4366f5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 8 Oct 2017 06:57:26 +0200 Subject: efi_loader: avoid NULL dereference in efi_dp_match When calling bootefi hello twice a kernel dump occurs. Neither bootefi hello nor bootefi selftest have an image device patch. So do not try to dereference the NULL value. Fixes: 95c5553ea26 efi_loader: refactor boot device and loaded_image handling Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 976d5822f7d..54cf16476cf 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1154,7 +1154,8 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob (void *)&efi_device_path_to_text; info->file_path = file_path; - info->device_handle = efi_dp_find_obj(device_path, NULL); + if (device_path) + info->device_handle = efi_dp_find_obj(device_path, NULL); list_add_tail(&obj->link, &efi_obj_list); } -- cgit v1.2.3 From 77511b3b4be449f1547cd97ec6dde780ef589d84 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Sun, 8 Oct 2017 11:33:08 -0400 Subject: efi_loader: Fix disk dp's for pre-DM/legacy devices This fixes an issue with OpenBSD's bootloader, and I think should also fix a similar issue with grub2 on legacy devices. In the legacy case we were creating disk objects for the partitions, but not also the parent device. Reported-by: Jonathan Gray Signed-off-by: Rob Clark Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index eb9ce772d1d..47b487aa30b 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -340,6 +340,8 @@ 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 = 1; desc = blk_get_devnum_by_type(if_type, i); if (!desc) @@ -349,6 +351,15 @@ int efi_disk_register(void) snprintf(devname, sizeof(devname), "%s%d", if_typename, i); + + /* add devices for each partition: */ + while (!part_get_info(desc, part, &info)) { + efi_disk_add_dev(devname, if_typename, desc, + i, 0, part); + part++; + } + + /* ... and add block device: */ efi_disk_add_dev(devname, if_typename, desc, i, 0, 0); disks++; -- cgit v1.2.3 From 10a08c4ed70e57ac570974b04844ceec13ad311a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 8 Oct 2017 06:57:27 +0200 Subject: efi_loader: comments for functions add missing @return For some functions the @return description is missing. Fix typo. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 54cf16476cf..f627340de44 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -611,6 +611,7 @@ out: * notification function for execution. * * @event event to signal + * @return status code */ static efi_status_t EFIAPI efi_signal_event_ext(struct efi_event *event) { @@ -1120,7 +1121,7 @@ static efi_status_t EFIAPI efi_install_configuration_table_ext(efi_guid_t *guid, * Initialize a loaded_image_info + loaded_image_info object with correct * protocols, boot-device, etc. * - * @info loaded image info to be passed to the enty point of the + * @info loaded image info to be passed to the entry point of the * image * @obj internal object associated with the loaded image * @device_path device path of the loaded image @@ -1165,6 +1166,7 @@ void efi_setup_loaded_image(struct efi_loaded_image *info, struct efi_object *ob * * @file_path the path of the image to load * @buffer buffer containing the loaded image + * @return status code */ efi_status_t efi_load_image_from_path(struct efi_device_path *file_path, void **buffer) @@ -1286,6 +1288,7 @@ static efi_status_t EFIAPI efi_load_image(bool boot_policy, * @image_handle handle of the image * @exit_data_size size of the buffer * @exit_data buffer to receive the exit data of the called image + * @return status code */ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, unsigned long *exit_data_size, @@ -1326,6 +1329,7 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, * @exit_status status code * @exit_data_size size of the buffer in bytes * @exit_data buffer with data describing an error + * @return status code */ static efi_status_t EFIAPI efi_exit(efi_handle_t image_handle, efi_status_t exit_status, unsigned long exit_data_size, @@ -1500,6 +1504,7 @@ static efi_status_t EFIAPI efi_stall(unsigned long microseconds) * @watchdog_code code to be logged when resetting * @data_size size of buffer in bytes * @watchdog_data buffer with data describing the reset reason + * @return status code */ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout, uint64_t watchdog_code, @@ -1612,6 +1617,7 @@ static efi_status_t EFIAPI efi_open_protocol_information(efi_handle_t handle, * @handle handle for which the information is retrieved * @protocol_buffer buffer with protocol GUIDs * @protocol_buffer_count number of entries in the buffer + * @return status code */ static efi_status_t EFIAPI efi_protocols_per_handle(void *handle, efi_guid_t ***protocol_buffer, @@ -1723,6 +1729,7 @@ out: * @protocol GUID of the protocol * @registration registration key passed to the notification function * @protocol_interface interface implementing the protocol + * @return status code */ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, void *registration, -- cgit v1.2.3 From fdd04563cedb6abbc013821c123f5d7ef3078c31 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 8 Oct 2017 06:57:28 +0200 Subject: efi_selftest: error handling in SNP test Avoid NULL pointer dereference after setup failed due to a missing network. Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_snp.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest_snp.c b/lib/efi_selftest/efi_selftest_snp.c index 638be0147df..bdd6ce20da6 100644 --- a/lib/efi_selftest/efi_selftest_snp.c +++ b/lib/efi_selftest/efi_selftest_snp.c @@ -198,7 +198,7 @@ static int setup(const efi_handle_t handle, */ ret = boottime->set_timer(timer, EFI_TIMER_PERIODIC, 10000000); if (ret != EFI_SUCCESS) { - efi_st_error("Failed to locate simple network protocol\n"); + efi_st_error("Failed to set timer\n"); return EFI_ST_FAILURE; } /* @@ -206,6 +206,7 @@ static int setup(const efi_handle_t handle, */ ret = boottime->locate_protocol(&efi_net_guid, NULL, (void **)&net); if (ret != EFI_SUCCESS) { + net = NULL; efi_st_error("Failed to locate simple network protocol\n"); return EFI_ST_FAILURE; } @@ -273,6 +274,12 @@ static int execute(void) */ unsigned int timeout = 10; + /* Setup may have failed */ + if (!net || !timer) { + efi_st_error("Cannot execute test after setup failure\n"); + return EFI_ST_FAILURE; + } + /* * Send DHCP discover message */ -- cgit v1.2.3 From 16a73b249d138fedeb188710533902ed7aac1ddc Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 10 Oct 2017 13:55:26 +1100 Subject: efi_loader: search all possible disk partitions When searching for partitions don't stop if a partition is not present for a given partition number as there may be valid partitions after. Search for up to MAX_SEARCH_PARTITIONS matching the other callers of part_get_info(). This allows OpenBSD to boot via the efi_loader on rpi_3 again after changes made after U-Boot 2017.09. With MBR partitioning OpenBSD will by default use the fourth partition for the 0xA6 (OpenBSD) partition. Signed-off-by: Jonathan Gray Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 47b487aa30b..6b192701a8a 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -254,18 +254,19 @@ static int efi_disk_create_eltorito(struct blk_desc *desc, #if CONFIG_IS_ENABLED(ISO_PARTITION) char devname[32] = { 0 }; /* dp->str is u16[32] long */ disk_partition_t info; - int part = 1; + int part; if (desc->part_type != PART_TYPE_ISO) return 0; /* and devices for each partition: */ - while (!part_get_info(desc, part, &info)) { + for (part = 1; part <= MAX_SEARCH_PARTITIONS; part++) { + if (part_get_info(desc, part, &info)) + continue; snprintf(devname, sizeof(devname), "%s:%d", pdevname, part); efi_disk_add_dev(devname, if_typename, desc, diskid, info.start, part); - part++; disks++; } @@ -299,15 +300,16 @@ int efi_disk_register(void) struct blk_desc *desc = dev_get_uclass_platdata(dev); const char *if_typename = dev->driver->name; disk_partition_t info; - int part = 1; + int part; printf("Scanning disk %s...\n", dev->name); /* add devices for each partition: */ - while (!part_get_info(desc, part, &info)) { + 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); - part++; } /* ... and add block device: */ @@ -341,7 +343,7 @@ int efi_disk_register(void) struct blk_desc *desc; char devname[32] = { 0 }; /* dp->str is u16[32] long */ disk_partition_t info; - int part = 1; + int part; desc = blk_get_devnum_by_type(if_type, i); if (!desc) @@ -353,7 +355,9 @@ int efi_disk_register(void) if_typename, i); /* add devices for each partition: */ - while (!part_get_info(desc, part, &info)) { + 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); part++; -- cgit v1.2.3 From bcbc4a80462c42c5d5ccac0287b8a7d49df9e179 Mon Sep 17 00:00:00 2001 From: Jonathan Gray Date: Tue, 10 Oct 2017 21:32:29 +1100 Subject: efi_loader: don't increment part twice per loop Correct a mistake in the part number handling of commit 16a73b249d138fedeb188710533902ed7aac1ddc and only increment part once per loop. Signed-off-by: Jonathan Gray Tested-by: Peter Robinson Signed-off-by: Alexander Graf --- lib/efi_loader/efi_disk.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 6b192701a8a..e61dbc80580 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -360,7 +360,6 @@ int efi_disk_register(void) continue; efi_disk_add_dev(devname, if_typename, desc, i, 0, part); - part++; } /* ... and add block device: */ -- cgit v1.2.3 From bf19273e81eb5e23c9bc14c3881f92a120565561 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 10 Oct 2017 08:23:06 -0400 Subject: efi_loader: Add mem-mapped for fallback When we don't have a real device/image path, such as 'bootefi hello', construct a mem-mapped device-path. This fixes 'bootefi hello' after devicepath refactoring. Fixes: 95c5553ea2 ("efi_loader: refactor boot device and loaded_image handling") Signed-off-by: Rob Clark Acked-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path.c | 24 ++++++++++++++++++++++++ lib/efi_loader/efi_device_path_to_text.c | 9 +++++++++ 2 files changed, 33 insertions(+) (limited to 'lib') diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 5d5c3b34646..f6e368e029b 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -538,6 +538,30 @@ struct efi_device_path *efi_dp_from_eth(void) } #endif +/* Construct a device-path for memory-mapped image */ +struct efi_device_path *efi_dp_from_mem(uint32_t memory_type, + uint64_t start_address, + uint64_t end_address) +{ + struct efi_device_path_memory *mdp; + void *buf, *start; + + start = buf = dp_alloc(sizeof(*mdp) + sizeof(END)); + + mdp = buf; + mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE; + mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY; + mdp->dp.length = sizeof(*mdp); + mdp->memory_type = memory_type; + mdp->start_address = start_address; + mdp->end_address = end_address; + buf = &mdp[1]; + + *((struct efi_device_path *)buf) = END; + + return start; +} + /* * Helper to split a full device path (containing both device and file * parts) into it's constituent parts. diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 1a5ef3919ba..62771338f03 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -24,6 +24,15 @@ static char *dp_unknown(char *s, struct efi_device_path *dp) static char *dp_hardware(char *s, struct efi_device_path *dp) { switch (dp->sub_type) { + 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)", + mdp->memory_type, + mdp->start_address, + mdp->end_address); + break; + } case DEVICE_PATH_SUB_TYPE_VENDOR: { struct efi_device_path_vendor *vdp = (struct efi_device_path_vendor *)dp; -- cgit v1.2.3 From 2d5dc2a52d412964031c9920d354ad5bdc91c654 Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Tue, 10 Oct 2017 08:23:01 -0400 Subject: efi_loader: console support for color attributes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shell.efi uses this, and supporting color attributes makes things look nicer. Map the EFI fg/bg color attributes to ANSI escape sequences. Not all colors have a perfect match, but spec just says "Devices supporting a different number of text colors are required to emulate the above colors to the best of the device’s capabilities". Signed-off-by: Rob Clark Tested-by: Heinrich Schuchardt Reviewed-by: Alexander Graf [agraf: s/unsigned/unsigned int/] Signed-off-by: Alexander Graf --- lib/efi_loader/efi_console.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 1bdf36b4ae7..01732aafead 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -307,14 +307,37 @@ static efi_status_t EFIAPI efi_cout_set_mode( return EFI_EXIT(EFI_SUCCESS); } +static const struct { + unsigned int fg; + unsigned int bg; +} color[] = { + { 30, 40 }, /* 0: black */ + { 34, 44 }, /* 1: blue */ + { 32, 42 }, /* 2: green */ + { 36, 46 }, /* 3: cyan */ + { 31, 41 }, /* 4: red */ + { 35, 45 }, /* 5: magenta */ + { 33, 43 }, /* 6: brown, map to yellow as edk2 does*/ + { 37, 47 }, /* 7: light grey, map to white */ +}; + +/* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */ static efi_status_t EFIAPI efi_cout_set_attribute( struct efi_simple_text_output_protocol *this, unsigned long attribute) { + unsigned int bold = EFI_ATTR_BOLD(attribute); + unsigned int fg = EFI_ATTR_FG(attribute); + unsigned int bg = EFI_ATTR_BG(attribute); + EFI_ENTRY("%p, %lx", this, attribute); - /* Just ignore attributes (colors) for now */ - return EFI_EXIT(EFI_UNSUPPORTED); + if (attribute) + printf(ESC"[%u;%u;%um", bold, color[fg].fg, color[bg].bg); + else + printf(ESC"[0;37;40m"); + + return EFI_EXIT(EFI_SUCCESS); } static efi_status_t EFIAPI efi_cout_clear_screen( -- cgit v1.2.3 From abe994633b2ad56c5eea87c9253873f41dab477d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 13 Oct 2017 01:00:05 +0200 Subject: efi_selftest: correctly check return values When cancelling the timer we should check the return value provided by the set_timer service. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_events.c | 2 +- lib/efi_selftest/efi_selftest_tpl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/efi_selftest/efi_selftest_events.c b/lib/efi_selftest/efi_selftest_events.c index b2cdc150da2..081f31257fb 100644 --- a/lib/efi_selftest/efi_selftest_events.c +++ b/lib/efi_selftest/efi_selftest_events.c @@ -186,7 +186,7 @@ static int execute(void) return EFI_ST_FAILURE; } ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); - if (index != 0) { + if (ret != EFI_SUCCESS) { efi_st_error("Could not cancel timer\n"); return EFI_ST_FAILURE; } diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c index b8c0e70262d..ddb67ed268b 100644 --- a/lib/efi_selftest/efi_selftest_tpl.c +++ b/lib/efi_selftest/efi_selftest_tpl.c @@ -207,7 +207,7 @@ static int execute(void) return EFI_ST_FAILURE; } ret = boottime->set_timer(event_wait, EFI_TIMER_STOP, 0); - if (index != 0) { + if (ret != EFI_SUCCESS) { efi_st_error("Could not cancel timer\n"); return EFI_ST_FAILURE; } -- cgit v1.2.3