From 66ca24a9a05aa094bcdcf0784d8cc5911dc2f725 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 2 Jun 2019 01:43:33 +0200 Subject: efi_loader: DisconnectController() with no driver If DisconnectController() is called and no driver is managing ControllerHandle, return EFI_SUCCESS. UEFI SCT II 2017, 3.3.12 DisconnectController(), 5.1.3.12.4 - 5.1.3.12.6 Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 54fff85e64..027bd6d4d3 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1134,11 +1134,15 @@ static efi_status_t efi_get_drivers(efi_handle_t handle, ++count; } } + *number_of_drivers = 0; + if (!count) { + *driver_handle_buffer = NULL; + return EFI_SUCCESS; + } /* * Create buffer. In case of duplicate driver assignments the buffer * will be too large. But that does not harm. */ - *number_of_drivers = 0; *driver_handle_buffer = calloc(count, sizeof(efi_handle_t)); if (!*driver_handle_buffer) return EFI_OUT_OF_RESOURCES; @@ -1194,7 +1198,8 @@ static efi_status_t efi_disconnect_all_drivers &driver_handle_buffer); if (ret != EFI_SUCCESS) return ret; - + if (!number_of_drivers) + return EFI_SUCCESS; ret = EFI_NOT_FOUND; while (number_of_drivers) { r = EFI_CALL(efi_disconnect_controller( -- cgit v1.2.3 From 6a853dbcc02ba26d8b85d26be9763464c6bfe63e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 2 Jun 2019 21:02:10 +0200 Subject: lib: time: export usec_to_tick() In the UEFI Stall() boottime service we need access to usec_to_tick(). Export the function. Remove redundant implementation in arch/arm/mach-rockchip/rk_timer.c. Signed-off-by: Heinrich Schuchardt --- arch/arm/mach-rockchip/rk_timer.c | 7 ------- include/time.h | 9 +++++++++ lib/time.c | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/arm/mach-rockchip/rk_timer.c b/arch/arm/mach-rockchip/rk_timer.c index f20e64f48e..29d379fa0a 100644 --- a/arch/arm/mach-rockchip/rk_timer.c +++ b/arch/arm/mach-rockchip/rk_timer.c @@ -20,13 +20,6 @@ static uint64_t rockchip_get_ticks(void) return timebase_h << 32 | timebase_l; } -static uint64_t usec_to_tick(unsigned int usec) -{ - uint64_t tick = usec; - tick *= CONFIG_SYS_TIMER_RATE / (1000 * 1000); - return tick; -} - void rockchip_udelay(unsigned int usec) { uint64_t tmp; diff --git a/include/time.h b/include/time.h index 9fd0d73fb4..1e9b369be7 100644 --- a/include/time.h +++ b/include/time.h @@ -4,6 +4,7 @@ #define _TIME_H #include +#include unsigned long get_timer(unsigned long base); @@ -21,6 +22,14 @@ unsigned long timer_get_us(void); */ void timer_test_add_offset(unsigned long offset); +/** + * usec_to_tick() - convert microseconds to clock ticks + * + * @usec: duration in microseconds + * Return: duration in clock ticks + */ +uint64_t usec_to_tick(unsigned long usec); + /* * These inlines deal with timer wrapping correctly. You are * strongly encouraged to use them diff --git a/lib/time.c b/lib/time.c index 9c55da6f1b..f5751ab162 100644 --- a/lib/time.c +++ b/lib/time.c @@ -139,7 +139,7 @@ unsigned long __weak notrace timer_get_us(void) return tick_to_time(get_ticks() * 1000); } -static uint64_t usec_to_tick(unsigned long usec) +uint64_t usec_to_tick(unsigned long usec) { uint64_t tick = usec; tick *= get_tbclk(); -- cgit v1.2.3 From 22f23db428b8ee14ff04a9128431e719ef2a387c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 2 Jun 2019 21:12:17 +0200 Subject: efi_loader: check timer events in Stall() During a call to Stall() we should periodically check for timer events. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 027bd6d4d3..fed8d47ade 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1947,8 +1947,14 @@ out: */ static efi_status_t EFIAPI efi_stall(unsigned long microseconds) { + u64 end_tick; + EFI_ENTRY("%ld", microseconds); - udelay(microseconds); + + end_tick = get_ticks() + usec_to_tick(microseconds); + while (get_ticks() < end_tick) + efi_timer_check(); + return EFI_EXIT(EFI_SUCCESS); } -- cgit v1.2.3 From 25e6fb5e93194d84c4b93fb3ab9d93d2157923dd Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 2 Jun 2019 22:54:28 +0200 Subject: efi_loader: fix EnableCursor() The EnableCursor() service of the simple text output protocol must update the the CursorVisible field of the output mode. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_console.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index b2cb18e6d6..3b7578f3aa 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -430,6 +430,7 @@ static efi_status_t EFIAPI efi_cout_enable_cursor( EFI_ENTRY("%p, %d", this, enable); printf(ESC"[?25%c", enable ? 'h' : 'l'); + efi_con_mode.cursor_visible = !!enable; return EFI_EXIT(EFI_SUCCESS); } -- cgit v1.2.3 From 120ff7ba68df265a8b96c5c6131b579ce722a7a5 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 2 Jun 2019 20:02:32 +0200 Subject: efi_loader: close protocols in UnloadImage() When UnloadImage() is called all protocols opened by the image have to be closed. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_boottime.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index fed8d47ade..78c6076e28 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2791,12 +2791,46 @@ efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, * @image_obj: handle of the loaded image * @loaded_image_protocol: loaded image protocol */ -static void efi_delete_image(struct efi_loaded_image_obj *image_obj, - struct efi_loaded_image *loaded_image_protocol) +static efi_status_t efi_delete_image + (struct efi_loaded_image_obj *image_obj, + struct efi_loaded_image *loaded_image_protocol) { + struct efi_object *efiobj; + efi_status_t r, ret = EFI_SUCCESS; + +close_next: + list_for_each_entry(efiobj, &efi_obj_list, link) { + struct efi_handler *protocol; + + list_for_each_entry(protocol, &efiobj->protocols, link) { + struct efi_open_protocol_info_item *info; + + list_for_each_entry(info, &protocol->open_infos, link) { + if (info->info.agent_handle != + (efi_handle_t)image_obj) + continue; + r = EFI_CALL(efi_close_protocol + (efiobj, protocol->guid, + info->info.agent_handle, + info->info.controller_handle + )); + if (r != EFI_SUCCESS) + ret = r; + /* + * Closing protocols may results in further + * items being deleted. To play it safe loop + * over all elements again. + */ + goto close_next; + } + } + } + efi_free_pages((uintptr_t)loaded_image_protocol->image_base, efi_size_in_pages(loaded_image_protocol->image_size)); efi_delete_handle(&image_obj->header); + + return ret; } /** -- cgit v1.2.3 From 94e6e5505310be3bec4392f24ac13b75dbbaca2b Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 29 May 2019 20:54:25 +0200 Subject: efi_loader: bootmgr: print a message when loading from BootNext failed If a user defines BootNext but not BootOrder and loading from BootNext fails, you will see only a message like this: BootOrder not defined This may confuse a user. Adding an error message will be helpful. An example output looks like this: => efidebug boot add 0001 label1 scsi 0:1 "\path1\file1.efi" "--option foo" => efidebug boot add 0002 label2 scsi 0:1 "\path2\file2.efi" "--option bar" => efidebug boot add 0003 label3 scsi 0:1 "\path3\file3.efi" "--option no" => efidebug boot order 0001 0002 => efidebug boot next 0003 => bootefi bootmgr Loading from Boot0003 'label3' failed Loading from BootNext failed, falling back to BootOrder Loading from Boot0001 'label1' failed Loading from Boot0002 'label2' failed EFI boot manager: Cannot load any image Signed-off-by: AKASHI Takahiro Adjust messages. Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_bootmgr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 7bf51874c1..43791422c8 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -149,8 +149,11 @@ static efi_status_t try_load_entry(u16 n, efi_handle_t *handle) ret = EFI_CALL(efi_load_image(true, efi_root, lo.file_path, NULL, 0, handle)); - if (ret != EFI_SUCCESS) + if (ret != EFI_SUCCESS) { + printf("Loading from Boot%04X '%ls' failed\n", n, + lo.label); goto error; + } attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; @@ -215,6 +218,7 @@ efi_status_t efi_bootmgr_load(efi_handle_t *handle) ret = try_load_entry(bootnext, handle); if (ret == EFI_SUCCESS) return ret; + printf("Loading from BootNext failed, falling back to BootOrder\n"); } } else { printf("Deleting BootNext failed\n"); -- cgit v1.2.3 From 8190b4a3e01c80fed782e206e49696d64fedd8a6 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 28 May 2019 09:00:35 +0900 Subject: cmd: env: print a message when setting UEFI variable failed Error message will alert a user that setting/deleting a variable failed. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/nvedit_efi.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index 2805e8182b..ff8eaa1aad 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -373,6 +373,8 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) for ( ; argc > 0; argc--, argv++) if (append_value(&value, &size, argv[0]) < 0) { + printf("## Failed to process an argument, %s\n", + argv[0]); ret = CMD_RET_FAILURE; goto out; } @@ -381,6 +383,7 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) len = utf8_utf16_strnlen(var_name, strlen(var_name)); var_name16 = malloc((len + 1) * 2); if (!var_name16) { + printf("## Out of memory\n"); ret = CMD_RET_FAILURE; goto out; } @@ -392,7 +395,12 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, value)); - ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); + if (ret == EFI_SUCCESS) { + ret = CMD_RET_SUCCESS; + } else { + printf("## Failed to set EFI variable\n"); + ret = CMD_RET_FAILURE; + } out: free(value); free(var_name16); -- cgit v1.2.3 From e80474ad39d1f348cda3837bef1b7baf600fae47 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 4 Jun 2019 20:55:12 +0200 Subject: efi_loader: notify memory map changes When the memory map is changed signal events of the EFI_EVENT_GROUP_MEMORY_MAP_CHANGE event group. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_memory.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 76dcaa48f4..386cf924fe 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -230,6 +230,7 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, struct efi_mem_list *newlist; bool carve_again; uint64_t carved_pages = 0; + struct efi_event *evt; EFI_PRINT("%s: 0x%llx 0x%llx %d %s\n", __func__, start, pages, memory_type, overlap_only_ram ? "yes" : "no"); @@ -315,6 +316,16 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, /* And make sure memory is listed in descending order */ efi_mem_sort(); + /* Notify that the memory map was changed */ + list_for_each_entry(evt, &efi_events, link) { + if (evt->group && + !guidcmp(evt->group, + &efi_guid_event_group_memory_map_change)) { + efi_signal_event(evt, false); + break; + } + } + return start; } -- cgit v1.2.3 From cee2cbc73173a871a5c65e9e55f3d98a6fd71325 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 4 Jun 2019 15:52:06 +0900 Subject: efi_loader: variable: support non-volatile attribute The attribute, EFI_VARIABLE_NON_VOLATILE, should be encoded as "nv" flag in U-Boot variable if specified. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_variable.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 50bc10537f..e56053194d 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -125,6 +125,8 @@ static const char *parse_attr(const char *str, u32 *attrp) if ((s = prefix(str, "ro"))) { attr |= READ_ONLY; + } else if ((s = prefix(str, "nv"))) { + attr |= EFI_VARIABLE_NON_VOLATILE; } else if ((s = prefix(str, "boot"))) { attr |= EFI_VARIABLE_BOOTSERVICE_ACCESS; } else if ((s = prefix(str, "run"))) { @@ -468,7 +470,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, } } - val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1); + val = malloc(2 * data_size + strlen("{ro,run,boot,nv}(blob)") + 1); if (!val) { ret = EFI_OUT_OF_RESOURCES; goto out; @@ -480,12 +482,16 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, * store attributes * TODO: several attributes are not supported */ - attributes &= (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS); + attributes &= (EFI_VARIABLE_NON_VOLATILE | + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS); s += sprintf(s, "{"); while (attributes) { u32 attr = 1 << (ffs(attributes) - 1); - if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) + if (attr == EFI_VARIABLE_NON_VOLATILE) + s += sprintf(s, "nv"); + else if (attr == EFI_VARIABLE_BOOTSERVICE_ACCESS) s += sprintf(s, "boot"); else if (attr == EFI_VARIABLE_RUNTIME_ACCESS) s += sprintf(s, "run"); -- cgit v1.2.3 From 366161cf976c41f2cfabbb896c8f9a94c31886ce Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 4 Jun 2019 15:52:09 +0900 Subject: efi_loader: bootmgr: make BootNext non-volatile Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- lib/efi_loader/efi_bootmgr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 43791422c8..b2102c5b5a 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -210,7 +210,8 @@ efi_status_t efi_bootmgr_load(efi_handle_t *handle) ret = EFI_CALL(efi_set_variable( L"BootNext", (efi_guid_t *)&efi_global_variable_guid, - 0, 0, &bootnext)); + EFI_VARIABLE_NON_VOLATILE, 0, + &bootnext)); /* load BootNext */ if (ret == EFI_SUCCESS) { -- cgit v1.2.3 From f658c2e190c3a45a94317f27ab53f2f7d8067d36 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 4 Jun 2019 15:52:10 +0900 Subject: cmd: efidebug: make some boot variables non-volatile Boot####, BootOrder and BootNext should be non-volatile. Signed-off-by: AKASHI Takahiro Signed-off-by: Heinrich Schuchardt --- cmd/efidebug.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index c4ac9dd634..e657226254 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -558,6 +558,7 @@ static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, } ret = EFI_CALL(RT->set_variable(var_name16, &guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, data)); @@ -909,6 +910,7 @@ static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag, guid = efi_global_variable_guid; size = sizeof(u16); ret = EFI_CALL(RT->set_variable(L"BootNext", &guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, &bootnext)); @@ -964,6 +966,7 @@ static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag, guid = efi_global_variable_guid; ret = EFI_CALL(RT->set_variable(L"BootOrder", &guid, + EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, size, bootorder)); -- cgit v1.2.3 From 4b27a761321fd17536e02644d0ec0373150eb570 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Tue, 4 Jun 2019 15:52:11 +0900 Subject: cmd: env: add -nv option for UEFI non-volatile variable With this option, -nv, at "setenv -e" command, a variable will be defined as non-volatile. Signed-off-by: AKASHI Takahiro Reviewed-by: Heinrich Schuchardt --- cmd/nvedit.c | 3 ++- cmd/nvedit_efi.c | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cmd/nvedit.c b/cmd/nvedit.c index 24a6cf7824..52c242b4f6 100644 --- a/cmd/nvedit.c +++ b/cmd/nvedit.c @@ -1344,8 +1344,9 @@ U_BOOT_CMD_COMPLETE( setenv, CONFIG_SYS_MAXARGS, 0, do_env_set, "set environment variables", #if defined(CONFIG_CMD_NVEDIT_EFI) - "-e name [value ...]\n" + "-e [-nv] name [value ...]\n" " - set UEFI variable 'name' to 'value' ...'\n" + " 'nv' option makes the variable non-volatile\n" " - delete UEFI variable 'name' if 'value' not specified\n" #endif "setenv [-f] name value ...\n" diff --git a/cmd/nvedit_efi.c b/cmd/nvedit_efi.c index ff8eaa1aad..60a8ac84c8 100644 --- a/cmd/nvedit_efi.c +++ b/cmd/nvedit_efi.c @@ -349,6 +349,7 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) u16 *var_name16 = NULL, *p; size_t len; efi_guid_t guid; + u32 attributes; efi_status_t ret; if (argc == 1) @@ -362,6 +363,16 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_FAILURE; } + attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS; + if (!strcmp(argv[1], "-nv")) { + attributes |= EFI_VARIABLE_NON_VOLATILE; + argc--; + argv++; + if (argc == 1) + return CMD_RET_SUCCESS; + } + var_name = argv[1]; if (argc == 2) { /* delete */ @@ -391,9 +402,7 @@ int do_env_set_efi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) utf8_utf16_strncpy(&p, var_name, len + 1); guid = efi_global_variable_guid; - ret = EFI_CALL(efi_set_variable(var_name16, &guid, - EFI_VARIABLE_BOOTSERVICE_ACCESS | - EFI_VARIABLE_RUNTIME_ACCESS, + ret = EFI_CALL(efi_set_variable(var_name16, &guid, attributes, size, value)); if (ret == EFI_SUCCESS) { ret = CMD_RET_SUCCESS; -- cgit v1.2.3