From f6e7b65380ddebea6f31a8456042074f59c17c98 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 26 Sep 2018 19:03:33 +0200 Subject: efi_selftest: simplify lib/efi_selftest/Makefile We should not make anything in lib/efi_selftest if CONFIG_CMD_BOOTEFI_SELFTEST is not defined. We can make that test in lib/Makefile Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/Makefile | 2 +- lib/efi_selftest/Makefile | 10 ++-------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 4d2e22027d0..8321355a44f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -8,7 +8,7 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_EFI_LOADER) += efi_driver/ obj-$(CONFIG_EFI_LOADER) += efi_loader/ -obj-$(CONFIG_EFI_LOADER) += efi_selftest/ +obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest/ obj-$(CONFIG_LZMA) += lzma/ obj-$(CONFIG_BZIP2) += bzip2/ obj-$(CONFIG_TIZEN) += tizen/ diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 2f55d9d66ff..0acd790550e 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -10,7 +10,7 @@ CFLAGS_REMOVE_efi_selftest_miniapp_exit.o := $(CFLAGS_NON_EFI) -Os CFLAGS_efi_selftest_miniapp_return.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os -obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ +obj-y += \ efi_selftest.o \ efi_selftest_bitblt.o \ efi_selftest_config_table.o \ @@ -37,20 +37,16 @@ efi_selftest_util.o \ efi_selftest_variables.o \ efi_selftest_watchdog.o -ifeq ($(CONFIG_CMD_BOOTEFI_SELFTEST),y) obj-$(CONFIG_CPU_V7) += efi_selftest_unaligned.o -endif ifeq ($(CONFIG_BLK)$(CONFIG_PARTITIONS),yy) -obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += efi_selftest_block_device.o +obj-y += efi_selftest_block_device.o endif # TODO: As of v2018.01 the relocation code for the EFI application cannot # be built on x86_64. ifeq ($(CONFIG_X86_64)$(CONFIG_SANDBOX),) -ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST),) - obj-y += \ efi_selftest_startimage_exit.o \ efi_selftest_startimage_return.o @@ -74,5 +70,3 @@ $(obj)/efi_selftest_startimage_exit.o: $(obj)/efi_miniapp_file_image_exit.h $(obj)/efi_selftest_startimage_return.o: $(obj)/efi_miniapp_file_image_return.h endif - -endif -- cgit v1.2.3 From 1c32bb101026eb8f693544824f015a6c3cfefe60 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 26 Sep 2018 19:05:58 +0200 Subject: efi_selftest: test handling of exceptions Test the handling of execptions by trying to execute an undefined instruction. For 32bit ARM we expect \selftest to be listed as loaded image. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_exception.c | 50 +++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_exception.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 0acd790550e..4b1c0bb84b1 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -21,6 +21,7 @@ efi_selftest_devicepath.o \ efi_selftest_devicepath_util.o \ efi_selftest_events.o \ efi_selftest_event_groups.o \ +efi_selftest_exception.o \ efi_selftest_exitbootservices.o \ efi_selftest_fdt.o \ efi_selftest_gop.o \ diff --git a/lib/efi_selftest/efi_selftest_exception.c b/lib/efi_selftest/efi_selftest_exception.c new file mode 100644 index 00000000000..2ac1796c3bd --- /dev/null +++ b/lib/efi_selftest/efi_selftest_exception.c @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_exception + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * Test the handling of execptions by trying to execute an undefined + * instruction. + */ + +#include + +/** + * undefined_instruction() - try to executed an undefined instruction + */ +static void undefined_instruction(void) +{ +#if defined(CONFIG_ARM) + /* + * 0xe7f...f. is undefined in ARM mode + * 0xde.. is undefined in Thumb mode + */ + asm volatile (".word 0xe7f7defb\n"); +#elif defined(CONFIG_RISCV) + asm volatile (".word 0xffffffff\n"); +#elif defined(CONFIG_X86) + asm volatile (".word 0xffff\n"); +#endif +} + +/** + * execute() - execute unit test + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + undefined_instruction(); + + efi_st_error("An undefined instruction exeption was not raised\n"); + + return EFI_ST_FAILURE; +} + +EFI_UNIT_TEST(exception) = { + .name = "exception", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .execute = execute, + .on_request = true, +}; -- cgit v1.2.3 From e706ed7f5b291282e8747e65c2f2d0e4f8ef5e03 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 16 Oct 2018 07:44:53 +0200 Subject: efi_loader: implement EFI_RESET_SHUTDOWN at boot time Allow an EFI application to shut down the system. If EFI_RESET_SHUTDOWN is issued call do_poweroff(). Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index f059dc97fd4..abcf03c5a42 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -141,7 +141,9 @@ static void EFIAPI efi_reset_system_boottime( do_reset(NULL, 0, 0, NULL); break; case EFI_RESET_SHUTDOWN: - /* We don't have anything to map this to */ +#ifdef CONFIG_CMD_POWEROFF + do_poweroff(NULL, 0, 0, NULL); +#endif break; } -- cgit v1.2.3 From 9b47f13bdfa459902001877e54ee506942762beb Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 28 Sep 2018 22:14:17 +0200 Subject: efi_loader: delete handles When the last protocol interface has been uninstalled remove the handle. Adjust ReinstallProtocol so that it does not remove the handle. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 81 ++++++++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index da978d2b34a..9440816f624 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1156,21 +1156,19 @@ static efi_status_t efi_disconnect_all_drivers( } /** - * efi_uninstall_protocol_interface() - uninstall protocol interface + * efi_uninstall_protocol() - uninstall protocol interface + * * @handle: handle from which the protocol shall be removed * @protocol: GUID of the protocol to be removed * @protocol_interface: interface to be removed * - * This function implements the UninstallProtocolInterface service. - * - * See the Unified Extensible Firmware Interface (UEFI) specification for - * details. + * This function DOES NOT delete a handle without installed protocol. * * Return: status code */ -static efi_status_t EFIAPI efi_uninstall_protocol_interface( - efi_handle_t handle, const efi_guid_t *protocol, - void *protocol_interface) +static efi_status_t efi_uninstall_protocol + (efi_handle_t handle, const efi_guid_t *protocol, + void *protocol_interface) { struct efi_object *efiobj; struct efi_handler *handler; @@ -1178,8 +1176,6 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface( struct efi_open_protocol_info_item *pos; efi_status_t r; - EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); - /* Check handle */ efiobj = efi_search_obj(handle); if (!efiobj) { @@ -1210,7 +1206,41 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface( } r = efi_remove_protocol(handle, protocol, protocol_interface); out: - return EFI_EXIT(r); + return r; +} + +/** + * efi_uninstall_protocol_interface() - uninstall protocol interface + * @handle: handle from which the protocol shall be removed + * @protocol: GUID of the protocol to be removed + * @protocol_interface: interface to be removed + * + * This function implements the UninstallProtocolInterface service. + * + * See the Unified Extensible Firmware Interface (UEFI) specification for + * details. + * + * Return: status code + */ +static efi_status_t EFIAPI efi_uninstall_protocol_interface + (efi_handle_t handle, const efi_guid_t *protocol, + void *protocol_interface) +{ + efi_status_t ret; + + EFI_ENTRY("%p, %pUl, %p", handle, protocol, protocol_interface); + + ret = efi_uninstall_protocol(handle, protocol, protocol_interface); + if (ret != EFI_SUCCESS) + goto out; + + /* If the last protocol has been removed, delete the handle. */ + if (list_empty(&handle->protocols)) { + list_del(&handle->link); + free(handle); + } +out: + return EFI_EXIT(ret); } /** @@ -2358,16 +2388,21 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( if (!protocol) break; protocol_interface = efi_va_arg(argptr, void*); - r = EFI_CALL(efi_uninstall_protocol_interface( - handle, protocol, - protocol_interface)); + r = efi_uninstall_protocol(handle, protocol, + protocol_interface); if (r != EFI_SUCCESS) break; i++; } efi_va_end(argptr); - if (r == EFI_SUCCESS) + if (r == EFI_SUCCESS) { + /* If the last protocol has been removed, delete the handle. */ + if (list_empty(&handle->protocols)) { + list_del(&handle->link); + free(handle); + } return EFI_EXIT(r); + } /* If an error occurred undo all changes. */ efi_va_start(argptr, handle); @@ -2828,13 +2863,19 @@ static efi_status_t EFIAPI efi_reinstall_protocol_interface( EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, old_interface, new_interface); - ret = EFI_CALL(efi_uninstall_protocol_interface(handle, protocol, - old_interface)); + + /* Uninstall protocol but do not delete handle */ + ret = efi_uninstall_protocol(handle, protocol, old_interface); if (ret != EFI_SUCCESS) goto out; - ret = EFI_CALL(efi_install_protocol_interface(&handle, protocol, - EFI_NATIVE_INTERFACE, - new_interface)); + + /* Install the new protocol */ + ret = efi_add_protocol(handle, protocol, new_interface); + /* + * The UEFI spec does not specify what should happen to the handle + * if in case of an error no protocol interface remains on the handle. + * So let's do nothing here. + */ if (ret != EFI_SUCCESS) goto out; /* -- cgit v1.2.3 From d8b2216c879ca8cf42de05c986136be70faf154d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 27 Sep 2018 20:44:40 +0200 Subject: efi_selftest: fix typos fix typos correct the header comment of efi_selftest_variables.c Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_config_table.c | 12 ++++++------ lib/efi_selftest/efi_selftest_controllers.c | 2 +- lib/efi_selftest/efi_selftest_crc32.c | 4 ++-- lib/efi_selftest/efi_selftest_event_groups.c | 4 ++-- lib/efi_selftest/efi_selftest_events.c | 2 +- lib/efi_selftest/efi_selftest_exception.c | 4 ++-- lib/efi_selftest/efi_selftest_fdt.c | 2 +- lib/efi_selftest/efi_selftest_textinput.c | 2 +- lib/efi_selftest/efi_selftest_tpl.c | 2 +- lib/efi_selftest/efi_selftest_variables.c | 6 ++---- lib/efi_selftest/efi_selftest_watchdog.c | 2 +- 11 files changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_config_table.c b/lib/efi_selftest/efi_selftest_config_table.c index 2aa3fc72847..0bc5da6b0ce 100644 --- a/lib/efi_selftest/efi_selftest_config_table.c +++ b/lib/efi_selftest/efi_selftest_config_table.c @@ -18,7 +18,7 @@ static efi_guid_t table_guid = 0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75); /* - * Notification function, increments the notfication count if parameter + * Notification function, increments the notification count if parameter * context is provided. * * @event notified event @@ -33,23 +33,23 @@ static void EFIAPI notify(struct efi_event *event, void *context) } /* - * Check crc32 of a table. + * Check CRC32 of a table. */ static int check_table(const void *table) { efi_status_t ret; u32 crc32, res; - /* Casting from const to not const */ + /* Casting from constant to not constant */ struct efi_table_hdr *hdr = (struct efi_table_hdr *)table; crc32 = hdr->crc32; /* - * Setting the crc32 of the 'const' table to zero is easier than + * Setting the CRC32 of the 'const' table to zero is easier than * copying */ hdr->crc32 = 0; ret = boottime->calculate_crc32(table, hdr->headersize, &res); - /* Reset table crc32 so it stays constant */ + /* Reset table CRC32 so it stays constant */ hdr->crc32 = crc32; if (ret != EFI_ST_SUCCESS) { efi_st_error("CalculateCrc32 failed\n"); @@ -203,7 +203,7 @@ static int execute(void) return EFI_ST_FAILURE; } if (tabcnt > 1) { - efi_st_error("Duplicate table guid\n"); + efi_st_error("Duplicate table GUID\n"); return EFI_ST_FAILURE; } if (table != &tables[1]) { diff --git a/lib/efi_selftest/efi_selftest_controllers.c b/lib/efi_selftest/efi_selftest_controllers.c index d08c377c72c..38720bb63d3 100644 --- a/lib/efi_selftest/efi_selftest_controllers.c +++ b/lib/efi_selftest/efi_selftest_controllers.c @@ -33,7 +33,7 @@ static efi_handle_t handle_driver; * Count child controllers * * @handle handle on which child controllers are installed - * @protocol protocol for which the child controlles where installed + * @protocol protocol for which the child controllers were installed * @count number of child controllers * @return status code */ diff --git a/lib/efi_selftest/efi_selftest_crc32.c b/lib/efi_selftest/efi_selftest_crc32.c index 8555b8f1140..4881e8ac6f2 100644 --- a/lib/efi_selftest/efi_selftest_crc32.c +++ b/lib/efi_selftest/efi_selftest_crc32.c @@ -5,7 +5,7 @@ * Copyright (c) 2018 Heinrich Schuchardt * * This unit test checks the CalculateCrc32 bootservice and checks the - * headers of the system table, the boot services tablle, and the runtime + * headers of the system table, the boot services table, and the runtime * services table before and after ExitBootServices(). */ @@ -19,7 +19,7 @@ static int check_table(const void *table) { efi_status_t ret; u32 crc32, res; - /* Casting from const to not const */ + /* Casting from constant to not constant */ struct efi_table_hdr *hdr = (struct efi_table_hdr *)table; if (!hdr->signature) { diff --git a/lib/efi_selftest/efi_selftest_event_groups.c b/lib/efi_selftest/efi_selftest_event_groups.c index 9b3c5132ef7..5a7980c5d0b 100644 --- a/lib/efi_selftest/efi_selftest_event_groups.c +++ b/lib/efi_selftest/efi_selftest_event_groups.c @@ -19,7 +19,7 @@ static efi_guid_t event_group = 0x0e, 0x5b, 0x45, 0xc0, 0x56, 0x91); /* - * Notification function, increments the notfication count if parameter + * Notification function, increments the notification count if parameter * context is provided. * * @event notified event @@ -114,7 +114,7 @@ static int execute(void) (unsigned int)i, (unsigned int)j, (unsigned int)counter[j]); efi_st_error( - "Nofification function not called\n"); + "Notification function not called\n"); return EFI_ST_FAILURE; } } diff --git a/lib/efi_selftest/efi_selftest_events.c b/lib/efi_selftest/efi_selftest_events.c index 47f9f99318d..ed99a538045 100644 --- a/lib/efi_selftest/efi_selftest_events.c +++ b/lib/efi_selftest/efi_selftest_events.c @@ -17,7 +17,7 @@ static unsigned int timer_ticks; static struct efi_boot_services *boottime; /* - * Notification function, increments the notfication count if parameter + * Notification function, increments the notification count if parameter * context is provided. * * @event notified event diff --git a/lib/efi_selftest/efi_selftest_exception.c b/lib/efi_selftest/efi_selftest_exception.c index 2ac1796c3bd..76cfb88d7c7 100644 --- a/lib/efi_selftest/efi_selftest_exception.c +++ b/lib/efi_selftest/efi_selftest_exception.c @@ -4,7 +4,7 @@ * * Copyright (c) 2018 Heinrich Schuchardt * - * Test the handling of execptions by trying to execute an undefined + * Test the handling of exceptions by trying to execute an undefined * instruction. */ @@ -37,7 +37,7 @@ static int execute(void) { undefined_instruction(); - efi_st_error("An undefined instruction exeption was not raised\n"); + efi_st_error("An undefined instruction exception was not raised\n"); return EFI_ST_FAILURE; } diff --git a/lib/efi_selftest/efi_selftest_fdt.c b/lib/efi_selftest/efi_selftest_fdt.c index c7bc242b5c4..d545d518120 100644 --- a/lib/efi_selftest/efi_selftest_fdt.c +++ b/lib/efi_selftest/efi_selftest_fdt.c @@ -16,7 +16,7 @@ static struct efi_boot_services *boottime; static const char *fdt; -/* This should be sufficent for */ +/* This should be sufficient for */ #define BUFFERSIZE 0x100000 static efi_guid_t fdt_guid = EFI_FDT_GUID; diff --git a/lib/efi_selftest/efi_selftest_textinput.c b/lib/efi_selftest/efi_selftest_textinput.c index 164fbffe6c2..b90671cdd20 100644 --- a/lib/efi_selftest/efi_selftest_textinput.c +++ b/lib/efi_selftest/efi_selftest_textinput.c @@ -5,7 +5,7 @@ * Copyright (c) 2018 Heinrich Schuchardt * * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_PROTOCOL. - * The unicode character and the scan code are printed for text + * The Unicode character and the scan code are printed for text * input. To run the test: * * setenv efi_selftest text input diff --git a/lib/efi_selftest/efi_selftest_tpl.c b/lib/efi_selftest/efi_selftest_tpl.c index 61ae46b7976..97d256abe4f 100644 --- a/lib/efi_selftest/efi_selftest_tpl.c +++ b/lib/efi_selftest/efi_selftest_tpl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * efi_selftest_events + * efi_selftest_tpl * * Copyright (c) 2017 Heinrich Schuchardt * diff --git a/lib/efi_selftest/efi_selftest_variables.c b/lib/efi_selftest/efi_selftest_variables.c index 146378fb9a2..e4c389a872f 100644 --- a/lib/efi_selftest/efi_selftest_variables.c +++ b/lib/efi_selftest/efi_selftest_variables.c @@ -4,10 +4,8 @@ * * Copyright (c) 2018 Heinrich Schuchardt * - * This unit test checks the following protocol services: - * ConnectController, DisconnectController, - * InstallProtocol, ReinstallProtocol, UninstallProtocol, - * OpenProtocol, CloseProtcol, OpenProtocolInformation + * This unit test checks the runtime services for variables: + * GetVariable, GetNextVariableName, SetVariable, QueryVariableInfo. */ #include diff --git a/lib/efi_selftest/efi_selftest_watchdog.c b/lib/efi_selftest/efi_selftest_watchdog.c index bff2330918c..cbc6761721c 100644 --- a/lib/efi_selftest/efi_selftest_watchdog.c +++ b/lib/efi_selftest/efi_selftest_watchdog.c @@ -35,7 +35,7 @@ static struct notify_context notification_context; static bool watchdog_reset; /* - * Notification function, increments the notfication count if parameter + * Notification function, increments the notification count if parameter * context is provided. * * @event notified event -- cgit v1.2.3 From faea1041054c355752dc61403fc885079daf015b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 26 Sep 2018 05:27:54 +0200 Subject: efi_loader: typedef struct efi_object *efi_handle_t All our handles point to a struct efi_object. So let's define the efi_handle_t accordingly. This helps us to discover coding errors much more easily. This becomes evident by the corrections to the usage of handles in this patch. Rename variable image_handle to image_obj where applicable. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 28 ++++++++++++++-------------- include/efi.h | 2 +- include/efi_api.h | 8 ++++---- lib/efi/efi.c | 2 +- lib/efi_loader/efi_boottime.c | 18 +++++++++--------- lib/efi_selftest/efi_selftest_devicepath.c | 2 +- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 4d68d807480..faa00f75c2a 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -345,7 +345,7 @@ static efi_status_t do_bootefi_exec(void *efi, efi_handle_t mem_handle = NULL; struct efi_device_path *memdp = NULL; efi_status_t ret; - struct efi_loaded_image_obj *image_handle = NULL; + struct efi_loaded_image_obj *image_obj = NULL; struct efi_loaded_image *loaded_image_info = NULL; EFIAPI efi_status_t (*entry)(efi_handle_t image_handle, @@ -376,7 +376,7 @@ static efi_status_t do_bootefi_exec(void *efi, assert(device_path && image_path); } - ret = efi_setup_loaded_image(device_path, image_path, &image_handle, + ret = efi_setup_loaded_image(device_path, image_path, &image_obj, &loaded_image_info); if (ret != EFI_SUCCESS) goto exit; @@ -384,7 +384,7 @@ static efi_status_t do_bootefi_exec(void *efi, /* Transfer environment variable bootargs as load options */ set_load_options(loaded_image_info, "bootargs"); /* Load the EFI payload */ - entry = efi_load_pe(image_handle, efi, loaded_image_info); + entry = efi_load_pe(image_obj, efi, loaded_image_info); if (!entry) { ret = EFI_LOAD_ERROR; goto exit; @@ -405,8 +405,8 @@ static efi_status_t do_bootefi_exec(void *efi, /* Call our payload! */ debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry); - if (setjmp(&image_handle->exit_jmp)) { - ret = image_handle->exit_status; + if (setjmp(&image_obj->exit_jmp)) { + ret = image_obj->exit_status; goto exit; } @@ -418,7 +418,7 @@ static efi_status_t do_bootefi_exec(void *efi, /* Move into EL2 and keep running there */ armv8_switch_to_el2((ulong)entry, - (ulong)image_handle, + (ulong)&image_obj->parent, (ulong)&systab, 0, (ulong)efi_run_in_el2, ES_TO_AARCH64); @@ -435,7 +435,7 @@ static efi_status_t do_bootefi_exec(void *efi, secure_ram_addr(_do_nonsec_entry)( efi_run_in_hyp, (uintptr_t)entry, - (uintptr_t)image_handle, + (uintptr_t)&image_obj->parent, (uintptr_t)&systab); /* Should never reach here, efi exits with longjmp */ @@ -443,12 +443,12 @@ static efi_status_t do_bootefi_exec(void *efi, } #endif - ret = efi_do_enter(image_handle, &systab, entry); + ret = efi_do_enter(&image_obj->parent, &systab, entry); exit: /* image has returned, loaded-image obj goes *poof*: */ - if (image_handle) - efi_delete_handle(&image_handle->parent); + if (image_obj) + efi_delete_handle(&image_obj->parent); if (mem_handle) efi_delete_handle(mem_handle); @@ -527,7 +527,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif #ifdef CONFIG_CMD_BOOTEFI_SELFTEST if (!strcmp(argv[1], "selftest")) { - struct efi_loaded_image_obj *image_handle; + struct efi_loaded_image_obj *image_obj; struct efi_loaded_image *loaded_image_info; /* Construct a dummy device path. */ @@ -537,7 +537,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest"); r = efi_setup_loaded_image(bootefi_device_path, - bootefi_image_path, &image_handle, + bootefi_image_path, &image_obj, &loaded_image_info); if (r != EFI_SUCCESS) return CMD_RET_FAILURE; @@ -546,10 +546,10 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) /* Transfer environment variable efi_selftest as load options */ set_load_options(loaded_image_info, "efi_selftest"); /* Execute the test */ - r = efi_selftest(image_handle, &systab); + r = efi_selftest(&image_obj->parent, &systab); efi_restore_gd(); free(loaded_image_info->load_options); - efi_delete_handle(&image_handle->parent); + efi_delete_handle(&image_obj->parent); return r != EFI_SUCCESS; } else #endif diff --git a/include/efi.h b/include/efi.h index b1deb609b46..b5e2c64f38b 100644 --- a/include/efi.h +++ b/include/efi.h @@ -96,7 +96,7 @@ typedef struct { typedef unsigned long efi_status_t; typedef u64 efi_physical_addr_t; typedef u64 efi_virtual_addr_t; -typedef void *efi_handle_t; +typedef struct efi_object *efi_handle_t; #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \ diff --git a/include/efi_api.h b/include/efi_api.h index e850b951eb0..88a60070f6a 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -85,10 +85,10 @@ struct efi_boot_services { efi_status_t (EFIAPI *check_event)(struct efi_event *event); #define EFI_NATIVE_INTERFACE 0x00000000 efi_status_t (EFIAPI *install_protocol_interface)( - void **handle, const efi_guid_t *protocol, + efi_handle_t *handle, const efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface); efi_status_t (EFIAPI *reinstall_protocol_interface)( - void *handle, const efi_guid_t *protocol, + efi_handle_t handle, const efi_guid_t *protocol, void *old_interface, void *new_interface); efi_status_t (EFIAPI *uninstall_protocol_interface)( efi_handle_t handle, const efi_guid_t *protocol, @@ -164,9 +164,9 @@ struct efi_boot_services { efi_status_t (EFIAPI *locate_protocol)(const efi_guid_t *protocol, void *registration, void **protocol_interface); efi_status_t (EFIAPI *install_multiple_protocol_interfaces)( - void **handle, ...); + efi_handle_t *handle, ...); efi_status_t (EFIAPI *uninstall_multiple_protocol_interfaces)( - void *handle, ...); + efi_handle_t handle, ...); efi_status_t (EFIAPI *calculate_crc32)(const void *data, efi_uintn_t data_size, u32 *crc32); diff --git a/lib/efi/efi.c b/lib/efi/efi.c index c6639f96cc4..2c6a50824fd 100644 --- a/lib/efi/efi.c +++ b/lib/efi/efi.c @@ -69,7 +69,7 @@ int efi_init(struct efi_priv *priv, const char *banner, efi_handle_t image, efi_putc(priv, ' '); ret = boot->open_protocol(priv->parent_image, &loaded_image_guid, - (void **)&loaded_image, &priv->parent_image, + (void **)&loaded_image, priv->parent_image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); if (ret) { efi_puts(priv, "Failed to get loaded image protocol\n"); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9440816f624..917d2294d16 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1019,7 +1019,7 @@ efi_status_t efi_add_protocol(const efi_handle_t handle, * Return: status code */ static efi_status_t EFIAPI efi_install_protocol_interface( - void **handle, const efi_guid_t *protocol, + efi_handle_t *handle, const efi_guid_t *protocol, int protocol_interface_type, void *protocol_interface) { efi_status_t r; @@ -2309,8 +2309,8 @@ out: * * Return: status code */ -static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( - void **handle, ...) +static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces + (efi_handle_t *handle, ...) { EFI_ENTRY("%p", handle); @@ -2346,7 +2346,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( for (; i; --i) { protocol = efi_va_arg(argptr, efi_guid_t*); protocol_interface = efi_va_arg(argptr, void*); - EFI_CALL(efi_uninstall_protocol_interface(handle, protocol, + EFI_CALL(efi_uninstall_protocol_interface(*handle, protocol, protocol_interface)); } efi_va_end(argptr); @@ -2369,7 +2369,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( * Return: status code */ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( - void *handle, ...) + efi_handle_t handle, ...) { EFI_ENTRY("%p", handle); @@ -2588,10 +2588,10 @@ out: * * Return: status code */ -static efi_status_t EFIAPI efi_open_protocol( - void *handle, const efi_guid_t *protocol, - void **protocol_interface, void *agent_handle, - void *controller_handle, uint32_t attributes) +static efi_status_t EFIAPI efi_open_protocol + (efi_handle_t handle, const efi_guid_t *protocol, + void **protocol_interface, efi_handle_t agent_handle, + efi_handle_t controller_handle, uint32_t attributes) { struct efi_handler *handler; efi_status_t r = EFI_INVALID_PARAMETER; diff --git a/lib/efi_selftest/efi_selftest_devicepath.c b/lib/efi_selftest/efi_selftest_devicepath.c index adcf531e90a..105ce2c92b3 100644 --- a/lib/efi_selftest/efi_selftest_devicepath.c +++ b/lib/efi_selftest/efi_selftest_devicepath.c @@ -257,7 +257,7 @@ static int teardown(void) static int execute(void) { struct efi_device_path *remaining_dp; - void *handle; + efi_handle_t handle; /* * This device path node ends with the letter 't' of 'u-boot'. * The following '.bin' does not belong to the node but is -- cgit v1.2.3 From fae0118e7ae3a209b30205f02e8349c36ec0dbd9 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 26 Sep 2018 05:27:55 +0200 Subject: efi_loader: eliminate handle member A pointer to a struct efi_object is a handle. We do not need any handle member in this structure. Let's eliminate it. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 26 ++++++++++++------ lib/efi_loader/efi_boottime.c | 59 ++++++++++++++++++++-------------------- lib/efi_loader/efi_console.c | 20 +++++++------- lib/efi_loader/efi_device_path.c | 2 +- lib/efi_loader/efi_disk.c | 14 +++++----- lib/efi_loader/efi_gop.c | 2 +- lib/efi_loader/efi_net.c | 6 ++-- 7 files changed, 68 insertions(+), 61 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 1417c3588fb..1c79905aac7 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -167,20 +167,28 @@ struct efi_handler { struct list_head open_infos; }; -/* - * UEFI has a poor man's OO model where one "object" can be polymorphic and have - * multiple different protocols (classes) attached to it. +/** + * struct efi_object - dereferenced EFI handle + * + * @link: pointers to put the handle into a linked list + * @protocols: linked list with the protocol interfaces installed on this + * handle + * + * UEFI offers a flexible and expandable object model. The objects in the UEFI + * API are devices, drivers, and loaded images. struct efi_object is our storage + * structure for these objects. + * + * When including this structure into a larger structure always put it first so + * that when deleting a handle the whole encompassing structure can be freed. * - * This struct is the parent struct for all of our actual implementation objects - * that can include it to make themselves an EFI object + * A pointer to this structure is referred to as a handle. Typedef efi_handle_t + * has been created for such pointers. */ struct efi_object { /* Every UEFI object is part of a global object list */ struct list_head link; /* The list of protocols */ struct list_head protocols; - /* The object spawner can either use this for data or as identifier */ - void *handle; }; /** @@ -290,11 +298,11 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map); /* Call this to set the current device name */ void efi_set_bootdev(const char *dev, const char *devnr, const char *path); /* Add a new object to the object list. */ -void efi_add_handle(struct efi_object *obj); +void efi_add_handle(efi_handle_t obj); /* Create handle */ efi_status_t efi_create_handle(efi_handle_t *handle); /* Delete handle */ -void efi_delete_handle(struct efi_object *obj); +void efi_delete_handle(efi_handle_t obj); /* Call this to validate a handle and find the EFI object for it */ struct efi_object *efi_search_obj(const efi_handle_t handle); /* Find a protocol on a handle */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 917d2294d16..397647073c1 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -416,13 +416,12 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer) * * The protocols list is initialized. The object handle is set. */ -void efi_add_handle(struct efi_object *obj) +void efi_add_handle(efi_handle_t handle) { - if (!obj) + if (!handle) return; - INIT_LIST_HEAD(&obj->protocols); - obj->handle = obj; - list_add_tail(&obj->link, &efi_obj_list); + INIT_LIST_HEAD(&handle->protocols); + list_add_tail(&handle->link, &efi_obj_list); } /** @@ -440,7 +439,7 @@ efi_status_t efi_create_handle(efi_handle_t *handle) return EFI_OUT_OF_RESOURCES; efi_add_handle(obj); - *handle = obj->handle; + *handle = obj; return EFI_SUCCESS; } @@ -536,13 +535,13 @@ efi_status_t efi_remove_all_protocols(const efi_handle_t handle) * * @obj: handle to delete */ -void efi_delete_handle(struct efi_object *obj) +void efi_delete_handle(efi_handle_t handle) { - if (!obj) + if (!handle) return; - efi_remove_all_protocols(obj->handle); - list_del(&obj->link); - free(obj); + efi_remove_all_protocols(handle); + list_del(&handle->link); + free(handle); } /** @@ -927,7 +926,7 @@ struct efi_object *efi_search_obj(const efi_handle_t handle) struct efi_object *efiobj; list_for_each_entry(efiobj, &efi_obj_list, link) { - if (efiobj->handle == handle) + if (efiobj == handle) return efiobj; } @@ -1052,7 +1051,7 @@ out: /** * efi_get_drivers() - get all drivers associated to a controller - * @efiobj: handle of the controller + * @handle: handle of the controller * @protocol: protocol GUID (optional) * @number_of_drivers: number of child controllers * @driver_handle_buffer: handles of the the drivers @@ -1061,7 +1060,7 @@ out: * * Return: status code */ -static efi_status_t efi_get_drivers(struct efi_object *efiobj, +static efi_status_t efi_get_drivers(efi_handle_t handle, const efi_guid_t *protocol, efi_uintn_t *number_of_drivers, efi_handle_t **driver_handle_buffer) @@ -1072,7 +1071,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj, bool duplicate; /* Count all driver associations */ - list_for_each_entry(handler, &efiobj->protocols, link) { + list_for_each_entry(handler, &handle->protocols, link) { if (protocol && guidcmp(handler->guid, protocol)) continue; list_for_each_entry(item, &handler->open_infos, link) { @@ -1090,7 +1089,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj, if (!*driver_handle_buffer) return EFI_OUT_OF_RESOURCES; /* Collect unique driver handles */ - list_for_each_entry(handler, &efiobj->protocols, link) { + list_for_each_entry(handler, &handle->protocols, link) { if (protocol && guidcmp(handler->guid, protocol)) continue; list_for_each_entry(item, &handler->open_infos, link) { @@ -1117,7 +1116,7 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj, /** * efi_disconnect_all_drivers() - disconnect all drivers from a controller - * @efiobj: handle of the controller + * @handle: handle of the controller * @protocol: protocol GUID (optional) * @child_handle: handle of the child to destroy * @@ -1128,16 +1127,16 @@ static efi_status_t efi_get_drivers(struct efi_object *efiobj, * * Return: status code */ -static efi_status_t efi_disconnect_all_drivers( - struct efi_object *efiobj, - const efi_guid_t *protocol, - efi_handle_t child_handle) +static efi_status_t efi_disconnect_all_drivers + (efi_handle_t handle, + const efi_guid_t *protocol, + efi_handle_t child_handle) { efi_uintn_t number_of_drivers; efi_handle_t *driver_handle_buffer; efi_status_t r, ret; - ret = efi_get_drivers(efiobj, protocol, &number_of_drivers, + ret = efi_get_drivers(handle, protocol, &number_of_drivers, &driver_handle_buffer); if (ret != EFI_SUCCESS) return ret; @@ -1145,7 +1144,7 @@ static efi_status_t efi_disconnect_all_drivers( ret = EFI_NOT_FOUND; while (number_of_drivers) { r = EFI_CALL(efi_disconnect_controller( - efiobj->handle, + handle, driver_handle_buffer[--number_of_drivers], child_handle)); if (r == EFI_SUCCESS) @@ -1270,7 +1269,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify( * @search_type: selection criterion * @protocol: GUID of the protocol * @search_key: registration key - * @efiobj: handle + * @handle: handle * * See the documentation of the LocateHandle service in the UEFI specification. * @@ -1278,7 +1277,7 @@ static efi_status_t EFIAPI efi_register_protocol_notify( */ static int efi_search(enum efi_locate_search_type search_type, const efi_guid_t *protocol, void *search_key, - struct efi_object *efiobj) + efi_handle_t handle) { efi_status_t ret; @@ -1289,7 +1288,7 @@ static int efi_search(enum efi_locate_search_type search_type, /* TODO: RegisterProtocolNotify is not implemented yet */ return -1; case BY_PROTOCOL: - ret = efi_search_protocol(efiobj->handle, protocol, NULL); + ret = efi_search_protocol(handle, protocol, NULL); return (ret != EFI_SUCCESS); default: /* Invalid search type */ @@ -1361,7 +1360,7 @@ static efi_status_t efi_locate_handle( /* Then fill the array */ list_for_each_entry(efiobj, &efi_obj_list, link) { if (!efi_search(search_type, protocol, search_key, efiobj)) - *buffer++ = efiobj->handle; + *buffer++ = efiobj; } return EFI_SUCCESS; @@ -1536,7 +1535,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, * When asking for the device path interface, return * bootefi_device_path */ - ret = efi_add_protocol(obj->parent.handle, + ret = efi_add_protocol(&obj->parent, &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) goto failure; @@ -1546,7 +1545,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, * When asking for the loaded_image interface, just * return handle which points to loaded_image_info */ - ret = efi_add_protocol(obj->parent.handle, + ret = efi_add_protocol(&obj->parent, &efi_guid_loaded_image, info); if (ret != EFI_SUCCESS) goto failure; @@ -2206,7 +2205,7 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol, efiobj = list_entry(lhandle, struct efi_object, link); - ret = efi_search_protocol(efiobj->handle, protocol, &handler); + ret = efi_search_protocol(efiobj, protocol, &handler); if (ret == EFI_SUCCESS) { *protocol_interface = handler->protocol_interface; return EFI_EXIT(EFI_SUCCESS); diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 0225222a616..7274d752045 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -1051,34 +1051,34 @@ static void EFIAPI efi_key_notify(struct efi_event *event, void *context) efi_status_t efi_console_register(void) { efi_status_t r; - struct efi_object *efi_console_output_obj; - struct efi_object *efi_console_input_obj; + efi_handle_t console_output_handle; + efi_handle_t console_input_handle; /* Set up mode information */ query_console_size(); /* Create handles */ - r = efi_create_handle((efi_handle_t *)&efi_console_output_obj); + r = efi_create_handle(&console_output_handle); if (r != EFI_SUCCESS) goto out_of_memory; - r = efi_add_protocol(efi_console_output_obj->handle, + r = efi_add_protocol(console_output_handle, &efi_guid_text_output_protocol, &efi_con_out); if (r != EFI_SUCCESS) goto out_of_memory; - systab.con_out_handle = efi_console_output_obj->handle; - systab.stderr_handle = efi_console_output_obj->handle; + systab.con_out_handle = console_output_handle; + systab.stderr_handle = console_output_handle; - r = efi_create_handle((efi_handle_t *)&efi_console_input_obj); + r = efi_create_handle(&console_input_handle); if (r != EFI_SUCCESS) goto out_of_memory; - r = efi_add_protocol(efi_console_input_obj->handle, + r = efi_add_protocol(console_input_handle, &efi_guid_text_input_protocol, &efi_con_in); if (r != EFI_SUCCESS) goto out_of_memory; - systab.con_in_handle = efi_console_input_obj->handle; - r = efi_add_protocol(efi_console_input_obj->handle, + systab.con_in_handle = console_input_handle; + r = efi_add_protocol(console_input_handle, &efi_guid_text_input_ex_protocol, &efi_con_in_ex); if (r != EFI_SUCCESS) goto out_of_memory; diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 46a24f78824..2b5d0671046 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -150,7 +150,7 @@ static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path, struct efi_device_path *obj_dp; efi_status_t ret; - ret = efi_search_protocol(efiobj->handle, + ret = efi_search_protocol(efiobj, &efi_guid_device_path, &handler); if (ret != EFI_SUCCESS) continue; diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index 13fcc1b471c..e861feee4aa 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -258,18 +258,18 @@ static efi_status_t efi_disk_add_dev( diskobj->dp = efi_dp_from_part(desc, part); } diskobj->part = part; - ret = efi_add_protocol(diskobj->parent.handle, &efi_block_io_guid, + ret = efi_add_protocol(&diskobj->parent, &efi_block_io_guid, &diskobj->ops); if (ret != EFI_SUCCESS) return ret; - ret = efi_add_protocol(diskobj->parent.handle, &efi_guid_device_path, + ret = efi_add_protocol(&diskobj->parent, &efi_guid_device_path, diskobj->dp); if (ret != EFI_SUCCESS) return ret; if (part >= 1) { diskobj->volume = efi_simple_file_system(desc, part, diskobj->dp); - ret = efi_add_protocol(diskobj->parent.handle, + ret = efi_add_protocol(&diskobj->parent, &efi_simple_file_system_protocol_guid, diskobj->volume); if (ret != EFI_SUCCESS) @@ -381,7 +381,7 @@ efi_status_t efi_disk_register(void) /* Partitions show up as block devices in EFI */ disks += efi_disk_create_partitions( - disk->parent.handle, desc, if_typename, + &disk->parent, desc, if_typename, desc->devnum, dev->name); } #else @@ -426,9 +426,9 @@ efi_status_t efi_disk_register(void) disks++; /* Partitions show up as block devices in EFI */ - disks += efi_disk_create_partitions( - disk->parent.handle, desc, - if_typename, i, devname); + disks += efi_disk_create_partitions + (&disk->parent, desc, + if_typename, i, devname); } } #endif diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index a4aa9bcf61a..a13c626f6fe 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -442,7 +442,7 @@ efi_status_t efi_gop_register(void) efi_add_handle(&gopobj->parent); /* Fill in object data */ - ret = efi_add_protocol(gopobj->parent.handle, &efi_gop_guid, + ret = efi_add_protocol(&gopobj->parent, &efi_gop_guid, &gopobj->ops); if (ret != EFI_SUCCESS) { printf("ERROR: Failure adding gop protocol\n"); diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 4e8b2d597df..ecc05f258c7 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -328,15 +328,15 @@ efi_status_t efi_net_register(void) efi_add_handle(&netobj->parent); /* Fill in object data */ - r = efi_add_protocol(netobj->parent.handle, &efi_net_guid, + r = efi_add_protocol(&netobj->parent, &efi_net_guid, &netobj->net); if (r != EFI_SUCCESS) goto failure_to_add_protocol; - r = efi_add_protocol(netobj->parent.handle, &efi_guid_device_path, + r = efi_add_protocol(&netobj->parent, &efi_guid_device_path, efi_dp_from_eth()); if (r != EFI_SUCCESS) goto failure_to_add_protocol; - r = efi_add_protocol(netobj->parent.handle, &efi_pxe_guid, + r = efi_add_protocol(&netobj->parent, &efi_pxe_guid, &netobj->pxe); if (r != EFI_SUCCESS) goto failure_to_add_protocol; -- cgit v1.2.3 From d39646a38b504c377b5bcf282a2a9407f99b5f57 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 26 Sep 2018 05:27:56 +0200 Subject: efi_loader: rename parent to header Rename the component parent of some EFI objects to header. This avoids misunderstandings. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 12 ++++++------ include/efi_loader.h | 9 +++++++-- lib/efi_loader/efi_boottime.c | 6 +++--- lib/efi_loader/efi_disk.c | 38 +++++++++++++++++++++----------------- lib/efi_loader/efi_gop.c | 21 ++++++++++++++------- lib/efi_loader/efi_net.c | 22 ++++++++++++++-------- 6 files changed, 65 insertions(+), 43 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index faa00f75c2a..a1650d6cd1f 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -418,7 +418,7 @@ static efi_status_t do_bootefi_exec(void *efi, /* Move into EL2 and keep running there */ armv8_switch_to_el2((ulong)entry, - (ulong)&image_obj->parent, + (ulong)&image_obj->header, (ulong)&systab, 0, (ulong)efi_run_in_el2, ES_TO_AARCH64); @@ -435,7 +435,7 @@ static efi_status_t do_bootefi_exec(void *efi, secure_ram_addr(_do_nonsec_entry)( efi_run_in_hyp, (uintptr_t)entry, - (uintptr_t)&image_obj->parent, + (uintptr_t)&image_obj->header, (uintptr_t)&systab); /* Should never reach here, efi exits with longjmp */ @@ -443,12 +443,12 @@ static efi_status_t do_bootefi_exec(void *efi, } #endif - ret = efi_do_enter(&image_obj->parent, &systab, entry); + ret = efi_do_enter(&image_obj->header, &systab, entry); exit: /* image has returned, loaded-image obj goes *poof*: */ if (image_obj) - efi_delete_handle(&image_obj->parent); + efi_delete_handle(&image_obj->header); if (mem_handle) efi_delete_handle(mem_handle); @@ -546,10 +546,10 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) /* Transfer environment variable efi_selftest as load options */ set_load_options(loaded_image_info, "efi_selftest"); /* Execute the test */ - r = efi_selftest(&image_obj->parent, &systab); + r = efi_selftest(&image_obj->header, &systab); efi_restore_gd(); free(loaded_image_info->load_options); - efi_delete_handle(&image_obj->parent); + efi_delete_handle(&image_obj->header); return r != EFI_SUCCESS; } else #endif diff --git a/include/efi_loader.h b/include/efi_loader.h index 1c79905aac7..7a8aa2913a1 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -193,10 +193,15 @@ struct efi_object { /** * struct efi_loaded_image_obj - handle of a loaded image + * + * @header: EFI object header + * @reloc_base: base address for the relocated image + * @reloc_size: size of the relocated image + * @exit_jmp: long jump buffer for returning form started image + * @entry: entry address of the relocated image */ struct efi_loaded_image_obj { - /* Generic EFI object parent class data */ - struct efi_object parent; + struct efi_object header; void *reloc_base; aligned_u64 reloc_size; efi_status_t exit_status; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 397647073c1..e3d911fad67 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1518,7 +1518,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, } /* Add internal object to object list */ - efi_add_handle(&obj->parent); + efi_add_handle(&obj->header); if (info_ptr) *info_ptr = info; @@ -1535,7 +1535,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, * When asking for the device path interface, return * bootefi_device_path */ - ret = efi_add_protocol(&obj->parent, + ret = efi_add_protocol(&obj->header, &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) goto failure; @@ -1545,7 +1545,7 @@ efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path, * When asking for the loaded_image interface, just * return handle which points to loaded_image_info */ - ret = efi_add_protocol(&obj->parent, + ret = efi_add_protocol(&obj->header, &efi_guid_loaded_image, info); if (ret != EFI_SUCCESS) goto failure; diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c index e861feee4aa..c037526ad2d 100644 --- a/lib/efi_loader/efi_disk.c +++ b/lib/efi_loader/efi_disk.c @@ -14,26 +14,30 @@ const efi_guid_t efi_block_io_guid = BLOCK_IO_GUID; +/** + * struct efi_disk_obj - EFI disk object + * + * @header: EFI object header + * @ops: EFI disk I/O protocol interface + * @ifname: interface name for block device + * @dev_index: device index of block device + * @media: block I/O media information + * @dp: device path to the block device + * @part: partition + * @volume: simple file system protocol of the partition + * @offset: offset into disk for simple partition + * @desc: internal block device descriptor + */ struct efi_disk_obj { - /* Generic EFI object parent class data */ - struct efi_object parent; - /* EFI Interface callback struct for block I/O */ + struct efi_object header; struct efi_block_io ops; - /* U-Boot ifname for block device */ const char *ifname; - /* U-Boot dev_index for block device */ int dev_index; - /* EFI Interface Media descriptor struct, referenced by ops */ struct efi_block_io_media media; - /* EFI device path to this block device */ struct efi_device_path *dp; - /* partition # */ unsigned int part; - /* handle to filesys proto (for partition objects) */ struct efi_simple_file_system_protocol *volume; - /* Offset into disk for simple partitions */ lbaint_t offset; - /* Internal block device */ struct blk_desc *desc; }; @@ -246,7 +250,7 @@ static efi_status_t efi_disk_add_dev( return EFI_OUT_OF_RESOURCES; /* Hook up to the device list */ - efi_add_handle(&diskobj->parent); + efi_add_handle(&diskobj->header); /* Fill in object data */ if (part) { @@ -258,18 +262,18 @@ static efi_status_t efi_disk_add_dev( diskobj->dp = efi_dp_from_part(desc, part); } diskobj->part = part; - ret = efi_add_protocol(&diskobj->parent, &efi_block_io_guid, + ret = efi_add_protocol(&diskobj->header, &efi_block_io_guid, &diskobj->ops); if (ret != EFI_SUCCESS) return ret; - ret = efi_add_protocol(&diskobj->parent, &efi_guid_device_path, + ret = efi_add_protocol(&diskobj->header, &efi_guid_device_path, diskobj->dp); if (ret != EFI_SUCCESS) return ret; if (part >= 1) { diskobj->volume = efi_simple_file_system(desc, part, diskobj->dp); - ret = efi_add_protocol(&diskobj->parent, + ret = efi_add_protocol(&diskobj->header, &efi_simple_file_system_protocol_guid, diskobj->volume); if (ret != EFI_SUCCESS) @@ -381,7 +385,7 @@ efi_status_t efi_disk_register(void) /* Partitions show up as block devices in EFI */ disks += efi_disk_create_partitions( - &disk->parent, desc, if_typename, + &disk->header, desc, if_typename, desc->devnum, dev->name); } #else @@ -427,7 +431,7 @@ efi_status_t efi_disk_register(void) /* Partitions show up as block devices in EFI */ disks += efi_disk_create_partitions - (&disk->parent, desc, + (&disk->header, desc, if_typename, i, devname); } } diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index a13c626f6fe..fbd5d97de97 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -16,15 +16,22 @@ DECLARE_GLOBAL_DATA_PTR; static const efi_guid_t efi_gop_guid = EFI_GOP_GUID; +/** + * struct efi_gop_obj - graphical output protocol object + * + * @header: EFI object header + * @ops: graphical output protocol interface + * @info: graphical output mode information + * @mode: graphical output mode + * @bpix: bits per pixel + * @fb: frame buffer + */ struct efi_gop_obj { - /* Generic EFI object parent class data */ - struct efi_object parent; - /* EFI Interface callback struct for gop */ + struct efi_object header; struct efi_gop ops; - /* The only mode we support */ struct efi_gop_mode_info info; struct efi_gop_mode mode; - /* Fields we only have acces to during init */ + /* Fields we only have access to during init */ u32 bpix; void *fb; }; @@ -439,10 +446,10 @@ efi_status_t efi_gop_register(void) } /* Hook up to the device list */ - efi_add_handle(&gopobj->parent); + efi_add_handle(&gopobj->header); /* Fill in object data */ - ret = efi_add_protocol(&gopobj->parent, &efi_gop_guid, + ret = efi_add_protocol(&gopobj->header, &efi_gop_guid, &gopobj->ops); if (ret != EFI_SUCCESS) { printf("ERROR: Failure adding gop protocol\n"); diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index ecc05f258c7..c4f35cd50d3 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -24,13 +24,19 @@ static struct efi_event *network_timer_event; */ static struct efi_event *wait_for_packet; +/** + * struct efi_net_obj - EFI object representing a network interface + * + * @header: EFI object header + * @net: simple network protocol interface + * @net_mode: status of the network interface + * @pxe: PXE base code protocol interface + * @pxe_mode: status of the PXE base code protocol + */ struct efi_net_obj { - /* Generic EFI object parent class data */ - struct efi_object parent; - /* EFI Interface callback struct for network */ + struct efi_object header; struct efi_simple_network net; struct efi_simple_network_mode net_mode; - /* PXE struct to transmit dhcp data */ struct efi_pxe pxe; struct efi_pxe_mode pxe_mode; }; @@ -325,18 +331,18 @@ efi_status_t efi_net_register(void) } /* Hook net up to the device list */ - efi_add_handle(&netobj->parent); + efi_add_handle(&netobj->header); /* Fill in object data */ - r = efi_add_protocol(&netobj->parent, &efi_net_guid, + r = efi_add_protocol(&netobj->header, &efi_net_guid, &netobj->net); if (r != EFI_SUCCESS) goto failure_to_add_protocol; - r = efi_add_protocol(&netobj->parent, &efi_guid_device_path, + r = efi_add_protocol(&netobj->header, &efi_guid_device_path, efi_dp_from_eth()); if (r != EFI_SUCCESS) goto failure_to_add_protocol; - r = efi_add_protocol(&netobj->parent, &efi_pxe_guid, + r = efi_add_protocol(&netobj->header, &efi_pxe_guid, &netobj->pxe); if (r != EFI_SUCCESS) goto failure_to_add_protocol; -- cgit v1.2.3 From 87fc275caccfc6fdd2defba570c188f6c5fb15e7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 24 Sep 2018 23:53:51 +0200 Subject: efi_selftest: use CR LF in helloworld The UEFI spec defines that a line feed moves the cursor to the next line and (only) a carriage return moves the cursor to the beginning of the line. So we should issue CR LF when we want to get to the start of the next line. Add some comments. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/helloworld.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/lib/efi_loader/helloworld.c b/lib/efi_loader/helloworld.c index 3b8de5b4ea7..2905479e658 100644 --- a/lib/efi_loader/helloworld.c +++ b/lib/efi_loader/helloworld.c @@ -17,6 +17,16 @@ static const efi_guid_t fdt_guid = EFI_FDT_GUID; static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID; static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID; +/** + * hw_memcmp() - compare memory areas + * + * @buf1: pointer to first area + * @buf2: pointer to second area + * @length: number of bytes to compare + * Return: 0 if both memory areas are the same, otherwise the sign of the + * result value is the same as the sign of ghe difference between + * the first differing pair of bytes taken as u8. + */ static int hw_memcmp(const void *buf1, const void *buf2, size_t length) { const u8 *pos1 = buf1; @@ -31,12 +41,12 @@ static int hw_memcmp(const void *buf1, const void *buf2, size_t length) return 0; } -/* - * Entry point of the EFI application. +/** + * efi_main() - entry point of the EFI application. * - * @handle handle of the loaded image - * @systable system table - * @return status code + * @handle: handle of the loaded image + * @systable: system table + * @return: status code */ efi_status_t EFIAPI efi_main(efi_handle_t handle, struct efi_system_table *systable) @@ -48,7 +58,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, efi_uintn_t i; u16 rev[] = L"0.0.0"; - con_out->output_string(con_out, L"Hello, world!\n"); + /* UEFI requires CR LF */ + con_out->output_string(con_out, L"Hello, world!\r\n"); /* Print the revision number */ rev[0] = (systable->hdr.revision >> 16) + '0'; @@ -65,27 +76,30 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, con_out->output_string(con_out, L"Running on UEFI "); con_out->output_string(con_out, rev); - con_out->output_string(con_out, L"\n"); + con_out->output_string(con_out, L"\r\n"); /* Get the loaded image protocol */ ret = boottime->handle_protocol(handle, &loaded_image_guid, (void **)&loaded_image); if (ret != EFI_SUCCESS) { - con_out->output_string(con_out, - L"Cannot open loaded image protocol\n"); + con_out->output_string + (con_out, L"Cannot open loaded image protocol\r\n"); goto out; } /* Find configuration tables */ for (i = 0; i < systable->nr_tables; ++i) { if (!hw_memcmp(&systable->tables[i].guid, &fdt_guid, sizeof(efi_guid_t))) - con_out->output_string(con_out, L"Have device tree\n"); + con_out->output_string + (con_out, L"Have device tree\r\n"); if (!hw_memcmp(&systable->tables[i].guid, &acpi_guid, sizeof(efi_guid_t))) - con_out->output_string(con_out, L"Have ACPI 2.0 table\n"); + con_out->output_string + (con_out, L"Have ACPI 2.0 table\r\n"); if (!hw_memcmp(&systable->tables[i].guid, &smbios_guid, sizeof(efi_guid_t))) - con_out->output_string(con_out, L"Have SMBIOS table\n"); + con_out->output_string + (con_out, L"Have SMBIOS table\r\n"); } /* Output the load options */ con_out->output_string(con_out, L"Load options: "); @@ -94,7 +108,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t handle, (u16 *)loaded_image->load_options); else con_out->output_string(con_out, L""); - con_out->output_string(con_out, L"\n"); + con_out->output_string(con_out, L"\r\n"); out: boottime->exit(handle, ret, 0, NULL); -- cgit v1.2.3 From e2373021f67ac4ca78fe75e1eb98f190f36b819d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 24 Sep 2018 19:57:27 +0200 Subject: efi_loader: UninstallMultipleProtocolInterfaces error code If UninstallMultipleProtocolInterfaces fails, we sometimes return the wrong status code. The UEFI spec mandates to always return EFI_INVALID_PARAMETER. Update unit test. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 3 ++- lib/efi_selftest/efi_selftest_manageprotocols.c | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index e3d911fad67..eb652e83485 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2414,7 +2414,8 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( } efi_va_end(argptr); - return EFI_EXIT(r); + /* In case of an error always return EFI_INVALID_PARAMETER */ + return EFI_EXIT(EFI_INVALID_PARAMETER); } /** diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c index b09e4cdcfa5..0ff35cec8a7 100644 --- a/lib/efi_selftest/efi_selftest_manageprotocols.c +++ b/lib/efi_selftest/efi_selftest_manageprotocols.c @@ -189,7 +189,14 @@ static int execute(void) /* * Test error handling in UninstallMultipleProtocols * - * Try to uninstall more protocols than there are installed. + * These are the installed protocol interfaces on handle 2: + * + * guid1 interface4 + * guid2 interface2 + * + * Try to uninstall more protocols than there are installed. This + * should return an error EFI_INVALID_PARAMETER. All deleted protocols + * should be reinstalled. */ ret = boottime->uninstall_multiple_protocol_interfaces( handle2, @@ -197,13 +204,18 @@ static int execute(void) &guid2, &interface2, &guid3, &interface3, NULL); - if (ret == EFI_SUCCESS) { + if (ret != EFI_INVALID_PARAMETER) { + printf("%lx", ret); efi_st_error("UninstallMultipleProtocolInterfaces did not catch error\n"); return EFI_ST_FAILURE; } /* * Test LocateHandleBuffer with ByProtocol + * + * These are the handles with a guid1 protocol interface installed: + * + * handle1, handle2 */ count = buffer_size; ret = boottime->locate_handle_buffer(BY_PROTOCOL, &guid1, NULL, @@ -213,7 +225,7 @@ static int execute(void) return EFI_ST_FAILURE; } if (count != 2) { - efi_st_error("LocateHandleBuffer failed to locate new handles\n"); + efi_st_error("UninstallMultipleProtocolInterfaces deleted handle\n"); return EFI_ST_FAILURE; } ret = find_in_buffer(handle1, count, buffer); -- cgit v1.2.3 From f7855bb7dbdbabafa86a624cd8450129d99514cb Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Oct 2018 07:39:29 -0700 Subject: efi_loader: Generate Microsoft PE format compliant images Per Microsoft PE Format documentation [1], PointerToSymbolTable and NumberOfSymbols should be zero for an image in the COFF file header. Currently U-Boot is generating *.efi images (eg: helloworld.efi) in which these two members are not zero. This updates the build rules to tell linker to remove the symbol table completely so that we can generate compliant *.efi images. [1] https://docs.microsoft.com/zh-cn/windows/desktop/Debug/pe-format Reported-by: Heinrich Schuchardt Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- scripts/Makefile.lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 4dceb6d1b37..a4f16bb4bb5 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -381,7 +381,7 @@ $(obj)/%.efi: $(obj)/%_efi.so quiet_cmd_efi_ld = LD $@ cmd_efi_ld = $(LD) -nostdlib -znocombreloc -T $(EFI_LDS_PATH) -shared \ - -Bsymbolic $^ -o $@ + -Bsymbolic -s $^ -o $@ EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS) -- cgit v1.2.3 From 972ffcd7b0bef07e07e02a339bc0ae95a5d9d5b8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Oct 2018 07:39:30 -0700 Subject: x86: efi: payload: Generate Microsoft PE format compliant image Per Microsoft PE Format documentation [1], PointerToSymbolTable and NumberOfSymbols should be zero for an image in the COFF file header. Currently U-Boot is generating u-boot-payload.efi image in which these two members are not zero. This updates the build rules to tell linker to remove the symbol table completely so that we can generate compliant *.efi images. [1] https://docs.microsoft.com/zh-cn/windows/desktop/Debug/pe-format Reported-by: Heinrich Schuchardt Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- arch/x86/config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 8151e476d4d..f4faea69e4d 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -34,7 +34,7 @@ PLATFORM_LDFLAGS += -m $(if $(IS_32BIT),elf_i386,elf_x86_64) # This is used in the top-level Makefile which does not include # PLATFORM_LDFLAGS -LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined +LDFLAGS_EFI_PAYLOAD := -Bsymbolic -Bsymbolic-functions -shared --no-undefined -s OBJCOPYFLAGS_EFI := -j .text -j .sdata -j .data -j .dynamic -j .dynsym \ -j .rel -j .rela -j .reloc -- cgit v1.2.3 From c54ed3ef5ee536a24d2ad1d9caee83c6c391a338 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Oct 2018 07:39:31 -0700 Subject: x86: efi: app: Generate Microsoft PE format compliant image Per Microsoft PE Format documentation [1], PointerToSymbolTable and NumberOfSymbols should be zero for an image in the COFF file header. Currently U-Boot is generating u-boot-app.efi in which these two members are not zero. This updates the build rules to tell linker to remove the symbol table completely so that we can generate compliant *.efi images. [1] https://docs.microsoft.com/zh-cn/windows/desktop/Debug/pe-format Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- arch/x86/config.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/config.mk b/arch/x86/config.mk index f4faea69e4d..b5e8f462979 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -65,7 +65,7 @@ CPPFLAGS_crt0-efi-$(EFIARCH).o += $(CFLAGS_EFI) ifeq ($(CONFIG_EFI_APP),y) PLATFORM_CPPFLAGS += $(CFLAGS_EFI) -LDFLAGS_FINAL += -znocombreloc -shared +LDFLAGS_FINAL += -znocombreloc -shared -s LDSCRIPT := $(LDSCRIPT_EFI) else -- cgit v1.2.3 From 16c3da3fe965a43f8395472e335677c19c846468 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Oct 2018 07:39:32 -0700 Subject: pe.h: Add characteristics defines This adds characteristics macros as defined by the Microsoft PE Format documentation [1]. [1] https://docs.microsoft.com/zh-cn/windows/desktop/Debug/pe-format Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/asm-generic/pe.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/asm-generic/pe.h b/include/asm-generic/pe.h index 9a8b5e82e38..faae534e371 100644 --- a/include/asm-generic/pe.h +++ b/include/asm-generic/pe.h @@ -11,6 +11,24 @@ #ifndef _ASM_PE_H #define _ASM_PE_H +/* Characteristics */ +#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 +#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 +#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 +#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 +#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010 +#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 +/* Reserved 0x0040 */ +#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 +#define IMAGE_FILE_32BIT_MACHINE 0x0100 +#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 +#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 +#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 +#define IMAGE_FILE_SYSTEM 0x1000 +#define IMAGE_FILE_DLL 0x2000 +#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 +#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 + /* Subsystem type */ #define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 #define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 -- cgit v1.2.3 From fb8ebf52a4518e9355957b8815b0493e7900170d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Oct 2018 07:39:33 -0700 Subject: arm: efi: Generate Microsoft PE format compliant images Per Microsoft PE Format documentation [1], PointerToSymbolTable and NumberOfSymbols should be zero for an image in the COFF file header. Currently the COFF file header is hardcoded on ARM and these two members are not zero. This updates the hardcoded structure to clear these two members, as well as setting the flag IMAGE_FILE_LOCAL_SYMS_STRIPPED so that we can generate compliant *.efi images. [1] https://docs.microsoft.com/zh-cn/windows/desktop/Debug/pe-format Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- arch/arm/lib/crt0_aarch64_efi.S | 12 ++++++------ arch/arm/lib/crt0_arm_efi.S | 16 ++++++++-------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/arm/lib/crt0_aarch64_efi.S b/arch/arm/lib/crt0_aarch64_efi.S index 0db4360bcf2..cb205fa30a5 100644 --- a/arch/arm/lib/crt0_aarch64_efi.S +++ b/arch/arm/lib/crt0_aarch64_efi.S @@ -28,13 +28,13 @@ coff_header: .short 2 /* nr_sections */ .long 0 /* TimeDateStamp */ .long 0 /* PointerToSymbolTable */ - .long 1 /* NumberOfSymbols */ + .long 0 /* NumberOfSymbols */ .short section_table - optional_header /* SizeOfOptionalHeader */ - /* - * Characteristics: IMAGE_FILE_DEBUG_STRIPPED | - * IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED - */ - .short 0x206 + /* Characteristics */ + .short (IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_LINE_NUMS_STRIPPED | \ + IMAGE_FILE_LOCAL_SYMS_STRIPPED | \ + IMAGE_FILE_DEBUG_STRIPPED) optional_header: .short 0x20b /* PE32+ format */ .byte 0x02 /* MajorLinkerVersion */ diff --git a/arch/arm/lib/crt0_arm_efi.S b/arch/arm/lib/crt0_arm_efi.S index 23db49f1fc4..5470e2ff0e6 100644 --- a/arch/arm/lib/crt0_arm_efi.S +++ b/arch/arm/lib/crt0_arm_efi.S @@ -27,16 +27,16 @@ coff_header: .short 2 /* nr_sections */ .long 0 /* TimeDateStamp */ .long 0 /* PointerToSymbolTable */ - .long 1 /* NumberOfSymbols */ + .long 0 /* NumberOfSymbols */ .short section_table - optional_header /* SizeOfOptionalHeader */ - /* - * Characteristics: IMAGE_FILE_32BIT_MACHINE | - * IMAGE_FILE_DEBUG_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | - * IMAGE_FILE_LINE_NUMS_STRIPPED - */ - .short 0x306 + /* Characteristics */ + .short (IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_LINE_NUMS_STRIPPED | \ + IMAGE_FILE_LOCAL_SYMS_STRIPPED | \ + IMAGE_FILE_32BIT_MACHINE | \ + IMAGE_FILE_DEBUG_STRIPPED) optional_header: - .short 0x10b /* PE32+ format */ + .short 0x10b /* PE32 format */ .byte 0x02 /* MajorLinkerVersion */ .byte 0x14 /* MinorLinkerVersion */ .long _edata - _start /* SizeOfCode */ -- cgit v1.2.3 From a33a4efd2785dfda23216bc97e7b636cfd29b9f8 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 2 Oct 2018 07:39:34 -0700 Subject: riscv: efi: Generate Microsoft PE format compliant images Per Microsoft PE Format documentation [1], PointerToSymbolTable and NumberOfSymbols should be zero for an image in the COFF file header. Currently the COFF file header is hardcoded on RISC-V and these two members are not zero. This updates the hardcoded structure to clear these two members, as well as setting the flag IMAGE_FILE_LOCAL_SYMS_STRIPPED so that we can generate compliant *.efi images. [1] https://docs.microsoft.com/zh-cn/windows/desktop/Debug/pe-format Signed-off-by: Bin Meng Reviewed-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- arch/riscv/lib/crt0_riscv_efi.S | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/riscv/lib/crt0_riscv_efi.S b/arch/riscv/lib/crt0_riscv_efi.S index 18f61f515ac..b7b5329e1f7 100644 --- a/arch/riscv/lib/crt0_riscv_efi.S +++ b/arch/riscv/lib/crt0_riscv_efi.S @@ -41,13 +41,13 @@ coff_header: .short 2 /* nr_sections */ .long 0 /* TimeDateStamp */ .long 0 /* PointerToSymbolTable */ - .long 1 /* NumberOfSymbols */ + .long 0 /* NumberOfSymbols */ .short section_table - optional_header /* SizeOfOptionalHeader */ - /* - * Characteristics: IMAGE_FILE_DEBUG_STRIPPED | - * IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED - */ - .short 0x206 + /* Characteristics */ + .short (IMAGE_FILE_EXECUTABLE_IMAGE | \ + IMAGE_FILE_LINE_NUMS_STRIPPED | \ + IMAGE_FILE_LOCAL_SYMS_STRIPPED | \ + IMAGE_FILE_DEBUG_STRIPPED) optional_header: .short 0x20b /* PE32+ format */ .byte 0x02 /* MajorLinkerVersion */ -- cgit v1.2.3 From b0c78d8ffc9fe8b0388353d72e9f2b9e9c6107c6 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 17 Oct 2018 16:32:02 +0900 Subject: fs: update fs_dev_part in fs_set_blk_dev_with_part() As in the case of fs_set_blk_dev(), fs_set_blk_dev_with_part() should maintain and update fs_dev_part whenever called. Without this patch, a problem will come up when an efi binary associated with efi's BOOTxxxx variable is invoked via "bootefi bootmgr". Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- fs/fs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/fs.c b/fs/fs.c index adae98d021e..cb265174e2f 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -365,6 +365,7 @@ int fs_set_blk_dev_with_part(struct blk_desc *desc, int part) for (i = 0, info = fstypes; i < ARRAY_SIZE(fstypes); i++, info++) { if (!info->probe(fs_dev_desc, &fs_partition)) { fs_type = info->fstype; + fs_dev_part = part; return 0; } } -- cgit v1.2.3 From f1589ffb33a798ddb9391dcbab0ddaea2643c2c8 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 17 Oct 2018 16:32:03 +0900 Subject: efi_loader: add efi_dp_from_name() Factor out efi_set_bootdev() and extract efi_dp_from_name(). This function will be used to set a boot device in efishell command. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- cmd/bootefi.c | 42 +++++++---------------------------- include/efi_loader.h | 4 ++++ lib/efi_loader/efi_device_path.c | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index a1650d6cd1f..78f126f1c60 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -608,45 +608,19 @@ U_BOOT_CMD( void efi_set_bootdev(const char *dev, const char *devnr, const char *path) { - char filename[32] = { 0 }; /* dp->str is u16[32] long */ - char *s; + struct efi_device_path *device, *image; + efi_status_t ret; /* efi_set_bootdev is typically called repeatedly, recover memory */ efi_free_pool(bootefi_device_path); efi_free_pool(bootefi_image_path); - /* If blk_get_device_part_str fails, avoid duplicate free. */ - bootefi_device_path = NULL; - bootefi_image_path = NULL; - - if (strcmp(dev, "Net")) { - struct blk_desc *desc; - disk_partition_t fs_partition; - int part; - - part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, - 1); - if (part < 0) - return; - - bootefi_device_path = efi_dp_from_part(desc, part); - } else { -#ifdef CONFIG_NET - bootefi_device_path = efi_dp_from_eth(); -#endif - } - - if (!path) - return; - if (strcmp(dev, "Net")) { - /* Add leading / to fs paths, because they're absolute */ - snprintf(filename, sizeof(filename), "/%s", path); + ret = efi_dp_from_name(dev, devnr, path, &device, &image); + if (ret == EFI_SUCCESS) { + bootefi_device_path = device; + bootefi_image_path = image; } else { - snprintf(filename, sizeof(filename), "%s", path); + bootefi_device_path = NULL; + bootefi_image_path = NULL; } - /* DOS style file path: */ - s = filename; - while ((s = strchr(s, '/'))) - *s++ = '\\'; - bootefi_image_path = efi_dp_from_file(NULL, 0, filename); } diff --git a/include/efi_loader.h b/include/efi_loader.h index 7a8aa2913a1..f399e995060 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -432,6 +432,10 @@ const struct efi_device_path *efi_dp_last_node( efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path, struct efi_device_path **device_path, struct efi_device_path **file_path); +efi_status_t efi_dp_from_name(const char *dev, const char *devnr, + const char *path, + struct efi_device_path **device, + struct efi_device_path **file); #define EFI_DP_TYPE(_dp, _type, _subtype) \ (((_dp)->type == DEVICE_PATH_TYPE_##_type) && \ diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 2b5d0671046..adb9938d452 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -941,3 +941,50 @@ efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path, *file_path = fp; return EFI_SUCCESS; } + +efi_status_t efi_dp_from_name(const char *dev, const char *devnr, + const char *path, + struct efi_device_path **device, + struct efi_device_path **file) +{ + int is_net; + struct blk_desc *desc = NULL; + disk_partition_t fs_partition; + int part = 0; + char filename[32] = { 0 }; /* dp->str is u16[32] long */ + char *s; + + if (!device || (path && !file)) + return EFI_INVALID_PARAMETER; + + is_net = !strcmp(dev, "Net"); + if (!is_net) { + part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition, + 1); + if (part < 0) + return EFI_INVALID_PARAMETER; + + *device = efi_dp_from_part(desc, part); + } else { +#ifdef CONFIG_NET + *device = efi_dp_from_eth(); +#endif + } + + if (!path) + return EFI_SUCCESS; + + if (!is_net) { + /* Add leading / to fs paths, because they're absolute */ + snprintf(filename, sizeof(filename), "/%s", path); + } else { + snprintf(filename, sizeof(filename), "%s", path); + } + /* DOS style file path: */ + s = filename; + while ((s = strchr(s, '/'))) + *s++ = '\\'; + *file = efi_dp_from_file(NULL, 0, filename); + + return EFI_SUCCESS; +} -- cgit v1.2.3 From 3d05c384600077c88471117eeb5c7d9ffa7ac1c2 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 16 Oct 2018 18:47:58 +0200 Subject: efi_loader: unset CONFIG_EFI_LOADER on vf610twr vf610twr_defconfig and vf610twr_nand_defconfig suffer from tight memory restrictions. Disable CONFIG_EFI_LOADER for these boards. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- configs/vf610twr_defconfig | 2 +- configs/vf610twr_nand_defconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configs/vf610twr_defconfig b/configs/vf610twr_defconfig index a928cd4fbc9..504eebbf5db 100644 --- a/configs/vf610twr_defconfig +++ b/configs/vf610twr_defconfig @@ -41,4 +41,4 @@ CONFIG_PHY_MICREL=y CONFIG_MII=y CONFIG_DM_SERIAL=y CONFIG_FSL_LPUART=y -# CONFIG_EFI_UNICODE_CAPITALIZATION is not set +# CONFIG_EFI_LOADER is not set diff --git a/configs/vf610twr_nand_defconfig b/configs/vf610twr_nand_defconfig index 560776fe56d..0a1e28e2ecd 100644 --- a/configs/vf610twr_nand_defconfig +++ b/configs/vf610twr_nand_defconfig @@ -41,4 +41,4 @@ CONFIG_PHY_MICREL=y CONFIG_MII=y CONFIG_DM_SERIAL=y CONFIG_FSL_LPUART=y -# CONFIG_EFI_UNICODE_CAPITALIZATION is not set +# CONFIG_EFI_LOADER is not set -- cgit v1.2.3 From eb3bc8bb177e8b19464529826acad5ec0d0edb61 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 17 Oct 2018 21:55:24 +0200 Subject: efi_loader: fix typos in efi_device_path.c Fix some typos in comments. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index adb9938d452..cdf7c7be8c5 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -82,7 +82,7 @@ struct efi_device_path *efi_dp_next(const struct efi_device_path *dp) /* * Compare two device-paths, stopping when the shorter of the two hits - * an End* node. This is useful to, for example, compare a device-path + * an End* node. This is useful to, for example, compare a device-path * representing a device with one representing a file on the device, or * a device with a parent device. */ @@ -109,16 +109,17 @@ int efi_dp_match(const struct efi_device_path *a, } /* - * See UEFI spec (section 3.1.2, about short-form device-paths.. - * tl;dr: we can have a device-path that starts with a USB WWID - * or USB Class node, and a few other cases which don't encode - * the full device path with bus hierarchy: + * We can have device paths that start with a USB WWID or a USB Class node, + * and a few other cases which don't encode the full device path with bus + * hierarchy: * * - MESSAGING:USB_WWID * - MESSAGING:USB_CLASS * - MEDIA:FILE_PATH * - MEDIA:HARD_DRIVE * - MESSAGING:URI + * + * See UEFI spec (section 3.1.2, about short-form device-paths) */ static struct efi_device_path *shorten_path(struct efi_device_path *dp) { @@ -644,7 +645,7 @@ static unsigned dp_part_size(struct blk_desc *desc, int part) /* * Create a device node for a block device partition. * - * @buf buffer to which the device path is wirtten + * @buf buffer to which the device path is written * @desc block device descriptor * @part partition number, 0 identifies a block device */ @@ -709,7 +710,7 @@ static void *dp_part_node(void *buf, struct blk_desc *desc, int part) /* * Create a device path for a block device or one of its partitions. * - * @buf buffer to which the device path is wirtten + * @buf buffer to which the device path is written * @desc block device descriptor * @part partition number, 0 identifies a block device */ @@ -728,7 +729,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) /* * We *could* make a more accurate path, by looking at if_type * and handling all the different cases like we do for non- - * legacy (ie CONFIG_BLK=y) case. But most important thing + * legacy (i.e. CONFIG_BLK=y) case. But most important thing * is just to have a unique device-path for if_type+devnum. * So map things to a fictitious USB device. */ @@ -752,7 +753,7 @@ static void *dp_part_fill(void *buf, struct blk_desc *desc, int part) return dp_part_node(buf, desc, part); } -/* Construct a device-path from a partition on a blk device: */ +/* Construct a device-path from a partition on a block device: */ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part) { void *buf, *start; @@ -771,7 +772,7 @@ struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part) /* * Create a device node for a block device partition. * - * @buf buffer to which the device path is wirtten + * @buf buffer to which the device path is written * @desc block device descriptor * @part partition number, 0 identifies a block device */ @@ -791,7 +792,7 @@ struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part) return buf; } -/* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */ +/* convert path to an UEFI style path (i.e. DOS style backslashes and UTF-16) */ static void path_to_uefi(u16 *uefi, const char *path) { while (*path) { -- cgit v1.2.3 From 81ea00838c682da06637bcf208549095181df337 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 18 Oct 2018 12:29:40 +0200 Subject: efi_loader: PSCI reset and shutdown When an operating system started via bootefi tries to reset or power off this is done by calling the EFI runtime ResetSystem(). On most ARMv8 system the actual reset relies on PSCI. Depending on whether the PSCI firmware resides the hypervisor (EL2) or in the secure monitor (EL3) either an HVC or an SMC command has to be issued. The current implementation always uses SMC. This results in crashes on systems where the PSCI firmware is implemented in the hypervisor, e.g. qemu-arm64_defconfig. The logic to decide which call is needed based on the device tree is already implemented in the PSCI firmware driver. During the EFI runtime the device driver model is not available. But we can minimize code duplication by merging the EFI runtime reset and poweroff code with the PSCI firmware driver. As the same HVC/SMC problem is also evident for the ARMv8 do_poweroff and reset_misc routines let's move them into the same code module. Signed-off-by: Heinrich Schuchardt Reviewed-by: Sumit Garg Tested-by: Sumit Garg Signed-off-by: Alexander Graf --- arch/arm/cpu/armv7/smccc-call.S | 2 + arch/arm/cpu/armv8/Kconfig | 1 + arch/arm/cpu/armv8/fwcall.c | 52 ++------------------- arch/arm/cpu/armv8/smccc-call.S | 2 + drivers/firmware/psci.c | 100 +++++++++++++++++++++++++++++++++------- include/linux/psci.h | 6 +-- 6 files changed, 96 insertions(+), 67 deletions(-) diff --git a/arch/arm/cpu/armv7/smccc-call.S b/arch/arm/cpu/armv7/smccc-call.S index 0d8b59eb6b9..eae69e36c3c 100644 --- a/arch/arm/cpu/armv7/smccc-call.S +++ b/arch/arm/cpu/armv7/smccc-call.S @@ -7,6 +7,8 @@ #include #include + .section .text.efi_runtime + #define UNWIND(x...) /* * Wrap c macros in asm macros to delay expansion until after the diff --git a/arch/arm/cpu/armv8/Kconfig b/arch/arm/cpu/armv8/Kconfig index ff42791fb44..1c12bbde75a 100644 --- a/arch/arm/cpu/armv8/Kconfig +++ b/arch/arm/cpu/armv8/Kconfig @@ -96,6 +96,7 @@ endmenu config PSCI_RESET bool "Use PSCI for reset and shutdown" default y + select ARM_SMCCC if OF_CONTROL depends on !ARCH_EXYNOS7 && !ARCH_BCM283X && \ !TARGET_LS2080A_SIMU && !TARGET_LS2080AQDS && \ !TARGET_LS2080ARDB && !TARGET_LS2080A_EMU && \ diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c index 0ba3dad8cc5..9957c2974bc 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -7,7 +7,6 @@ #include #include -#include #include #include #include @@ -19,7 +18,7 @@ * x0~x7: input arguments * x0~x3: output arguments */ -static void __efi_runtime hvc_call(struct pt_regs *args) +static void hvc_call(struct pt_regs *args) { asm volatile( "ldr x0, %0\n" @@ -53,7 +52,7 @@ static void __efi_runtime hvc_call(struct pt_regs *args) * x0~x3: output arguments */ -void __efi_runtime smc_call(struct pt_regs *args) +void smc_call(struct pt_regs *args) { asm volatile( "ldr x0, %0\n" @@ -83,9 +82,9 @@ void __efi_runtime smc_call(struct pt_regs *args) * use PSCI on U-Boot running below a hypervisor, please detect * this and set the flag accordingly. */ -static const __efi_runtime_data bool use_smc_for_psci = true; +static const bool use_smc_for_psci = true; -void __noreturn __efi_runtime psci_system_reset(void) +void __noreturn psci_system_reset(void) { struct pt_regs regs; @@ -100,7 +99,7 @@ void __noreturn __efi_runtime psci_system_reset(void) ; } -void __noreturn __efi_runtime psci_system_off(void) +void __noreturn psci_system_off(void) { struct pt_regs regs; @@ -114,44 +113,3 @@ void __noreturn __efi_runtime psci_system_off(void) while (1) ; } - -#ifdef CONFIG_CMD_POWEROFF -int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) -{ - puts("poweroff ...\n"); - - udelay(50000); /* wait 50 ms */ - - disable_interrupts(); - - psci_system_off(); - - /*NOTREACHED*/ - return 0; -} -#endif - -#ifdef CONFIG_PSCI_RESET -void reset_misc(void) -{ - psci_system_reset(); -} - -#ifdef CONFIG_EFI_LOADER -void __efi_runtime EFIAPI efi_reset_system( - enum efi_reset_type reset_type, - efi_status_t reset_status, - unsigned long data_size, void *reset_data) -{ - if (reset_type == EFI_RESET_COLD || - reset_type == EFI_RESET_WARM || - reset_type == EFI_RESET_PLATFORM_SPECIFIC) { - psci_system_reset(); - } else if (reset_type == EFI_RESET_SHUTDOWN) { - psci_system_off(); - } - - while (1) { } -} -#endif /* CONFIG_EFI_LOADER */ -#endif /* CONFIG_PSCI_RESET */ diff --git a/arch/arm/cpu/armv8/smccc-call.S b/arch/arm/cpu/armv8/smccc-call.S index 16c9e298b45..86de4b4089d 100644 --- a/arch/arm/cpu/armv8/smccc-call.S +++ b/arch/arm/cpu/armv8/smccc-call.S @@ -6,6 +6,8 @@ #include #include + .section .text.efi_runtime + .macro SMCCC instr .cfi_startproc \instr #0 diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 2cb35f356f4..c8c47acfd34 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -9,31 +9,38 @@ #include #include #include +#include #include #include #include #include #include -psci_fn *invoke_psci_fn; +#define DRIVER_NAME "psci" -static unsigned long __invoke_psci_fn_hvc(unsigned long function_id, - unsigned long arg0, unsigned long arg1, - unsigned long arg2) -{ - struct arm_smccc_res res; +#define PSCI_METHOD_HVC 1 +#define PSCI_METHOD_SMC 2 - arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); - return res.a0; -} +int __efi_runtime_data psci_method; -static unsigned long __invoke_psci_fn_smc(unsigned long function_id, - unsigned long arg0, unsigned long arg1, - unsigned long arg2) +unsigned long __efi_runtime invoke_psci_fn + (unsigned long function_id, unsigned long arg0, + unsigned long arg1, unsigned long arg2) { struct arm_smccc_res res; - arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + /* + * In the __efi_runtime we need to avoid the switch statement. In some + * cases the compiler creates lookup tables to implement switch. These + * tables are not correctly relocated when SetVirtualAddressMap is + * called. + */ + if (psci_method == PSCI_METHOD_SMC) + arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + else if (psci_method == PSCI_METHOD_HVC) + arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res); + else + res.a0 = PSCI_RET_DISABLED; return res.a0; } @@ -67,9 +74,9 @@ static int psci_probe(struct udevice *dev) } if (!strcmp("hvc", method)) { - invoke_psci_fn = __invoke_psci_fn_hvc; + psci_method = PSCI_METHOD_HVC; } else if (!strcmp("smc", method)) { - invoke_psci_fn = __invoke_psci_fn_smc; + psci_method = PSCI_METHOD_SMC; } else { pr_warn("invalid \"method\" property: %s\n", method); return -EINVAL; @@ -78,6 +85,67 @@ static int psci_probe(struct udevice *dev) return 0; } +/** + * void do_psci_probe() - probe PSCI firmware driver + * + * Ensure that psci_method is initialized. + */ +static void __maybe_unused do_psci_probe(void) +{ + struct udevice *dev; + + uclass_get_device_by_name(UCLASS_FIRMWARE, DRIVER_NAME, &dev); +} + +#if IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET) +efi_status_t efi_reset_system_init(void) +{ + do_psci_probe(); + return EFI_SUCCESS; +} + +void __efi_runtime EFIAPI efi_reset_system(enum efi_reset_type reset_type, + efi_status_t reset_status, + unsigned long data_size, + void *reset_data) +{ + if (reset_type == EFI_RESET_COLD || + reset_type == EFI_RESET_WARM || + reset_type == EFI_RESET_PLATFORM_SPECIFIC) { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); + } else if (reset_type == EFI_RESET_SHUTDOWN) { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); + } + while (1) + ; +} +#endif /* IS_ENABLED(CONFIG_EFI_LOADER) && IS_ENABLED(CONFIG_PSCI_RESET) */ + +#ifdef CONFIG_PSCI_RESET +void reset_misc(void) +{ + do_psci_probe(); + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); +} +#endif /* CONFIG_PSCI_RESET */ + +#ifdef CONFIG_CMD_POWEROFF +int do_poweroff(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + do_psci_probe(); + + puts("poweroff ...\n"); + udelay(50000); /* wait 50 ms */ + + disable_interrupts(); + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); + enable_interrupts(); + + log_err("Power off not supported on this platform\n"); + return CMD_RET_FAILURE; +} +#endif + static const struct udevice_id psci_of_match[] = { { .compatible = "arm,psci" }, { .compatible = "arm,psci-0.2" }, @@ -86,7 +154,7 @@ static const struct udevice_id psci_of_match[] = { }; U_BOOT_DRIVER(psci) = { - .name = "psci", + .name = DRIVER_NAME, .id = UCLASS_FIRMWARE, .of_match = psci_of_match, .bind = psci_bind, diff --git a/include/linux/psci.h b/include/linux/psci.h index 8d13bd27021..9433df836b6 100644 --- a/include/linux/psci.h +++ b/include/linux/psci.h @@ -88,10 +88,8 @@ #define PSCI_RET_DISABLED -8 #ifdef CONFIG_ARM_PSCI_FW -typedef unsigned long (psci_fn)(unsigned long, unsigned long, - unsigned long, unsigned long); - -extern psci_fn *invoke_psci_fn; +unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1, + unsigned long a2, unsigned long a3); #else unsigned long invoke_psci_fn(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3) -- cgit v1.2.3 From 4c174394caa814a185121e7b06a41dc4be5c774a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 19 Oct 2018 07:51:26 +0200 Subject: efi_selftest: do not write to linker generated array Linker generated arrays may be stored in code sections of memory that are not writable. So let's allocate setup_ok as an array at runtime. This avoids an illegal memory access observed in the sandbox. Reported-by: Simon Glass Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_selftest.h | 2 -- lib/efi_selftest/efi_selftest.c | 31 ++++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/efi_selftest.h b/include/efi_selftest.h index 56beac305ec..49d3d6d0b47 100644 --- a/include/efi_selftest.h +++ b/include/efi_selftest.h @@ -129,7 +129,6 @@ u16 efi_st_get_key(void); * @setup: set up the unit test * @teardown: tear down the unit test * @execute: execute the unit test - * @setup_ok: setup was successful (set at runtime) * @on_request: test is only executed on request */ struct efi_unit_test { @@ -139,7 +138,6 @@ struct efi_unit_test { const struct efi_system_table *systable); int (*execute)(void); int (*teardown)(void); - int setup_ok; bool on_request; }; diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index dd338db687e..fc7866365d0 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -18,6 +18,7 @@ static const struct efi_boot_services *boottime; static const struct efi_runtime_services *runtime; static efi_handle_t handle; static u16 reset_message[] = L"Selftest completed"; +static int *setup_ok; /* * Exit the boot services. @@ -74,20 +75,20 @@ void efi_st_exit_boot_services(void) */ static int setup(struct efi_unit_test *test, unsigned int *failures) { - if (!test->setup) { - test->setup_ok = EFI_ST_SUCCESS; + int ret; + + if (!test->setup) return EFI_ST_SUCCESS; - } efi_st_printc(EFI_LIGHTBLUE, "\nSetting up '%s'\n", test->name); - test->setup_ok = test->setup(handle, systable); - if (test->setup_ok != EFI_ST_SUCCESS) { + ret = test->setup(handle, systable); + if (ret != EFI_ST_SUCCESS) { efi_st_error("Setting up '%s' failed\n", test->name); ++*failures; } else { efi_st_printc(EFI_LIGHTGREEN, "Setting up '%s' succeeded\n", test->name); } - return test->setup_ok; + return ret; } /* @@ -186,18 +187,20 @@ static void list_all_tests(void) void efi_st_do_tests(const u16 *testname, unsigned int phase, unsigned int steps, unsigned int *failures) { + int i = 0; struct efi_unit_test *test; for (test = ll_entry_start(struct efi_unit_test, efi_unit_test); - test < ll_entry_end(struct efi_unit_test, efi_unit_test); ++test) { + test < ll_entry_end(struct efi_unit_test, efi_unit_test); + ++test, ++i) { if (testname ? efi_st_strcmp_16_8(testname, test->name) : test->on_request) continue; if (test->phase != phase) continue; if (steps & EFI_ST_SETUP) - setup(test, failures); - if (steps & EFI_ST_EXECUTE && test->setup_ok == EFI_ST_SUCCESS) + setup_ok[i] = setup(test, failures); + if (steps & EFI_ST_EXECUTE && setup_ok[i] == EFI_ST_SUCCESS) execute(test, failures); if (steps & EFI_ST_TEARDOWN) teardown(test, failures); @@ -271,6 +274,16 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, ll_entry_count(struct efi_unit_test, efi_unit_test)); + /* Allocate buffer for setup results */ + ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) * + ll_entry_count(struct efi_unit_test, + efi_unit_test), + (void **)&setup_ok); + if (ret != EFI_SUCCESS) { + efi_st_error("Allocate pool failed\n"); + return ret; + } + /* Execute boottime tests */ efi_st_do_tests(testname, EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, EFI_ST_SETUP | EFI_ST_EXECUTE | EFI_ST_TEARDOWN, -- cgit v1.2.3 From e1fec152fe53ca8ee922fd0ed4d2c197d4f641bf Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 18 Oct 2018 21:51:38 +0200 Subject: efi_loader: fix typos Fix typos in EFI subsystem comments. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 2 +- lib/efi_loader/efi_bootmgr.c | 2 +- lib/efi_loader/efi_console.c | 4 ++-- lib/efi_loader/efi_device_path_to_text.c | 8 ++++---- lib/efi_loader/efi_gop.c | 11 +++++++---- lib/efi_loader/efi_net.c | 8 ++++---- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 78f126f1c60..3605c3ff96c 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -354,7 +354,7 @@ static efi_status_t do_bootefi_exec(void *efi, /* * Special case for efi payload not loaded from disk, such as * 'bootefi hello' or for example payload loaded directly into - * memory via jtag, etc: + * memory via JTAG, etc: */ if (!device_path && !image_path) { printf("WARNING: using memory device/image path, this may confuse some payloads!\n"); diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 0c5764db127..2aae12e1545 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * EFI utils + * EFI boot manager * * Copyright (c) 2017 Rob Clark */ diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 7274d752045..66c33a551d5 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -205,7 +205,7 @@ static int query_console_serial(int *rows, int *cols) /* * Not all terminals understand CSI [18t for querying the console size. * We should adhere to escape sequences documented in the console_codes - * manpage and the ECMA-48 standard. + * man page and the ECMA-48 standard. * * So here we follow a different approach. We position the cursor to the * bottom right and query its position. Before leaving the function we @@ -480,7 +480,7 @@ void set_shift_mask(int mod, struct efi_key_state *key_state) * * This gets called when we have already parsed CSI. * - * @modifiers: bitmask (shift, alt, ctrl) + * @modifiers: bit mask (shift, alt, ctrl) * @return: the unmodified code */ static int analyze_modifiers(struct efi_key_state *key_state) diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c index 00822363595..e219f84b28d 100644 --- a/lib/efi_loader/efi_device_path_to_text.c +++ b/lib/efi_loader/efi_device_path_to_text.c @@ -269,9 +269,9 @@ static char *efi_convert_single_device_node_to_text( * for details. * * device_node device node to be converted - * display_only true if the shorter text represenation shall be used + * display_only true if the shorter text representation shall be used * allow_shortcuts true if shortcut forms may be used - * @return text represenation of the device path + * @return text representation of the device path * NULL if out of memory of device_path is NULL */ static uint16_t EFIAPI *efi_convert_device_node_to_text( @@ -302,9 +302,9 @@ out: * for details. * * device_path device path to be converted - * display_only true if the shorter text represenation shall be used + * display_only true if the shorter text representation shall be used * allow_shortcuts true if shortcut forms may be used - * @return text represenation of the device path + * @return text representation of the device path * NULL if out of memory of device_path is NULL */ static uint16_t EFIAPI *efi_convert_device_path_to_text( diff --git a/lib/efi_loader/efi_gop.c b/lib/efi_loader/efi_gop.c index fbd5d97de97..d62ce459127 100644 --- a/lib/efi_loader/efi_gop.c +++ b/lib/efi_loader/efi_gop.c @@ -243,12 +243,12 @@ static efi_uintn_t gop_get_bpp(struct efi_gop *this) } /* - * Gcc can't optimize our BLT function well, but we need to make sure that + * GCC can't optimize our BLT function well, but we need to make sure that * our 2-dimensional loop gets executed very quickly, otherwise the system * will feel slow. * * By manually putting all obvious branch targets into functions which call - * our generic blt function with constants, the compiler can successfully + * our generic BLT function with constants, the compiler can successfully * optimize for speed. */ static efi_status_t gop_blt_video_fill(struct efi_gop *this, @@ -452,7 +452,7 @@ efi_status_t efi_gop_register(void) ret = efi_add_protocol(&gopobj->header, &efi_gop_guid, &gopobj->ops); if (ret != EFI_SUCCESS) { - printf("ERROR: Failure adding gop protocol\n"); + printf("ERROR: Failure adding GOP protocol\n"); return ret; } gopobj->ops.query_mode = gop_query_mode; @@ -470,7 +470,10 @@ efi_status_t efi_gop_register(void) if (bpix == LCD_COLOR32) #endif { - /* With 32bit color space we can directly expose the fb */ + /* + * With 32bit color space we can directly expose the frame + * buffer + */ gopobj->mode.fb_base = fb_base; gopobj->mode.fb_size = fb_size; } diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index c4f35cd50d3..a64c603ed3e 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -269,7 +269,7 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, if (protocol) *protocol = protlen; if (*buffer_size < net_rx_packet_len) { - /* Packet doesn't fit, try again with bigger buf */ + /* Packet doesn't fit, try again with bigger buffer */ *buffer_size = net_rx_packet_len; return EFI_EXIT(EFI_BUFFER_TOO_SMALL); } @@ -319,11 +319,11 @@ efi_status_t efi_net_register(void) efi_status_t r; if (!eth_get_dev()) { - /* No eth device active, don't expose any */ + /* No network device active, don't expose any */ return EFI_SUCCESS; } - /* We only expose the "active" eth device, so one is enough */ + /* We only expose the "active" network device, so one is enough */ netobj = calloc(1, sizeof(*netobj)); if (!netobj) { printf("ERROR: Out of memory\n"); @@ -397,7 +397,7 @@ efi_status_t efi_net_register(void) printf("ERROR: Failed to register network event\n"); return r; } - /* Network is time critical, create event in every timer cyle */ + /* Network is time critical, create event in every timer cycle */ r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0); if (r != EFI_SUCCESS) { printf("ERROR: Failed to set network timer\n"); -- cgit v1.2.3 From dc03b704f4364da6df6a86aafccc3828ade8ed43 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 19 Oct 2018 14:41:01 +0200 Subject: usb: Do not compile USB_STORAGE with BLK && !DM_USB The USB storage driver does not compile when CONFIG_BLK is set, but DM_USB is not set, as we're missing the DM device links for CONFIG_BLK enabled code paths. So far it looks like nobody fell into this trap, because no board enabled CONFIG_BLK and CONFIG_USB_STORAGE while not enabling CONFIG_DM_USB, but we should still reflect that dependency properly in Kconfig so that implicit enabling of CONFIG_USB_STORAGE works. Signed-off-by: Alexander Graf --- drivers/usb/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 03746dd12fc..d456beb43fc 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -70,6 +70,7 @@ comment "USB peripherals" config USB_STORAGE bool "USB Mass Storage support" + depends on !(BLK && !DM_USB) ---help--- Say Y here if you want to connect USB mass storage devices to your board's USB port. -- cgit v1.2.3 From 4aa7492683f2d4a26d456d8734d8e59d6bd52e0d Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 18 Oct 2018 09:33:03 +0200 Subject: distro: Imply USB_STORAGE when USB is available When you support distro boot and you support USB, you usually want to also support booting from USB storage. Reflect that in the Kconfig, so that we don't have to explicitly add USB storage support to every defconfig individually. Reported-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/Kconfig b/Kconfig index dca9bb4e432..f512b308352 100644 --- a/Kconfig +++ b/Kconfig @@ -86,6 +86,7 @@ config DISTRO_DEFAULTS select SUPPORT_RAW_INITRD select SYS_LONGHELP imply CMD_MII if NET + imply USB_STORAGE imply USE_BOOTCOMMAND help Select this to enable various options and commands which are suitable -- cgit v1.2.3 From afdc4fcc8931589f2fab75d8830ab9b43d2725c4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 4 Nov 2018 22:25:22 +0100 Subject: efi_loader: Handle RELA absolute relocations properly With RELA absolute relocations, the relocation target contains our link offset which we need to remove from the equation again. We did this properly in the relative relocation path, but not in the absolute one. So let's do this for the absolute one as well. That way, u-boot can have a TEXT_OFFSET of != 0 and still relocate itself properly. This fixes a bug where efi_loader did not work on the RISC-V QEMU port. With this patch, I can successfully run UEFI applications on the RISC-V QEMU port. Reported-by: Auer, Lukas Signed-off-by: Alexander Graf Tested-by: Bin Meng Tested-by: Lukas Auer --- lib/efi_loader/efi_runtime.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index abcf03c5a42..ca66d33e588 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -380,6 +380,9 @@ void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map) ulong symidx = rel->info >> SYM_INDEX; extern struct dyn_sym __dyn_sym_start[]; newaddr = __dyn_sym_start[symidx].addr + offset; +#ifdef IS_RELA + newaddr -= CONFIG_SYS_TEXT_BASE; +#endif break; } #endif -- cgit v1.2.3 From c2e1ad70a75048d802bf5c3296a043761939dae6 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 5 Nov 2018 00:30:46 +0100 Subject: efi_loader: Ensure memory allocations are page aligned When the max_addr parameter of efi_find_free_memory() is within bounds of an existing map and fits the reservation, we just return that address as allocation value. That breaks however if max_addr is not page aligned. So ensure that it always comes to us page aligned, simplifying the allocation logic. Without this, I've seen breakage where we were allocating pages at -1U (32bit) which fits into a region that spans beyond 0x100000000. In that case, we would return 0xffffffff as a valid memory allocation, although we usually do guarantee they are all page aligned. Fix this by aligning the max address argument always. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5bd4f4d7fc4..1ffcf92eb2e 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -294,6 +294,12 @@ static uint64_t efi_find_free_memory(uint64_t len, uint64_t max_addr) { struct list_head *lhandle; + /* + * Prealign input max address, so we simplify our matching + * logic below and can just reuse it as return pointer. + */ + max_addr &= ~EFI_PAGE_MASK; + list_for_each(lhandle, &efi_mem) { struct efi_mem_list *lmem = list_entry(lhandle, struct efi_mem_list, link); -- cgit v1.2.3 From c966076cb52896422fa982ab2a84200ee9b4a730 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 12 Nov 2018 03:37:05 +0100 Subject: efi_loader: do not use unsupported printf code Using %zu for efi_intn_t (ssize_t) creates a build warning. Anyway %zu is not supported by efi_st_error(). So let's convert to int. Our implementation of StriColl() only returns -1, 0, or 1. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_unicode_collation.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_unicode_collation.c b/lib/efi_selftest/efi_selftest_unicode_collation.c index 9765bd3e44b..75294307d9f 100644 --- a/lib/efi_selftest/efi_selftest_unicode_collation.c +++ b/lib/efi_selftest/efi_selftest_unicode_collation.c @@ -52,7 +52,7 @@ static int test_stri_coll(void) c1, c2); if (ret) { efi_st_error( - "stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c2, ret); + "stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c2, (int)ret); return EFI_ST_FAILURE; } @@ -60,7 +60,7 @@ static int test_stri_coll(void) c1, c3); if (ret >= 0) { efi_st_error( - "stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c3, ret); + "stri_coll(\"%ps\", \"%ps\") = %d\n", c1, c3, (int)ret); return EFI_ST_FAILURE; } @@ -68,7 +68,7 @@ static int test_stri_coll(void) c3, c1); if (ret <= 0) { efi_st_error( - "stri_coll(\"%ps\", \"%ps\") = %zu\n", c3, c1, ret); + "stri_coll(\"%ps\", \"%ps\") = %d\n", c3, c1, (int)ret); return EFI_ST_FAILURE; } -- cgit v1.2.3 From 4574d1b3d1b1aca761ad48cf67db44f3b97c4d1b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 12 Nov 2018 18:55:22 +0100 Subject: efi_loader: memory reservation for fdt In copy_fdt() we allocate EFI pages for the fdt plus extra 12 KiB as EFI_RUNTIME_SERVICES_DATA. Afterwards in efi_install_fdt() we overwrite part of this memory allocation by marking it as EFI_BOOT_SERVICES_DATA. Remove the code marking the fdt as EFI_BOOT_SERVICES_DATA. Cf. commit 17ff6f02f5ad ("efi_loader: store DT in EFI_RUNTIME_SERVICES_DATA memory") Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 3605c3ff96c..8c4049b7db1 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -152,12 +152,11 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info, * An additional 12KB is added to the space in case the device tree needs to be * expanded later with fdt_open_into(). * - * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated - * FDT start - * @fdt_sizep: Returns new size of FDT, including - * @return new relocated address of FDT + * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated + * FDT start + * Return: status code */ -static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep) +static efi_status_t copy_fdt(ulong *fdt_addrp) { unsigned long fdt_ram_start = -1L, fdt_pages; efi_status_t ret = 0; @@ -209,7 +208,6 @@ static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep) fdt_set_totalsize(new_fdt, fdt_size); *fdt_addrp = new_fdt_addr; - *fdt_sizep = fdt_size; done: return ret; } @@ -287,7 +285,6 @@ static void efi_carve_out_dt_rsv(void *fdt) static efi_status_t efi_install_fdt(ulong fdt_addr) { bootm_headers_t img = { 0 }; - ulong fdt_pages, fdt_size, fdt_start; efi_status_t ret; void *fdt; @@ -298,13 +295,12 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) } /* Prepare fdt for payload */ - ret = copy_fdt(&fdt_addr, &fdt_size); + ret = copy_fdt(&fdt_addr); if (ret) return ret; unmap_sysmem(fdt); fdt = map_sysmem(fdt_addr, 0); - fdt_size = fdt_totalsize(fdt); if (image_setup_libfdt(&img, fdt, 0, NULL)) { printf("ERROR: failed to process device tree\n"); return EFI_LOAD_ERROR; @@ -317,13 +313,6 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) if (ret != EFI_SUCCESS) return EFI_OUT_OF_RESOURCES; - /* And reserve the space in the memory map */ - fdt_start = fdt_addr; - fdt_pages = fdt_size >> EFI_PAGE_SHIFT; - - ret = efi_add_memory_map(fdt_start, fdt_pages, - EFI_BOOT_SERVICES_DATA, true); - return ret; } -- cgit v1.2.3 From 23fd84b3eccb1af51699d49368e257a5b0a78593 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 12 Nov 2018 18:55:23 +0100 Subject: efi_loader: carving out memory reservations The "Devicetree Specification 0.2" does not prescribe that memory reservations must be EFI page aligned. So let's not make such an assumption in our code. Do not carve out the pages for the device tree. This memory area is already marked as EFI_RUNTIME_SERVICES_DATA. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 8c4049b7db1..3e37805ea13 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -275,7 +275,16 @@ static void efi_carve_out_dt_rsv(void *fdt) if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0) continue; - pages = ALIGN(size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT; + /* + * Do not carve out the device tree. It is already marked as + * EFI_RUNTIME_SERVICES_DATA + */ + if (addr == (uintptr_t)fdt) + continue; + + pages = ALIGN(size + (addr & EFI_PAGE_MASK), EFI_PAGE_SIZE) >> + EFI_PAGE_SHIFT; + addr &= ~EFI_PAGE_MASK; if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, false)) printf("FDT memrsv map %d: Failed to add to map\n", i); -- cgit v1.2.3 From 108bdff84a0b9104f05cb04a41bdd14f67f0d4c6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 12 Nov 2018 18:55:24 +0100 Subject: efi_loader: correct efi_add_known_memory() If a memory bank is not EFI_PAGE_SIZE aligned efi_add_known_memory() the number of memory pages may be incorrectly calculated. We have to round up the start address and to round down the end address to determine which complete pages are provided by the memory bank. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 1ffcf92eb2e..f225a9028c5 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -555,13 +555,21 @@ __weak void efi_add_known_memory(void) /* Add RAM */ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { - u64 ram_start = gd->bd->bi_dram[i].start; - u64 ram_size = gd->bd->bi_dram[i].size; - u64 start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; - u64 pages = (ram_size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + u64 ram_end, ram_start, pages; - efi_add_memory_map(start, pages, EFI_CONVENTIONAL_MEMORY, - false); + ram_start = gd->bd->bi_dram[i].start; + ram_end = ram_start + gd->bd->bi_dram[i].size; + + /* Remove partial pages */ + ram_end &= ~EFI_PAGE_MASK; + ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; + + if (ram_end > ram_start) { + pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT; + + efi_add_memory_map(ram_start, pages, + EFI_CONVENTIONAL_MEMORY, false); + } } } -- cgit v1.2.3 From 19dd90748cb60ab2cf88b3e9c52b0da4bc0ae0a5 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 14 Nov 2018 16:18:53 +0900 Subject: efi_loader: correct a function prototype of QueryCapsuleCapabilities() See UEFI specification v2.7, section 8.5.3. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- include/efi_api.h | 4 ++-- lib/efi_loader/efi_runtime.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index 88a60070f6a..e58dd0581c9 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -241,8 +241,8 @@ struct efi_runtime_services { efi_status_t (EFIAPI *query_capsule_caps)( struct efi_capsule_header **capsule_header_array, efi_uintn_t capsule_count, - u64 maximum_capsule_size, - u32 reset_type); + u64 *maximum_capsule_size, + u32 *reset_type); efi_status_t (EFIAPI *query_variable_info)( u32 attributes, u64 *maximum_variable_storage_size, diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index ca66d33e588..405f7001404 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -628,8 +628,8 @@ efi_status_t __efi_runtime EFIAPI efi_update_capsule( efi_status_t __efi_runtime EFIAPI efi_query_capsule_caps( struct efi_capsule_header **capsule_header_array, efi_uintn_t capsule_count, - u64 maximum_capsule_size, - u32 reset_type) + u64 *maximum_capsule_size, + u32 *reset_type) { return EFI_UNSUPPORTED; } -- cgit v1.2.3 From 83582419ea3653fdf3e5e5d0434f9ff5a8217149 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Wed, 14 Nov 2018 16:18:07 +0900 Subject: efi_loader: SetVirtualAddressMap() should return EFI_UNSUPPORTED See UEFI specification 2.7, section 8.4. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 405f7001404..95844efdb0e 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -284,7 +284,7 @@ static const struct efi_runtime_detach_list_struct efi_runtime_detach_list[] = { }, { /* invalidate_*cache_all are gone */ .ptr = &efi_runtime_services.set_virtual_address_map, - .patchto = &efi_invalid_parameter, + .patchto = &efi_unimplemented, }, { /* RTC accessors are gone */ .ptr = &efi_runtime_services.get_time, -- cgit v1.2.3 From 02c2f0298a0b53ae0b8636567265b8a612c598d1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 5 Nov 2018 20:22:12 +0100 Subject: efi_loader: use u16* for UTF16 strings We should be consistent in the types that we use to store Unicode strings. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 2 +- lib/efi_loader/efi_file.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index e58dd0581c9..aef77b6319d 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -965,7 +965,7 @@ struct efi_file_info { struct efi_time last_access_time; struct efi_time modification_time; u64 attribute; - s16 file_name[0]; + u16 file_name[0]; }; struct efi_file_system_info { diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c index beb4fba917d..128cb0a6273 100644 --- a/lib/efi_loader/efi_file.c +++ b/lib/efi_loader/efi_file.c @@ -563,7 +563,7 @@ static efi_status_t EFIAPI efi_file_getinfo(struct efi_file_handle *file, if (fh->isdir) info->attribute |= EFI_FILE_DIRECTORY; - ascii2unicode((u16 *)info->file_name, filename); + ascii2unicode(info->file_name, filename); } else if (!guidcmp(info_type, &efi_file_system_info_guid)) { struct efi_file_system_info *info = buffer; disk_partition_t part; -- cgit v1.2.3 From f31239acff61f7def88a06eef1f091fce74ecd61 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Thu, 15 Nov 2018 21:23:47 +0100 Subject: Revert "efi_loader: remove efi_exit_caches()" This reverts commit 3170db63c41a2eda6ee6573353bb4de8c7c1b9d5. It reportedly breaks OpenBSD/armv7 booting and I've already received complaints from people that it breaks some Linux armv7 systems as well. We'll have to give this whole caching story a good bit more thought. Reported-by: Jonathan Gray Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index eb652e83485..cc9efbb0cbf 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -26,6 +26,14 @@ LIST_HEAD(efi_obj_list); /* List of all events */ LIST_HEAD(efi_events); +/* + * If we're running on nasty systems (32bit ARM booting into non-EFI Linux) + * we need to do trickery with caches. Since we don't want to break the EFI + * aware boot path, only apply hacks when loading exiting directly (breaking + * direct Linux EFI booting along the way - oh well). + */ +static bool efi_is_direct_boot = true; + #ifdef CONFIG_ARM /* * The "gd" pointer lives in a register on ARM and AArch64 that we declare @@ -1707,6 +1715,8 @@ static efi_status_t EFIAPI efi_start_image(efi_handle_t image_handle, EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data); + efi_is_direct_boot = false; + /* call the image! */ if (setjmp(&image_obj->exit_jmp)) { /* @@ -1814,6 +1824,21 @@ static efi_status_t EFIAPI efi_unload_image(efi_handle_t image_handle) return EFI_EXIT(EFI_SUCCESS); } +/** + * efi_exit_caches() - fix up caches for EFI payloads if necessary + */ +static void efi_exit_caches(void) +{ +#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64) + /* + * Grub on 32bit ARM needs to have caches disabled before jumping into + * a zImage, but does not know of all cache layers. Give it a hand. + */ + if (efi_is_direct_boot) + cleanup_before_linux(); +#endif +} + /** * efi_exit_boot_services() - stop all boot services * @image_handle: handle of the loaded image @@ -1867,6 +1892,9 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, board_quiesce_devices(); + /* Fix up caches for EFI payloads if necessary */ + efi_exit_caches(); + /* This stops all lingering devices */ bootm_disable_interrupts(); -- cgit v1.2.3 From a2505fc8a901180fb555291c6fd106df7efed71c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 22 Nov 2018 13:46:37 -0700 Subject: sandbox: smbios: Update to support sandbox At present this code casts addresses to pointers so cannot be used with sandbox. Update it to use mapmem instead. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_loader/efi_smbios.c | 20 +++++++++++------ lib/smbios.c | 52 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 56 insertions(+), 16 deletions(-) diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c index 38e42fa2432..a81488495e2 100644 --- a/lib/efi_loader/efi_smbios.c +++ b/lib/efi_loader/efi_smbios.c @@ -7,6 +7,7 @@ #include #include +#include #include static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID; @@ -19,17 +20,19 @@ static const efi_guid_t smbios_guid = SMBIOS_TABLE_GUID; efi_status_t efi_smbios_register(void) { /* Map within the low 32 bits, to allow for 32bit SMBIOS tables */ - u64 dmi = U32_MAX; + u64 dmi_addr = U32_MAX; efi_status_t ret; + void *dmi; /* Reserve 4kiB page for SMBIOS */ ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, - EFI_RUNTIME_SERVICES_DATA, 1, &dmi); + EFI_RUNTIME_SERVICES_DATA, 1, &dmi_addr); if (ret != EFI_SUCCESS) { /* Could not find space in lowmem, use highmem instead */ ret = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, - EFI_RUNTIME_SERVICES_DATA, 1, &dmi); + EFI_RUNTIME_SERVICES_DATA, 1, + &dmi_addr); if (ret != EFI_SUCCESS) return ret; @@ -39,11 +42,14 @@ efi_status_t efi_smbios_register(void) * Generate SMBIOS tables - we know that efi_allocate_pages() returns * a 4k-aligned address, so it is safe to assume that * write_smbios_table() will write the table at that address. + * + * Note that on sandbox, efi_allocate_pages() unfortunately returns a + * pointer even though it uses a uint64_t type. Convert it. */ - assert(!(dmi & 0xf)); - write_smbios_table(dmi); + assert(!(dmi_addr & 0xf)); + dmi = (void *)(uintptr_t)dmi_addr; + write_smbios_table(map_to_sysmem(dmi)); /* And expose them to our EFI payload */ - return efi_install_configuration_table(&smbios_guid, - (void *)(uintptr_t)dmi); + return efi_install_configuration_table(&smbios_guid, dmi); } diff --git a/lib/smbios.c b/lib/smbios.c index 326eb00230d..e8ee55c4aeb 100644 --- a/lib/smbios.c +++ b/lib/smbios.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -72,9 +73,10 @@ static int smbios_string_table_len(char *start) static int smbios_write_type0(ulong *current, int handle) { - struct smbios_type0 *t = (struct smbios_type0 *)*current; + struct smbios_type0 *t; int len = sizeof(struct smbios_type0); + t = map_sysmem(*current, len); memset(t, 0, sizeof(struct smbios_type0)); fill_smbios_header(t, SMBIOS_BIOS_INFORMATION, len, handle); t->vendor = smbios_add_string(t->eos, "U-Boot"); @@ -101,16 +103,18 @@ static int smbios_write_type0(ulong *current, int handle) len = t->length + smbios_string_table_len(t->eos); *current += len; + unmap_sysmem(t); return len; } static int smbios_write_type1(ulong *current, int handle) { - struct smbios_type1 *t = (struct smbios_type1 *)*current; + struct smbios_type1 *t; int len = sizeof(struct smbios_type1); char *serial_str = env_get("serial#"); + t = map_sysmem(*current, len); memset(t, 0, sizeof(struct smbios_type1)); fill_smbios_header(t, SMBIOS_SYSTEM_INFORMATION, len, handle); t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); @@ -122,15 +126,17 @@ static int smbios_write_type1(ulong *current, int handle) len = t->length + smbios_string_table_len(t->eos); *current += len; + unmap_sysmem(t); return len; } static int smbios_write_type2(ulong *current, int handle) { - struct smbios_type2 *t = (struct smbios_type2 *)*current; + struct smbios_type2 *t; int len = sizeof(struct smbios_type2); + t = map_sysmem(*current, len); memset(t, 0, sizeof(struct smbios_type2)); fill_smbios_header(t, SMBIOS_BOARD_INFORMATION, len, handle); t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); @@ -140,15 +146,17 @@ static int smbios_write_type2(ulong *current, int handle) len = t->length + smbios_string_table_len(t->eos); *current += len; + unmap_sysmem(t); return len; } static int smbios_write_type3(ulong *current, int handle) { - struct smbios_type3 *t = (struct smbios_type3 *)*current; + struct smbios_type3 *t; int len = sizeof(struct smbios_type3); + t = map_sysmem(*current, len); memset(t, 0, sizeof(struct smbios_type3)); fill_smbios_header(t, SMBIOS_SYSTEM_ENCLOSURE, len, handle); t->manufacturer = smbios_add_string(t->eos, CONFIG_SMBIOS_MANUFACTURER); @@ -160,6 +168,7 @@ static int smbios_write_type3(ulong *current, int handle) len = t->length + smbios_string_table_len(t->eos); *current += len; + unmap_sysmem(t); return len; } @@ -198,9 +207,10 @@ static void smbios_write_type4_dm(struct smbios_type4 *t) static int smbios_write_type4(ulong *current, int handle) { - struct smbios_type4 *t = (struct smbios_type4 *)*current; + struct smbios_type4 *t; int len = sizeof(struct smbios_type4); + t = map_sysmem(*current, len); memset(t, 0, sizeof(struct smbios_type4)); fill_smbios_header(t, SMBIOS_PROCESSOR_INFORMATION, len, handle); t->processor_type = SMBIOS_PROCESSOR_TYPE_CENTRAL; @@ -214,32 +224,37 @@ static int smbios_write_type4(ulong *current, int handle) len = t->length + smbios_string_table_len(t->eos); *current += len; + unmap_sysmem(t); return len; } static int smbios_write_type32(ulong *current, int handle) { - struct smbios_type32 *t = (struct smbios_type32 *)*current; + struct smbios_type32 *t; int len = sizeof(struct smbios_type32); + t = map_sysmem(*current, len); memset(t, 0, sizeof(struct smbios_type32)); fill_smbios_header(t, SMBIOS_SYSTEM_BOOT_INFORMATION, len, handle); *current += len; + unmap_sysmem(t); return len; } static int smbios_write_type127(ulong *current, int handle) { - struct smbios_type127 *t = (struct smbios_type127 *)*current; + struct smbios_type127 *t; int len = sizeof(struct smbios_type127); + t = map_sysmem(*current, len); memset(t, 0, sizeof(struct smbios_type127)); fill_smbios_header(t, SMBIOS_END_OF_TABLE, len, handle); *current += len; + unmap_sysmem(t); return len; } @@ -257,6 +272,7 @@ static smbios_write_type smbios_write_funcs[] = { ulong write_smbios_table(ulong addr) { struct smbios_entry *se; + ulong table_addr; ulong tables; int len = 0; int max_struct_size = 0; @@ -268,7 +284,7 @@ ulong write_smbios_table(ulong addr) /* 16 byte align the table address */ addr = ALIGN(addr, 16); - se = (struct smbios_entry *)(uintptr_t)addr; + se = map_sysmem(addr, sizeof(struct smbios_entry)); memset(se, 0, sizeof(struct smbios_entry)); addr += sizeof(struct smbios_entry); @@ -290,7 +306,24 @@ ulong write_smbios_table(ulong addr) se->max_struct_size = max_struct_size; memcpy(se->intermediate_anchor, "_DMI_", 5); se->struct_table_length = len; - se->struct_table_address = tables; + + /* + * We must use a pointer here so things work correctly on sandbox. The + * user of this table is not aware of the mapping of addresses to + * sandbox's DRAM buffer. + */ + table_addr = (ulong)map_sysmem(tables, 0); + if (sizeof(table_addr) > sizeof(u32) && table_addr > (ulong)UINT_MAX) { + /* + * We need to put this >32-bit pointer into the table but the + * field is only 32 bits wide. + */ + printf("WARNING: SMBIOS table_address overflow %llx\n", + (unsigned long long)table_addr); + table_addr = 0; + } + se->struct_table_address = table_addr; + se->struct_count = handle; /* calculate checksums */ @@ -298,6 +331,7 @@ ulong write_smbios_table(ulong addr) isize = sizeof(struct smbios_entry) - SMBIOS_INTERMEDIATE_OFFSET; se->intermediate_checksum = table_compute_checksum(istart, isize); se->checksum = table_compute_checksum(se, sizeof(struct smbios_entry)); + unmap_sysmem(se); return addr; } -- cgit v1.2.3 From 335ce71db78b80ab43cf68fcf812fb99bac84c86 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 25 Nov 2018 15:21:40 +0100 Subject: efi_selftest: incorrect use of bitwise or We should use a logical or when combining logical values. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_loaded_image.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_selftest/efi_selftest_loaded_image.c b/lib/efi_selftest/efi_selftest_loaded_image.c index f9b54ae2635..ea2b380a777 100644 --- a/lib/efi_selftest/efi_selftest_loaded_image.c +++ b/lib/efi_selftest/efi_selftest_loaded_image.c @@ -53,7 +53,7 @@ static int execute(void) efi_st_error("ProtocolsPerHandle failed\n"); return EFI_ST_FAILURE; } - if (!protocol_buffer_count | !protocol_buffer) { + if (!protocol_buffer_count || !protocol_buffer) { efi_st_error("ProtocolsPerHandle returned no protocol\n"); return EFI_ST_FAILURE; } -- cgit v1.2.3 From 7b78d6438a2b3a7f58a34934b54a1a83733b8fdd Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Fri, 30 Nov 2018 21:24:56 +0100 Subject: efi_loader: Reserve unaccessible memory On some systems, not all RAM may be usable within U-Boot. Maybe the memory maps are incomplete, maybe it's used as workaround for broken DMA. But whatever the reason may be, a platform can say that it does not wish to have its RAM accessed above a certain address by defining board_get_usable_ram_top(). In the efi_loader world, we ignored that hint, mostly because very few boards actually have real restrictions around this. So let's honor the board's wish to not access high addresses during boot time. The best way to do so is by indicating the respective pages as "allocated by firmware". That way, Operating Systems will still use the pages after boot, but before boot no allocation will use them. Reported-by: Baruch Siach Signed-off-by: Alexander Graf Reviewed-by: Stephen Warren Reviewed-by: Heinrich Schuchardt Tested-by: Baruch Siach --- include/common.h | 11 +++++++++++ lib/efi_loader/efi_memory.c | 32 +++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/common.h b/include/common.h index 8b561370326..a8e879e1b9a 100644 --- a/include/common.h +++ b/include/common.h @@ -105,6 +105,17 @@ int mdm_init(void); */ void board_show_dram(phys_size_t size); +/** + * Get the uppermost pointer that is valid to access + * + * Some systems may not map all of their address space. This function allows + * boards to indicate what their highest support pointer value is for DRAM + * access. + * + * @param total_size Size of U-Boot (unused?) + */ +ulong board_get_usable_ram_top(ulong total_size); + /** * arch_fixup_fdt() - Write arch-specific information to fdt * diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index f225a9028c5..73bfbb65c4d 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -551,8 +551,13 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, __weak void efi_add_known_memory(void) { + u64 ram_top = board_get_usable_ram_top(0) & ~EFI_PAGE_MASK; int i; + /* Fix for 32bit targets with ram_top at 4G */ + if (!ram_top) + ram_top = 0x100000000ULL; + /* Add RAM */ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { u64 ram_end, ram_start, pages; @@ -564,11 +569,32 @@ __weak void efi_add_known_memory(void) ram_end &= ~EFI_PAGE_MASK; ram_start = (ram_start + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; - if (ram_end > ram_start) { - pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT; + if (ram_end <= ram_start) { + /* Invalid mapping, keep going. */ + continue; + } + + pages = (ram_end - ram_start) >> EFI_PAGE_SHIFT; + efi_add_memory_map(ram_start, pages, + EFI_CONVENTIONAL_MEMORY, false); + + /* + * Boards may indicate to the U-Boot memory core that they + * can not support memory above ram_top. Let's honor this + * in the efi_loader subsystem too by declaring any memory + * above ram_top as "already occupied by firmware". + */ + if (ram_top < ram_start) { + /* ram_top is before this region, reserve all */ efi_add_memory_map(ram_start, pages, - EFI_CONVENTIONAL_MEMORY, false); + EFI_BOOT_SERVICES_DATA, true); + } else if ((ram_top >= ram_start) && (ram_top < ram_end)) { + /* ram_top is inside this region, reserve parts */ + pages = (ram_end - ram_top) >> EFI_PAGE_SHIFT; + + efi_add_memory_map(ram_top, pages, + EFI_BOOT_SERVICES_DATA, true); } } } -- cgit v1.2.3 From 2ab7ef74cd90a6d60df6aad7dac24b6a2bb1fe85 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Nov 2018 20:14:36 -0700 Subject: efi: Check for failure to create objects in selftest At present a few error conditions are not checked. Before refactoring this code, add some basic checks. Note that this code still leaks memory in the event of error. This will be tackled after the refactor. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 3e37805ea13..5be10c9b832 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -532,7 +532,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, (uintptr_t)&efi_selftest, (uintptr_t)&efi_selftest); + if (!bootefi_device_path) + return CMD_RET_FAILURE; + bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest"); + if (!bootefi_image_path) + return CMD_RET_FAILURE; r = efi_setup_loaded_image(bootefi_device_path, bootefi_image_path, &image_obj, -- cgit v1.2.3 From d9717eae316d4ffd84146257dd7674c2ff6406f9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Nov 2018 20:14:37 -0700 Subject: efi: Split out test init/uninit into functions The functions in bootefi are very long because they mix high-level code and control with the low-level implementation. To help with this, create functions which handle preparing for running the test and cleaning up afterwards. Also shorten the awfully long variable names here. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 85 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 5be10c9b832..666d90e4b70 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -453,6 +453,66 @@ exit: return ret; } +#ifdef CONFIG_CMD_BOOTEFI_SELFTEST +/** + * bootefi_test_prepare() - prepare to run an EFI test + * + * This sets things up so we can call EFI functions. This involves preparing + * the 'gd' pointer and setting up the load ed image data structures. + * + * @image_objp: loaded_image_infop: Pointer to a struct which will hold the + * loaded image object. This struct will be inited by this function before + * use. + * @loaded_image_infop: Pointer to a struct which will hold the loaded image + * info. This struct will be inited by this function before use. + * @path: File path to the test being run (often just the test name with a + * backslash before it + * @test_func: Address of the test function that is being run + * @return 0 if OK, -ve on error + */ +static efi_status_t bootefi_test_prepare + (struct efi_loaded_image_obj **image_objp, + struct efi_loaded_image **loaded_image_infop, + const char *path, + ulong test_func) +{ + efi_status_t r; + + /* Construct a dummy device path */ + bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, + (uintptr_t)test_func, + (uintptr_t)test_func); + if (!bootefi_device_path) + return EFI_OUT_OF_RESOURCES; + bootefi_image_path = efi_dp_from_file(NULL, 0, path); + if (!bootefi_image_path) + return EFI_OUT_OF_RESOURCES; + r = efi_setup_loaded_image(bootefi_device_path, bootefi_image_path, + image_objp, loaded_image_infop); + if (r) + return r; + + /* Transfer environment variable efi_selftest as load options */ + set_load_options(*loaded_image_infop, "efi_selftest"); + + return 0; +} + +/** + * bootefi_test_finish() - finish up after running an EFI test + * + * @image_obj: Pointer to a struct which holds the loaded image object + * @loaded_image_info: Pointer to a struct which holds the loaded image info + */ +static void bootefi_test_finish(struct efi_loaded_image_obj *image_obj, + struct efi_loaded_image *loaded_image_info) +{ + efi_restore_gd(); + free(loaded_image_info->load_options); + efi_delete_handle(&image_obj->header); +} +#endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ + static int do_bootefi_bootmgr_exec(void) { struct efi_device_path *device_path, *file_path; @@ -528,31 +588,14 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) struct efi_loaded_image_obj *image_obj; struct efi_loaded_image *loaded_image_info; - /* Construct a dummy device path. */ - bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, - (uintptr_t)&efi_selftest, - (uintptr_t)&efi_selftest); - if (!bootefi_device_path) - return CMD_RET_FAILURE; - - bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest"); - if (!bootefi_image_path) + if (bootefi_test_prepare(&image_obj, &loaded_image_info, + "\\selftest", + (uintptr_t)&efi_selftest)) return CMD_RET_FAILURE; - r = efi_setup_loaded_image(bootefi_device_path, - bootefi_image_path, &image_obj, - &loaded_image_info); - if (r != EFI_SUCCESS) - return CMD_RET_FAILURE; - - efi_save_gd(); - /* Transfer environment variable efi_selftest as load options */ - set_load_options(loaded_image_info, "efi_selftest"); /* Execute the test */ r = efi_selftest(&image_obj->header, &systab); - efi_restore_gd(); - free(loaded_image_info->load_options); - efi_delete_handle(&image_obj->header); + bootefi_test_finish(image_obj, loaded_image_info); return r != EFI_SUCCESS; } else #endif -- cgit v1.2.3 From f4f0f7cb6e0a61f4a3ae0f2aadbe95654df602b5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Nov 2018 20:14:38 -0700 Subject: efi: Create a function to set up for running EFI code There is still duplicated code in efi_loader for tests and normal operation. Add a new bootefi_run_prepare() function which holds common code used to set up U-Boot to run EFI code. Make use of this from the existing bootefi_test_prepare() function, as well as do_bootefi_exec(). Also shorten a few variable names. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 52 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 666d90e4b70..ca6693a245e 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -325,6 +325,25 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) return ret; } +static efi_status_t bootefi_run_prepare(const char *load_options_path, + struct efi_device_path *device_path, + struct efi_device_path *image_path, + struct efi_loaded_image_obj **image_objp, + struct efi_loaded_image **loaded_image_infop) +{ + efi_status_t ret; + + ret = efi_setup_loaded_image(device_path, image_path, image_objp, + loaded_image_infop); + if (ret != EFI_SUCCESS) + return ret; + + /* Transfer environment variable as load options */ + set_load_options(*loaded_image_infop, load_options_path); + + return 0; +} + /** * do_bootefi_exec() - execute EFI binary * @@ -374,13 +393,11 @@ static efi_status_t do_bootefi_exec(void *efi, assert(device_path && image_path); } - ret = efi_setup_loaded_image(device_path, image_path, &image_obj, - &loaded_image_info); - if (ret != EFI_SUCCESS) - goto exit; + ret = bootefi_run_prepare("bootargs", device_path, image_path, + &image_obj, &loaded_image_info); + if (ret) + return ret; - /* Transfer environment variable bootargs as load options */ - set_load_options(loaded_image_info, "bootargs"); /* Load the EFI payload */ entry = efi_load_pe(image_obj, efi, loaded_image_info); if (!entry) { @@ -468,16 +485,14 @@ exit: * @path: File path to the test being run (often just the test name with a * backslash before it * @test_func: Address of the test function that is being run + * @load_options_path: U-Boot environment variable to use as load options * @return 0 if OK, -ve on error */ static efi_status_t bootefi_test_prepare (struct efi_loaded_image_obj **image_objp, - struct efi_loaded_image **loaded_image_infop, - const char *path, - ulong test_func) + struct efi_loaded_image **loaded_image_infop, const char *path, + ulong test_func, const char *load_options_path) { - efi_status_t r; - /* Construct a dummy device path */ bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE, (uintptr_t)test_func, @@ -487,15 +502,10 @@ static efi_status_t bootefi_test_prepare bootefi_image_path = efi_dp_from_file(NULL, 0, path); if (!bootefi_image_path) return EFI_OUT_OF_RESOURCES; - r = efi_setup_loaded_image(bootefi_device_path, bootefi_image_path, - image_objp, loaded_image_infop); - if (r) - return r; - /* Transfer environment variable efi_selftest as load options */ - set_load_options(*loaded_image_infop, "efi_selftest"); - - return 0; + return bootefi_run_prepare(load_options_path, bootefi_device_path, + bootefi_image_path, image_objp, + loaded_image_infop); } /** @@ -589,8 +599,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) struct efi_loaded_image *loaded_image_info; if (bootefi_test_prepare(&image_obj, &loaded_image_info, - "\\selftest", - (uintptr_t)&efi_selftest)) + "\\selftest", (uintptr_t)&efi_selftest, + "efi_selftest")) return CMD_RET_FAILURE; /* Execute the test */ -- cgit v1.2.3 From 5e2f03910731e825b964452356414ab2e99df4d2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 25 Nov 2018 20:14:39 -0700 Subject: efi: Rename bootefi_test_finish() to bootefi_run_finish() This function can be used from do_bootefi_exec() so that we use mostly the same code for a normal EFI application and an EFI test. Rename the function and use it in both places. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index ca6693a245e..eadfd934b73 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -344,6 +344,20 @@ static efi_status_t bootefi_run_prepare(const char *load_options_path, return 0; } +/** + * bootefi_run_finish() - finish up after running an EFI test + * + * @loaded_image_info: Pointer to a struct which holds the loaded image info + * @image_objj: Pointer to a struct which holds the loaded image object + */ +static void bootefi_run_finish(struct efi_loaded_image_obj *image_obj, + struct efi_loaded_image *loaded_image_info) +{ + efi_restore_gd(); + free(loaded_image_info->load_options); + efi_delete_handle(&image_obj->header); +} + /** * do_bootefi_exec() - execute EFI binary * @@ -384,11 +398,11 @@ static efi_status_t do_bootefi_exec(void *efi, */ ret = efi_create_handle(&mem_handle); if (ret != EFI_SUCCESS) - goto exit; + return ret; /* TODO: leaks device_path */ ret = efi_add_protocol(mem_handle, &efi_guid_device_path, device_path); if (ret != EFI_SUCCESS) - goto exit; + goto err_add_protocol; } else { assert(device_path && image_path); } @@ -396,13 +410,13 @@ static efi_status_t do_bootefi_exec(void *efi, ret = bootefi_run_prepare("bootargs", device_path, image_path, &image_obj, &loaded_image_info); if (ret) - return ret; + goto err_prepare; /* Load the EFI payload */ entry = efi_load_pe(image_obj, efi, loaded_image_info); if (!entry) { ret = EFI_LOAD_ERROR; - goto exit; + goto err_prepare; } if (memdp) { @@ -422,7 +436,7 @@ static efi_status_t do_bootefi_exec(void *efi, if (setjmp(&image_obj->exit_jmp)) { ret = image_obj->exit_status; - goto exit; + goto err_prepare; } #ifdef CONFIG_ARM64 @@ -460,10 +474,11 @@ static efi_status_t do_bootefi_exec(void *efi, ret = efi_do_enter(&image_obj->header, &systab, entry); -exit: +err_prepare: /* image has returned, loaded-image obj goes *poof*: */ - if (image_obj) - efi_delete_handle(&image_obj->header); + bootefi_run_finish(image_obj, loaded_image_info); + +err_add_protocol: if (mem_handle) efi_delete_handle(mem_handle); @@ -508,19 +523,6 @@ static efi_status_t bootefi_test_prepare loaded_image_infop); } -/** - * bootefi_test_finish() - finish up after running an EFI test - * - * @image_obj: Pointer to a struct which holds the loaded image object - * @loaded_image_info: Pointer to a struct which holds the loaded image info - */ -static void bootefi_test_finish(struct efi_loaded_image_obj *image_obj, - struct efi_loaded_image *loaded_image_info) -{ - efi_restore_gd(); - free(loaded_image_info->load_options); - efi_delete_handle(&image_obj->header); -} #endif /* CONFIG_CMD_BOOTEFI_SELFTEST */ static int do_bootefi_bootmgr_exec(void) @@ -605,7 +607,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) /* Execute the test */ r = efi_selftest(&image_obj->header, &systab); - bootefi_test_finish(image_obj, loaded_image_info); + bootefi_run_finish(image_obj, loaded_image_info); return r != EFI_SUCCESS; } else #endif -- cgit v1.2.3 From 49759743bf090dfa859f036804630e54b8a3f803 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:46 +0100 Subject: efi_loader: eliminate sandbox addresses Do not use the sandbox's virtual address space for the internal structures of the memory map. This way we can eliminate a whole lot of unnecessary conversions. The only conversion remaining is the one when adding known memory. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 73bfbb65c4d..307e6f77ab7 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -384,7 +384,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, /* Reserve that map in our memory maps */ ret = efi_add_memory_map(addr, pages, memory_type, true); if (ret == addr) { - *memory = (uintptr_t)map_sysmem(addr, len); + *memory = addr; } else { /* Map would overlap, bail out */ r = EFI_OUT_OF_RESOURCES; @@ -418,12 +418,11 @@ void *efi_alloc(uint64_t len, int memory_type) efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) { uint64_t r = 0; - uint64_t addr = map_to_sysmem((void *)(uintptr_t)memory); - r = efi_add_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, false); + r = efi_add_memory_map(memory, pages, EFI_CONVENTIONAL_MEMORY, false); /* Merging of adjacent free regions is missing */ - if (r == addr) + if (r == memory) return EFI_SUCCESS; return EFI_NOT_FOUND; @@ -562,7 +561,7 @@ __weak void efi_add_known_memory(void) for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { u64 ram_end, ram_start, pages; - ram_start = gd->bd->bi_dram[i].start; + ram_start = (uintptr_t)map_sysmem(gd->bd->bi_dram[i].start, 0); ram_end = ram_start + gd->bd->bi_dram[i].size; /* Remove partial pages */ -- cgit v1.2.3 From 34841303ac2c5564f6430627f30c8ade08b2b471 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:47 +0100 Subject: efi_selftest: add test for memory allocation This unit test checks the following runtime services: AllocatePages, FreePages, GetMemoryMap Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_memory.c | 163 +++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_memory.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 4b1c0bb84b1..743b4820449 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -27,6 +27,7 @@ efi_selftest_fdt.o \ efi_selftest_gop.o \ efi_selftest_loaded_image.o \ efi_selftest_manageprotocols.o \ +efi_selftest_memory.o \ efi_selftest_rtc.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ diff --git a/lib/efi_selftest/efi_selftest_memory.c b/lib/efi_selftest/efi_selftest_memory.c new file mode 100644 index 00000000000..0623e8e62da --- /dev/null +++ b/lib/efi_selftest/efi_selftest_memory.c @@ -0,0 +1,163 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_memory + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * This unit test checks the following runtime services: + * AllocatePages, FreePages, GetMemoryMap + */ + +#include + +#define EFI_ST_NUM_PAGES 8 + +static struct efi_boot_services *boottime; + +/** + * setup() - setup unit test + * + * @handle: handle of the loaded image + * @systable: system table + * Return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/** + * find_in_memory_map() - check matching memory map entry exists + * + * @memory_map: memory map + * @desc_size: number of memory map entries + * @addr: physical address to find in the map + * @type: expected memory type + * Return: EFI_ST_SUCCESS for success + */ +static int find_in_memory_map(efi_uintn_t map_size, + struct efi_mem_desc *memory_map, + efi_uintn_t desc_size, + u64 addr, int memory_type) +{ + efi_uintn_t i; + bool found = false; + + for (i = 0; map_size; ++i, map_size -= desc_size) { + struct efi_mem_desc *entry = &memory_map[i]; + + if (addr >= entry->physical_start && + addr < entry->physical_start + + (entry->num_pages << EFI_PAGE_SHIFT)) { + if (found) { + efi_st_error("Duplicate memory map entry\n"); + return EFI_ST_FAILURE; + } + found = true; + if (memory_type != entry->type) { + efi_st_error + ("Wrong memory type %d, expected %d\n", + entry->type, memory_type); + return EFI_ST_FAILURE; + } + } + } + if (!found) { + efi_st_error("Missing memory map entry\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * execute() - execute unit test + * + * Return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + u64 p1; + u64 p2; + efi_uintn_t map_size = 0; + efi_uintn_t map_key; + efi_uintn_t desc_size; + u32 desc_version; + struct efi_mem_desc *memory_map; + efi_status_t ret; + + /* Allocate two page ranges with different memory type */ + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_CODE, + EFI_ST_NUM_PAGES, &p1); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->allocate_pages(EFI_ALLOCATE_ANY_PAGES, + EFI_RUNTIME_SERVICES_DATA, + EFI_ST_NUM_PAGES, &p2); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + /* Load memory map */ + ret = boottime->get_memory_map(&map_size, NULL, &map_key, &desc_size, + &desc_version); + if (ret != EFI_BUFFER_TOO_SMALL) { + efi_st_error + ("GetMemoryMap did not return EFI_BUFFER_TOO_SMALL\n"); + return EFI_ST_FAILURE; + } + /* Allocate extra space for newly allocated memory */ + map_size += sizeof(struct efi_mem_desc); + ret = boottime->allocate_pool(EFI_BOOT_SERVICES_DATA, map_size, + (void **)&memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("AllocatePool did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->get_memory_map(&map_size, memory_map, &map_key, + &desc_size, &desc_version); + if (ret != EFI_SUCCESS) { + efi_st_error("GetMemoryMap did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + /* Check memory map entries */ + if (find_in_memory_map(map_size, memory_map, desc_size, p1, + EFI_RUNTIME_SERVICES_CODE) != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + if (find_in_memory_map(map_size, memory_map, desc_size, p2, + EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) + return EFI_ST_FAILURE; + + /* Free memory */ + ret = boottime->free_pages(p1, EFI_ST_NUM_PAGES); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pages(p2, EFI_ST_NUM_PAGES); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePages did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + ret = boottime->free_pool(memory_map); + if (ret != EFI_SUCCESS) { + efi_st_error("FreePool did not return EFI_SUCCESS\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(memory) = { + .name = "memory", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; -- cgit v1.2.3 From 42910ff1baa9c6bf9e0eecbe252bf06e11861fa8 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:48 +0100 Subject: efi_selftest: building sandbox with EFI_SELFTEST Enable building the sandbox with CONFIG_EFI_SELFTEST. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig index b52696778dd..59f9f36801c 100644 --- a/lib/efi_selftest/Kconfig +++ b/lib/efi_selftest/Kconfig @@ -1,6 +1,6 @@ config CMD_BOOTEFI_SELFTEST bool "Allow booting an EFI efi_selftest" - depends on CMD_BOOTEFI && !SANDBOX + depends on CMD_BOOTEFI imply FAT imply FAT_WRITE help -- cgit v1.2.3 From c3772ca1e38f36f2486b44c27094421442414e5e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:49 +0100 Subject: efi_loader: macro efi_size_in_pages() When allocating EFI memory pages the size in bytes has to be converted to pages. Provide a macro efi_size_in_pages() for this conversion. Use it in the EFI subsystem and correct related comments. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 15 ++++++--------- include/efi_loader.h | 11 ++++++++++- lib/efi_loader/efi_memory.c | 6 +++--- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index eadfd934b73..a57b0b4fe4b 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -149,7 +149,7 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info, * copy_fdt() - Copy the device tree to a new location available to EFI * * The FDT is relocated into a suitable location within the EFI memory map. - * An additional 12KB is added to the space in case the device tree needs to be + * Additional 12 KiB are added to the space in case the device tree needs to be * expanded later with fdt_open_into(). * * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated @@ -177,14 +177,12 @@ static efi_status_t copy_fdt(ulong *fdt_addrp) } /* - * Give us at least 4KB of breathing room in case the device tree needs - * to be expanded later. Round up to the nearest EFI page boundary. + * Give us at least 12 KiB of breathing room in case the device tree + * needs to be expanded later. */ fdt = map_sysmem(*fdt_addrp, 0); - fdt_size = fdt_totalsize(fdt); - fdt_size += 4096 * 3; - fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE); - fdt_pages = fdt_size >> EFI_PAGE_SHIFT; + fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000); + fdt_size = fdt_pages << EFI_PAGE_SHIFT; /* Safe fdt location is at 127MB */ new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size; @@ -282,8 +280,7 @@ static void efi_carve_out_dt_rsv(void *fdt) if (addr == (uintptr_t)fdt) continue; - pages = ALIGN(size + (addr & EFI_PAGE_MASK), EFI_PAGE_SIZE) >> - EFI_PAGE_SHIFT; + pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK)); addr &= ~EFI_PAGE_MASK; if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, false)) diff --git a/include/efi_loader.h b/include/efi_loader.h index f399e995060..3c90515fef1 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -344,7 +344,16 @@ struct efi_simple_file_system_protocol *efi_simple_file_system( /* open file from device-path: */ struct efi_file_handle *efi_file_from_path(struct efi_device_path *fp); - +/** + * efi_size_in_pages() - convert size in bytes to size in pages + * + * This macro returns the number of EFI memory pages required to hold 'size' + * bytes. + * + * @size: size in bytes + * Return: size in pages + */ +#define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT) /* Generic EFI memory allocator, call this to get memory */ void *efi_alloc(uint64_t len, int memory_type); /* More specific EFI memory allocator, called by EFI payloads */ diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 307e6f77ab7..5359118b4d7 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -397,7 +397,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, void *efi_alloc(uint64_t len, int memory_type) { uint64_t ret = 0; - uint64_t pages = (len + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + uint64_t pages = efi_size_in_pages(len); efi_status_t r; r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, memory_type, pages, @@ -440,8 +440,8 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) { efi_status_t r; struct efi_pool_allocation *alloc; - u64 num_pages = (size + sizeof(struct efi_pool_allocation) + - EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + u64 num_pages = efi_size_in_pages(size + + sizeof(struct efi_pool_allocation)); if (!buffer) return EFI_INVALID_PARAMETER; -- cgit v1.2.3 From f980c99985dda829f4300bfec32695dfe4731849 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:50 +0100 Subject: fdt: sandbox: correct use of ${fdtcontroladdr} The sandbox uses a virtual address space that is neither the physical nor the virtual address space of the operating system. All address used on the command line live in this address space. So also the environment variable ${fdtcontroladdr} has to be in this address space. Commands like bootefi and booti receive the fdt address as parameter. Without the patch ${fdtcontroladdr} cannot be used as parameter value on the sandbox. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- common/board_r.c | 3 ++- lib/fdtdec.c | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/common/board_r.c b/common/board_r.c index c55e33eec27..745212be71a 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -453,7 +453,8 @@ static int initr_env(void) else set_default_env(NULL, 0); #ifdef CONFIG_OF_CONTROL - env_set_addr("fdtcontroladdr", gd->fdt_blob); + env_set_hex("fdtcontroladdr", + (unsigned long)map_to_sysmem(gd->fdt_blob)); #endif /* Initialize from environment */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index d28f2cbb1cf..cbdc0778258 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -1253,8 +1254,9 @@ int fdtdec_setup(void) # if CONFIG_IS_ENABLED(OF_PRIOR_STAGE) gd->fdt_blob = (void *)prior_stage_fdt_address; # else - gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16, - (uintptr_t)gd->fdt_blob); + gd->fdt_blob = map_sysmem + (env_get_ulong("fdtcontroladdr", 16, + (unsigned long)map_to_sysmem(gd->fdt_blob)), 0); # endif # endif -- cgit v1.2.3 From 9ad0a799e55a55b23ebad26dbad5fcd0dbedecf6 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:51 +0100 Subject: fdt_support: fdt reservations on the sandbox On the sandbox the memory addresses in the device tree refer to the virtual address space of the sandbox. This implies that the memory reservations for the fdt also have to be converted to this address space. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- common/fdt_support.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/fdt_support.c b/common/fdt_support.c index e6daa67990d..3440e42a257 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -633,7 +634,7 @@ int fdt_shrink_to_minimum(void *blob, uint extrasize) fdt_set_totalsize(blob, actualsize); /* Add the new reservation */ - ret = fdt_add_mem_rsv(blob, (uintptr_t)blob, actualsize); + ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize); if (ret < 0) return ret; -- cgit v1.2.3 From 16b615d9abd006fb69930860f23e7785a48d040a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:52 +0100 Subject: efi_loader: fix memory mapping for sandbox The sandbox is using a virtual address space which is neither the physical address space of the operating system nor the virtual address space in which Linux aplications live. The addresses used insided the flattened device tree use this sandbox virtual address space. The EFI subsystem uses the virtual address space of the operating system and this is where the fdt is stored. Fix all incorrect addresses for the fdt in cmd/bootefi.cmd. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index a57b0b4fe4b..ad97a9c0196 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -148,15 +148,16 @@ static void set_load_options(struct efi_loaded_image *loaded_image_info, /** * copy_fdt() - Copy the device tree to a new location available to EFI * - * The FDT is relocated into a suitable location within the EFI memory map. + * The FDT is copied to a suitable location within the EFI memory map. * Additional 12 KiB are added to the space in case the device tree needs to be * expanded later with fdt_open_into(). * - * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated + * @fdtp: On entry a pointer to the flattened device tree. + * On exit a pointer to the copy of the flattened device tree. * FDT start * Return: status code */ -static efi_status_t copy_fdt(ulong *fdt_addrp) +static efi_status_t copy_fdt(void **fdtp) { unsigned long fdt_ram_start = -1L, fdt_pages; efi_status_t ret = 0; @@ -180,12 +181,16 @@ static efi_status_t copy_fdt(ulong *fdt_addrp) * Give us at least 12 KiB of breathing room in case the device tree * needs to be expanded later. */ - fdt = map_sysmem(*fdt_addrp, 0); + fdt = *fdtp; fdt_pages = efi_size_in_pages(fdt_totalsize(fdt) + 0x3000); fdt_size = fdt_pages << EFI_PAGE_SHIFT; - /* Safe fdt location is at 127MB */ - new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size; + /* + * Safe fdt location is at 127 MiB. + * On the sandbox convert from the sandbox address space. + */ + new_fdt_addr = (uintptr_t)map_sysmem(fdt_ram_start + 0x7f00000 + + fdt_size, 0); ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_RUNTIME_SERVICES_DATA, fdt_pages, &new_fdt_addr); @@ -200,12 +205,11 @@ static efi_status_t copy_fdt(ulong *fdt_addrp) goto done; } } - - new_fdt = map_sysmem(new_fdt_addr, fdt_size); + new_fdt = (void *)(uintptr_t)new_fdt_addr; memcpy(new_fdt, fdt, fdt_totalsize(fdt)); fdt_set_totalsize(new_fdt, fdt_size); - *fdt_addrp = new_fdt_addr; + *fdtp = (void *)(uintptr_t)new_fdt_addr; done: return ret; } @@ -273,6 +277,9 @@ static void efi_carve_out_dt_rsv(void *fdt) if (fdt_get_mem_rsv(fdt, i, &addr, &size) != 0) continue; + /* Convert from sandbox address space. */ + addr = (uintptr_t)map_sysmem(addr, 0); + /* * Do not carve out the device tree. It is already marked as * EFI_RUNTIME_SERVICES_DATA @@ -301,12 +308,10 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) } /* Prepare fdt for payload */ - ret = copy_fdt(&fdt_addr); + ret = copy_fdt(&fdt); if (ret) return ret; - unmap_sysmem(fdt); - fdt = map_sysmem(fdt_addr, 0); if (image_setup_libfdt(&img, fdt, 0, NULL)) { printf("ERROR: failed to process device tree\n"); return EFI_LOAD_ERROR; -- cgit v1.2.3 From 0c9ac06a2894ea08488b5f8f5d1e5cbd57808900 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:53 +0100 Subject: efi_loader: create fdt reservation before copy When copying the device we must ensure that the copy does not fall into a memory area reserved by the same. So let's change the sequence: first create memory reservations and then copy the device tree. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index ad97a9c0196..38679ffc56a 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -280,13 +280,6 @@ static void efi_carve_out_dt_rsv(void *fdt) /* Convert from sandbox address space. */ addr = (uintptr_t)map_sysmem(addr, 0); - /* - * Do not carve out the device tree. It is already marked as - * EFI_RUNTIME_SERVICES_DATA - */ - if (addr == (uintptr_t)fdt) - continue; - pages = efi_size_in_pages(size + (addr & EFI_PAGE_MASK)); addr &= ~EFI_PAGE_MASK; if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, @@ -307,6 +300,9 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) return EFI_INVALID_PARAMETER; } + /* Create memory reservation as indicated by the device tree */ + efi_carve_out_dt_rsv(fdt); + /* Prepare fdt for payload */ ret = copy_fdt(&fdt); if (ret) @@ -317,8 +313,6 @@ static efi_status_t efi_install_fdt(ulong fdt_addr) return EFI_LOAD_ERROR; } - efi_carve_out_dt_rsv(fdt); - /* Link to it in the efi tables */ ret = efi_install_configuration_table(&efi_guid_fdt, fdt); if (ret != EFI_SUCCESS) -- cgit v1.2.3 From 34c96659ed578b50f08bbba40e39fdb9d15865e1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 18 Nov 2018 17:58:54 +0100 Subject: efi_selftest: check fdt is marked as runtime data Check that the memory area containing the device tree is marked as runtime data. Update the Python test to pass ${fdtcontroladdr} to bootefi. Update the description of the Python test. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_memory.c | 24 ++++++++++++++++++++++++ test/py/tests/test_efi_selftest.py | 10 ++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_memory.c b/lib/efi_selftest/efi_selftest_memory.c index 0623e8e62da..24b4438ce4f 100644 --- a/lib/efi_selftest/efi_selftest_memory.c +++ b/lib/efi_selftest/efi_selftest_memory.c @@ -6,13 +6,17 @@ * * This unit test checks the following runtime services: * AllocatePages, FreePages, GetMemoryMap + * + * The memory type used for the device tree is checked. */ #include #define EFI_ST_NUM_PAGES 8 +static const efi_guid_t fdt_guid = EFI_FDT_GUID; static struct efi_boot_services *boottime; +static u64 fdt_addr; /** * setup() - setup unit test @@ -24,8 +28,20 @@ static struct efi_boot_services *boottime; static int setup(const efi_handle_t handle, const struct efi_system_table *systable) { + size_t i; + boottime = systable->boottime; + for (i = 0; i < systable->nr_tables; ++i) { + if (!efi_st_memcmp(&systable->tables[i].guid, &fdt_guid, + sizeof(efi_guid_t))) { + if (fdt_addr) { + efi_st_error("Duplicate device tree\n"); + return EFI_ST_FAILURE; + } + fdt_addr = (uintptr_t)systable->tables[i].table; + } + } return EFI_ST_SUCCESS; } @@ -152,6 +168,14 @@ static int execute(void) return EFI_ST_FAILURE; } + /* Check memory reservation for the device tree */ + if (fdt_addr && + find_in_memory_map(map_size, memory_map, desc_size, fdt_addr, + EFI_RUNTIME_SERVICES_DATA) != EFI_ST_SUCCESS) { + efi_st_error + ("Device tree not marked as runtime services data\n"); + return EFI_ST_FAILURE; + } return EFI_ST_SUCCESS; } diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py index e0833ffe22c..36b35ee536b 100644 --- a/test/py/tests/test_efi_selftest.py +++ b/test/py/tests/test_efi_selftest.py @@ -8,12 +8,14 @@ import u_boot_utils @pytest.mark.buildconfigspec('cmd_bootefi_selftest') def test_efi_selftest(u_boot_console): - """ - Run bootefi selftest - """ + """Test the UEFI implementation + + :param u_boot_console: U-Boot console + This function executes all selftests that are not marked as on request. + """ u_boot_console.run_command(cmd='setenv efi_selftest') - u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False) + u_boot_console.run_command(cmd='bootefi selftest ${fdtcontroladdr}', wait_for_prompt=False) m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key']) if m != 0: raise Exception('Failures occurred during the EFI selftest') -- cgit v1.2.3 From 65fa17d41755ed1bc923bf09303b95a34e0e855f Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 16 Nov 2018 20:17:23 +0100 Subject: MAINTAINERS: add EFI PAYLOAD reviewer Alex suggested to add me as a reviewer for the EFI subsystem. The patch also adds a description for R: entries. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- MAINTAINERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 214629e2830..8ea8ef9924e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2,6 +2,8 @@ Descriptions of section entries: P: Person (obsolete) M: Mail patches to: FullName + R: Designated reviewer: FullName + These reviewers should be CCed on patches. L: Mailing list that is relevant to this area W: Web-page with status/info Q: Patchwork web based patch tracking system site @@ -414,6 +416,7 @@ F: test/dm/ EFI PAYLOAD M: Alexander Graf +R: Heinrich Schuchardt S: Maintained T: git git://github.com/agraf/u-boot.git F: doc/README.uefi -- cgit v1.2.3 From 0fdb9e30b325f52422fe9cf5e4c9d060a6d33562 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 20 Oct 2018 22:01:08 +0200 Subject: efi_selftest: fix simple network protocol test To use the simple network protocol we have to call the start service first and the initialize service second. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_snp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_snp.c b/lib/efi_selftest/efi_selftest_snp.c index 09bd53da82d..e10a34ba645 100644 --- a/lib/efi_selftest/efi_selftest_snp.c +++ b/lib/efi_selftest/efi_selftest_snp.c @@ -103,7 +103,7 @@ static efi_status_t send_dhcp_discover(void) struct dhcp p = {}; /* - * Fill ethernet header + * 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, @@ -229,19 +229,19 @@ static int setup(const efi_handle_t handle, return EFI_ST_FAILURE; } /* - * Initialize network adapter. + * Start network adapter. */ - ret = net->initialize(net, 0, 0); - if (ret != EFI_SUCCESS) { - efi_st_error("Failed to initialize network adapter\n"); + ret = net->start(net); + if (ret != EFI_SUCCESS && ret != EFI_ALREADY_STARTED) { + efi_st_error("Failed to start network adapter\n"); return EFI_ST_FAILURE; } /* - * Start network adapter. + * Initialize network adapter. */ - ret = net->start(net); + ret = net->initialize(net, 0, 0); if (ret != EFI_SUCCESS) { - efi_st_error("Failed to start network adapter\n"); + efi_st_error("Failed to initialize network adapter\n"); return EFI_ST_FAILURE; } return EFI_ST_SUCCESS; -- cgit v1.2.3 From 622fe621a2e7f431f7dc5dcdfd30d56af00de0ae Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 1 Dec 2018 00:16:32 +0100 Subject: efi_loader: correctly aligned transmit buffer Calling net_send_packet() requires that the buffer is aligned to a multiple of PKTALIGN (= ARCH_DMA_MINALIGN). The UEFI spec does not require efi_net_transmit() to be called with a buffer with any special alignment. So we have to copy to an aligned buffer. The current coding copies to an aligned buffer only if CONFIG_EFI_LOADER_BOUNCE_BUFFER=y. Many boards like the Odroid C2 do not use a bounce buffer. With the patch we copy to a correctly aligned buffer in all cases. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index a64c603ed3e..68ed9e9520c 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -14,6 +14,8 @@ 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; +static void *transmit_buffer; + /* * The notification function of this event is called in every timer cycle * to check if a new network packet has been received. @@ -198,13 +200,11 @@ static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, return EFI_EXIT(EFI_INVALID_PARAMETER); } -#ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER - /* Ethernet packets always fit, just bounce */ - memcpy(efi_bounce_buffer, buffer, buffer_size); - net_send_packet(efi_bounce_buffer, buffer_size); -#else - net_send_packet(buffer, buffer_size); -#endif + /* Ensure that the packet fits into the buffer */ + if (buffer_size > PKTSIZE_ALIGN) + return EFI_EXIT(EFI_INVALID_PARAMETER); + memcpy(transmit_buffer, buffer, buffer_size); + net_send_packet(transmit_buffer, buffer_size); new_tx_packet = buffer; @@ -325,10 +325,14 @@ efi_status_t efi_net_register(void) /* We only expose the "active" network device, so one is enough */ netobj = calloc(1, sizeof(*netobj)); - if (!netobj) { - printf("ERROR: Out of memory\n"); - return EFI_OUT_OF_RESOURCES; - } + if (!netobj) + goto out_of_resources; + + /* Allocate an aligned transmit buffer */ + transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN); + if (!transmit_buffer) + goto out_of_resources; + transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN); /* Hook net up to the device list */ efi_add_handle(&netobj->header); @@ -408,4 +412,9 @@ efi_status_t efi_net_register(void) failure_to_add_protocol: printf("ERROR: Failure to add protocol\n"); return r; +out_of_resources: + free(netobj); + /* free(transmit_buffer) not needed yet */ + printf("ERROR: Out of memory\n"); + return EFI_OUT_OF_RESOURCES; } -- cgit v1.2.3 From 41b0587981c44552c53bafa8ac9121ee3a4b2ee0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 1 Dec 2018 00:16:33 +0100 Subject: efi_loader: fix simple network protocol We should not call eth_rx() before the network interface is initialized. The services of the simple network protocol should check the state of the network adapter. Add and correct comments. Without this patch i.mx6 system Wandboard Quad rev B1 fails to execute bootefi selftest. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_net.c | 391 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 332 insertions(+), 59 deletions(-) diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 68ed9e9520c..c7d9da8521a 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -43,22 +43,68 @@ struct efi_net_obj { struct efi_pxe_mode pxe_mode; }; +/* + * efi_net_start() - start the network interface + * + * This function implements the Start service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * Return: status code + */ static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this) { + efi_status_t ret = EFI_SUCCESS; + EFI_ENTRY("%p", this); - return EFI_EXIT(EFI_SUCCESS); + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + if (this->mode->state != EFI_NETWORK_STOPPED) + ret = EFI_ALREADY_STARTED; + else + this->mode->state = EFI_NETWORK_STARTED; +out: + return EFI_EXIT(ret); } +/* + * efi_net_stop() - stop the network interface + * + * This function implements the Stop service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * Return: status code + */ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) { + efi_status_t ret = EFI_SUCCESS; + EFI_ENTRY("%p", this); - return EFI_EXIT(EFI_SUCCESS); + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + if (this->mode->state == EFI_NETWORK_STOPPED) + ret = EFI_NOT_STARTED; + else + this->mode->state = EFI_NETWORK_STOPPED; +out: + return EFI_EXIT(ret); } /* - * Initialize network adapter and allocate transmit and receive buffers. + * efi_net_initialize() - initialize the network interface * * This function implements the Initialize service of the * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface @@ -67,7 +113,7 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) * @this: pointer to the protocol instance * @extra_rx: extra receive buffer to be allocated * @extra_tx: extra transmit buffer to be allocated - * @return: status code + * Return: status code */ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, ulong extra_rx, ulong extra_tx) @@ -77,9 +123,10 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx); + /* Check parameters */ if (!this) { r = EFI_INVALID_PARAMETER; - goto error; + goto out; } /* Setup packet buffers */ @@ -92,32 +139,83 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, ret = eth_init(); if (ret < 0) { eth_halt(); + this->mode->state = EFI_NETWORK_STOPPED; r = EFI_DEVICE_ERROR; + goto out; + } else { + this->mode->state = EFI_NETWORK_INITIALIZED; } - -error: +out: return EFI_EXIT(r); } +/* + * efi_net_reset() - reinitialize the network interface + * + * This function implements the Reset service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @extended_verification: execute exhaustive verification + * Return: status code + */ static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this, int extended_verification) { EFI_ENTRY("%p, %x", this, extended_verification); - return EFI_EXIT(EFI_SUCCESS); + return EFI_EXIT(EFI_CALL(efi_net_initialize(this, 0, 0))); } +/* + * efi_net_shutdown() - shut down the network interface + * + * This function implements the Shutdown service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * Return: status code + */ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) { + efi_status_t ret = EFI_SUCCESS; + EFI_ENTRY("%p", this); - return EFI_EXIT(EFI_SUCCESS); + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + eth_halt(); + this->mode->state = EFI_NETWORK_STOPPED; + +out: + return EFI_EXIT(ret); } -static efi_status_t EFIAPI efi_net_receive_filters( - struct efi_simple_network *this, u32 enable, u32 disable, - int reset_mcast_filter, ulong mcast_filter_count, - struct efi_mac_address *mcast_filter) +/* + * efi_net_receive_filters() - mange multicast receive filters + * + * This function implements the ReceiveFilters service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @enable: bit mask of receive filters to enable + * @disable: bit mask of receive filters to disable + * @reset_mcast_filter: true resets contents of the filters + * @mcast_filter_count: number of hardware MAC addresses in the new filters list + * @mcast_filter: list of new filters + * Return: status code + */ +static efi_status_t EFIAPI efi_net_receive_filters + (struct efi_simple_network *this, u32 enable, u32 disable, + int reset_mcast_filter, ulong mcast_filter_count, + struct efi_mac_address *mcast_filter) { EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable, reset_mcast_filter, mcast_filter_count, mcast_filter); @@ -125,15 +223,40 @@ static efi_status_t EFIAPI efi_net_receive_filters( return EFI_EXIT(EFI_UNSUPPORTED); } -static efi_status_t EFIAPI efi_net_station_address( - struct efi_simple_network *this, int reset, - struct efi_mac_address *new_mac) +/* + * efi_net_station_address() - set the hardware MAC address + * + * This function implements the StationAddress service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @reset: if true reset the address to default + * @new_mac: new MAC address + * Return: status code + */ +static efi_status_t EFIAPI efi_net_station_address + (struct efi_simple_network *this, int reset, + struct efi_mac_address *new_mac) { EFI_ENTRY("%p, %x, %p", this, reset, new_mac); return EFI_EXIT(EFI_UNSUPPORTED); } +/* + * efi_net_statistics() - reset or collect statistics of the network interface + * + * This function implements the Statistics service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @reset: if true, the statistics are reset + * @stat_size: size of the statistics table + * @stat_table: table to receive the statistics + * Return: status code + */ static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, int reset, ulong *stat_size, void *stat_table) @@ -143,6 +266,19 @@ static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this, return EFI_EXIT(EFI_UNSUPPORTED); } +/* + * efi_net_mcastiptomac() - translate multicast IP address to MAC address + * + * This function implements the Statistics service of the + * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface + * (UEFI) specification for details. + * + * @this: pointer to the protocol instance + * @ipv6: true if the IP address is an IPv6 address + * @ip: IP address + * @mac: MAC address + * Return: status code + */ static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this, int ipv6, struct efi_ip_address *ip, @@ -153,6 +289,19 @@ static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this, return EFI_EXIT(EFI_INVALID_PARAMETER); } +/** + * efi_net_nvdata() - read or write NVRAM + * + * This function implements the GetStatus service of the Simple Network + * Protocol. See the UEFI spec for details. + * + * @this: the instance of the Simple Network Protocol + * @readwrite: true for read, false for write + * @offset: offset in NVRAM + * @buffer_size: size of buffer + * @buffer: buffer + * Return: status code + */ static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this, int read_write, ulong offset, ulong buffer_size, char *buffer) @@ -163,13 +312,42 @@ static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this, return EFI_EXIT(EFI_UNSUPPORTED); } +/** + * efi_net_get_status() - get interrupt status + * + * This function implements the GetStatus service of the Simple Network + * Protocol. See the UEFI spec for details. + * + * @this: the instance of the Simple Network Protocol + * @int_status: interface status + * @txbuf: transmission buffer + */ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, u32 *int_status, void **txbuf) { + efi_status_t ret = EFI_SUCCESS; + EFI_ENTRY("%p, %p, %p", this, int_status, txbuf); efi_timer_check(); + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + switch (this->mode->state) { + case EFI_NETWORK_STOPPED: + ret = EFI_NOT_STARTED; + goto out; + case EFI_NETWORK_STARTED: + ret = EFI_DEVICE_ERROR; + goto out; + default: + break; + } + if (int_status) { /* We send packets synchronously, so nothing is outstanding */ *int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT; @@ -180,63 +358,103 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, *txbuf = new_tx_packet; new_tx_packet = NULL; - - return EFI_EXIT(EFI_SUCCESS); +out: + return EFI_EXIT(ret); } -static efi_status_t EFIAPI efi_net_transmit(struct efi_simple_network *this, - 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_net_transmit() - transmit a packet + * + * This function implements the Transmit 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 hardware MAC address + * @dest_addr: destination hardware MAC address + * @protocol: type of header to build + * Return: status code + */ +static efi_status_t EFIAPI efi_net_transmit + (struct efi_simple_network *this, 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_status_t ret = EFI_SUCCESS; + 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(); + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + /* We do not support jumbo packets */ + if (buffer_size > PKTSIZE_ALIGN) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + if (header_size) { - /* We would need to create the header if header_size != 0 */ - return EFI_EXIT(EFI_INVALID_PARAMETER); + /* + * TODO: We would need to create the header + * if header_size != 0 + */ + ret = EFI_INVALID_PARAMETER; + goto out; + } + + switch (this->mode->state) { + case EFI_NETWORK_STOPPED: + ret = EFI_NOT_STARTED; + goto out; + case EFI_NETWORK_STARTED: + ret = EFI_DEVICE_ERROR; + goto out; + default: + break; } - /* Ensure that the packet fits into the buffer */ - if (buffer_size > PKTSIZE_ALIGN) - return EFI_EXIT(EFI_INVALID_PARAMETER); + /* Ethernet packets always fit, just bounce */ memcpy(transmit_buffer, buffer, buffer_size); net_send_packet(transmit_buffer, buffer_size); new_tx_packet = buffer; - return EFI_EXIT(EFI_SUCCESS); -} - -static void efi_net_push(void *pkt, int len) -{ - new_rx_packet = true; - wait_for_packet->is_signaled = true; +out: + return EFI_EXIT(ret); } -/* - * Receive a packet from a network interface. +/** + * efi_net_receive() - 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 + * @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, - size_t *header_size, size_t *buffer_size, void *buffer, - struct efi_mac_address *src_addr, - struct efi_mac_address *dest_addr, u16 *protocol) +static efi_status_t EFIAPI efi_net_receive + (struct efi_simple_network *this, 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_status_t ret = EFI_SUCCESS; struct ethernet_hdr *eth_hdr; size_t hdr_size = sizeof(struct ethernet_hdr); u16 protlen; @@ -244,14 +462,35 @@ 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); + /* Execute events */ efi_timer_check(); - if (!new_rx_packet) - return EFI_EXIT(EFI_NOT_READY); + /* Check parameters */ + if (!this) { + ret = EFI_INVALID_PARAMETER; + goto out; + } + + switch (this->mode->state) { + case EFI_NETWORK_STOPPED: + ret = EFI_NOT_STARTED; + goto out; + case EFI_NETWORK_STARTED: + ret = EFI_DEVICE_ERROR; + goto out; + default: + break; + } + + if (!new_rx_packet) { + ret = EFI_NOT_READY; + goto out; + } /* 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); + ret = EFI_NOT_READY; + goto out; } /* Fill export parameters */ eth_hdr = (struct ethernet_hdr *)net_rx_packet; @@ -271,16 +510,22 @@ static efi_status_t EFIAPI efi_net_receive(struct efi_simple_network *this, if (*buffer_size < net_rx_packet_len) { /* Packet doesn't fit, try again with bigger buffer */ *buffer_size = net_rx_packet_len; - return EFI_EXIT(EFI_BUFFER_TOO_SMALL); + ret = EFI_BUFFER_TOO_SMALL; + goto out; } /* Copy packet */ memcpy(buffer, net_rx_packet, net_rx_packet_len); *buffer_size = net_rx_packet_len; new_rx_packet = false; - - return EFI_EXIT(EFI_SUCCESS); +out: + return EFI_EXIT(ret); } +/** + * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address + * + * This function is called by dhcp_handler(). + */ void efi_net_set_dhcp_ack(void *pkt, int len) { int maxsize = sizeof(*dhcp_ack); @@ -291,8 +536,22 @@ 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. +/** + * efi_net_push() - callback for received network packet + * + * This function is called when a network packet is received by eth_rx(). + * + * @pkt: network packet + * @len: length + */ +static void efi_net_push(void *pkt, int len) +{ + new_rx_packet = true; + wait_for_packet->is_signaled = true; +} + +/** + * efi_network_timer_notify() - check if a new network packet has been received * * This notification function is called in every timer cycle. * @@ -302,20 +561,34 @@ void efi_net_set_dhcp_ack(void *pkt, int len) static void EFIAPI efi_network_timer_notify(struct efi_event *event, void *context) { + struct efi_simple_network *this = (struct efi_simple_network *)context; + EFI_ENTRY("%p, %p", event, context); + /* + * Some network drivers do not support calling eth_rx() before + * initialization. + */ + if (!this || this->mode->state != EFI_NETWORK_INITIALIZED) + goto out; + if (!new_rx_packet) { push_packet = efi_net_push; eth_rx(); push_packet = NULL; } +out: EFI_EXIT(EFI_SUCCESS); } -/* This gets called from do_bootefi_exec(). */ +/** + * efi_net_register() - register the simple network protocol + * + * This gets called from do_bootefi_exec(). + */ efi_status_t efi_net_register(void) { - struct efi_net_obj *netobj; + struct efi_net_obj *netobj = NULL; efi_status_t r; if (!eth_get_dev()) { @@ -395,7 +668,7 @@ efi_status_t efi_net_register(void) * iPXE is running at TPL_CALLBACK most of the time. Use a higher TPL. */ r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY, - efi_network_timer_notify, NULL, NULL, + efi_network_timer_notify, &netobj->net, NULL, &network_timer_event); if (r != EFI_SUCCESS) { printf("ERROR: Failed to register network event\n"); -- cgit v1.2.3 From 3c2c54ca814aa28624633d7472526e054c344bf3 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 22 Oct 2018 23:15:10 +0200 Subject: efi_selftest: rename setup_ok The variable name setup_ok might suggest a boolean with true indicating OK. Let's avoid the misleading name. %s/setup_ok/setup_status/g Suggested-by: Simon Glass Signed-off-by: Heinrich Schuchardt Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index fc7866365d0..5b01610eca1 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -18,7 +18,7 @@ static const struct efi_boot_services *boottime; static const struct efi_runtime_services *runtime; static efi_handle_t handle; static u16 reset_message[] = L"Selftest completed"; -static int *setup_ok; +static int *setup_status; /* * Exit the boot services. @@ -199,8 +199,8 @@ void efi_st_do_tests(const u16 *testname, unsigned int phase, if (test->phase != phase) continue; if (steps & EFI_ST_SETUP) - setup_ok[i] = setup(test, failures); - if (steps & EFI_ST_EXECUTE && setup_ok[i] == EFI_ST_SUCCESS) + setup_status[i] = setup(test, failures); + if (steps & EFI_ST_EXECUTE && setup_status[i] == EFI_ST_SUCCESS) execute(test, failures); if (steps & EFI_ST_TEARDOWN) teardown(test, failures); @@ -278,7 +278,7 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, ret = boottime->allocate_pool(EFI_RUNTIME_SERVICES_DATA, sizeof(int) * ll_entry_count(struct efi_unit_test, efi_unit_test), - (void **)&setup_ok); + (void **)&setup_status); if (ret != EFI_SUCCESS) { efi_st_error("Allocate pool failed\n"); return ret; -- cgit v1.2.3 From 7a82c3051c8fdc5c6a91db1f50303ad18c36621f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 17 Sep 2018 13:54:33 +0200 Subject: efi_loader: Align runtime section to 64kb The UEFI spec mandates that runtime sections are 64kb aligned to enable support for 64kb page size OSs. This patch ensures that we extend the runtime section to 64kb to be spec compliant. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 5359118b4d7..4bb517473e4 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -11,6 +11,7 @@ #include #include #include +#include DECLARE_GLOBAL_DATA_PTR; @@ -602,6 +603,7 @@ __weak void efi_add_known_memory(void) static void add_u_boot_and_runtime(void) { unsigned long runtime_start, runtime_end, runtime_pages; + unsigned long runtime_mask = EFI_PAGE_MASK; unsigned long uboot_start, uboot_pages; unsigned long uboot_stack_size = 16 * 1024 * 1024; @@ -610,10 +612,22 @@ static void add_u_boot_and_runtime(void) uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT; efi_add_memory_map(uboot_start, uboot_pages, EFI_LOADER_DATA, false); - /* Add Runtime Services */ - runtime_start = (ulong)&__efi_runtime_start & ~EFI_PAGE_MASK; +#if defined(__aarch64__) + /* + * Runtime Services must be 64KiB aligned according to the + * "AArch64 Platforms" section in the UEFI spec (2.7+). + */ + + runtime_mask = SZ_64K - 1; +#endif + + /* + * Add Runtime Services. We mark surrounding boottime code as runtime as + * well to fulfill the runtime alignment constraints but avoid padding. + */ + runtime_start = (ulong)&__efi_runtime_start & ~runtime_mask; runtime_end = (ulong)&__efi_runtime_stop; - runtime_end = (runtime_end + EFI_PAGE_MASK) & ~EFI_PAGE_MASK; + runtime_end = (runtime_end + runtime_mask) & ~runtime_mask; runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT; efi_add_memory_map(runtime_start, runtime_pages, EFI_RUNTIME_SERVICES_CODE, false); -- cgit v1.2.3 From b989648cf45d073674677f04ca2ac8b5f7618513 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 1 Dec 2018 10:07:10 +0100 Subject: doc: README.iscsi: Open-iSCSI configuration Provide settings for Open-iSCSI Reformat headers. h3-headers marked with ^^^ are not recognized in some markup editors. Use the ### notation instead. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- doc/README.iscsi | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/doc/README.iscsi b/doc/README.iscsi index faee6362642..3a12438f909 100644 --- a/doc/README.iscsi +++ b/doc/README.iscsi @@ -1,8 +1,6 @@ -iSCSI booting with U-Boot and iPXE -================================== +# iSCSI booting with U-Boot and iPXE -Motivation ----------- +## Motivation U-Boot has only a reduced set of supported network protocols. The focus for network booting has been on UDP based protocols. A TCP stack and HTTP support @@ -41,8 +39,7 @@ fine grained control of the boot process and can provide a command shell. iPXE can be built as an EFI application (named snp.efi) which can be loaded and run by U-Boot. -Boot sequence -------------- +## Boot sequence U-Boot loads the EFI application iPXE snp.efi using the bootefi command. This application has network access via the simple network protocol offered by @@ -106,19 +103,16 @@ the EFI stub Linux is called as an EFI application:: | | | ~ ~ ~ ~| -Security --------- +## Security The iSCSI protocol is not encrypted. The traffic could be secured using IPsec but neither U-Boot nor iPXE does support this. So we should at least separate the iSCSI traffic from all other network traffic. This can be achieved using a virtual local area network (VLAN). -Configuration -------------- +## Configuration -iPXE -^^^^ +### iPXE For running iPXE on arm64 the bin-arm64-efi/snp.efi build target is needed:: @@ -157,9 +151,20 @@ following into src/config/local/general.h is sufficient for most use cases:: #define DOWNLOAD_PROTO_NFS /* Network File System Protocol */ #define DOWNLOAD_PROTO_FILE /* Local file system access */ -Links ------ +### Open-iSCSI + +When the root file system is on an iSCSI drive you should disable pings and set +the replacement timer to a high value [3]: + + node.conn[0].timeo.noop_out_interval = 0 + node.conn[0].timeo.noop_out_timeout = 0 + node.session.timeo.replacement_timeout = 86400 + +## Links * [1](https://ipxe.org) https://ipxe.org - iPXE open source boot firmware * [2](https://www.gnu.org/software/grub/) https://www.gnu.org/software/grub/ - - GNU GRUB (Grand Unified Bootloader) + GNU GRUB (Grand Unified Bootloader) +* [3](https://github.com/open-iscsi/open-iscsi/blob/master/README) + https://github.com/open-iscsi/open-iscsi/blob/master/README - + Open-iSCSI README -- cgit v1.2.3 From 2419b161cc083c4927c2ee0582ccc93d1d54b3b0 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Mon, 5 Nov 2018 18:06:40 +0900 Subject: efi_loader: allow device == NULL in efi_dp_from_name() This is a preparatory patch for use in efi_serialize_load_option() as a load option's file_path should have both a device path and a file path. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- lib/efi_loader/efi_device_path.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index cdf7c7be8c5..d94982314a3 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -955,7 +955,7 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, char filename[32] = { 0 }; /* dp->str is u16[32] long */ char *s; - if (!device || (path && !file)) + if (path && !file) return EFI_INVALID_PARAMETER; is_net = !strcmp(dev, "Net"); @@ -965,10 +965,12 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, if (part < 0) return EFI_INVALID_PARAMETER; - *device = efi_dp_from_part(desc, part); + if (device) + *device = efi_dp_from_part(desc, part); } else { #ifdef CONFIG_NET - *device = efi_dp_from_eth(); + if (device) + *device = efi_dp_from_eth(); #endif } @@ -985,7 +987,8 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, s = filename; while ((s = strchr(s, '/'))) *s++ = '\\'; - *file = efi_dp_from_file(NULL, 0, filename); + *file = efi_dp_from_file(((!is_net && device) ? desc : NULL), + part, filename); return EFI_SUCCESS; } -- cgit v1.2.3 From 1a82b3413cb577cd52cf8a1dc22dd306e4ce0772 Mon Sep 17 00:00:00 2001 From: AKASHI Takahiro Date: Mon, 5 Nov 2018 18:06:41 +0900 Subject: efi_loader: bootmgr: add load option helper functions In this patch, helper functions for an load option variable (BootXXXX) are added: * efi_deserialize_load_option(): parse a string into load_option data (renamed from parse_load_option and exported) * efi_serialize_load_option(): convert load_option data into a string Those functions will be used to implement efishell command. Signed-off-by: AKASHI Takahiro Signed-off-by: Alexander Graf --- include/efi_loader.h | 23 +++++++++++ lib/efi_loader/efi_bootmgr.c | 93 ++++++++++++++++++++++++++++---------------- 2 files changed, 83 insertions(+), 33 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 3c90515fef1..53f08161ab6 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -518,6 +518,29 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name, efi_guid_t *vendor, u32 attributes, efi_uintn_t data_size, void *data); +/* + * See section 3.1.3 in the v2.7 UEFI spec for more details on + * the layout of EFI_LOAD_OPTION. In short it is: + * + * typedef struct _EFI_LOAD_OPTION { + * UINT32 Attributes; + * UINT16 FilePathListLength; + * // CHAR16 Description[]; <-- variable length, NULL terminated + * // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; + * <-- FilePathListLength bytes + * // UINT8 OptionalData[]; + * } EFI_LOAD_OPTION; + */ +struct efi_load_option { + u32 attributes; + u16 file_path_length; + u16 *label; + struct efi_device_path *file_path; + u8 *optional_data; +}; + +void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data); +unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); void *efi_bootmgr_load(struct efi_device_path **device_path, struct efi_device_path **file_path); diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c index 2aae12e1545..a095df3f540 100644 --- a/lib/efi_loader/efi_bootmgr.c +++ b/lib/efi_loader/efi_bootmgr.c @@ -9,6 +9,7 @@ #include #include #include +#include static const struct efi_boot_services *bs; static const struct efi_runtime_services *rs; @@ -30,42 +31,68 @@ static const struct efi_runtime_services *rs; */ -/* - * See section 3.1.3 in the v2.7 UEFI spec for more details on - * the layout of EFI_LOAD_OPTION. In short it is: - * - * typedef struct _EFI_LOAD_OPTION { - * UINT32 Attributes; - * UINT16 FilePathListLength; - * // CHAR16 Description[]; <-- variable length, NULL terminated - * // EFI_DEVICE_PATH_PROTOCOL FilePathList[]; <-- FilePathListLength bytes - * // UINT8 OptionalData[]; - * } EFI_LOAD_OPTION; - */ -struct load_option { - u32 attributes; - u16 file_path_length; - u16 *label; - struct efi_device_path *file_path; - u8 *optional_data; -}; - -/* parse an EFI_LOAD_OPTION, as described above */ -static void parse_load_option(struct load_option *lo, void *ptr) +/* Parse serialized data and transform it into efi_load_option structure */ +void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data) { - lo->attributes = *(u32 *)ptr; - ptr += sizeof(u32); + lo->attributes = get_unaligned_le32(data); + data += sizeof(u32); + + lo->file_path_length = get_unaligned_le16(data); + data += sizeof(u16); - lo->file_path_length = *(u16 *)ptr; - ptr += sizeof(u16); + /* FIXME */ + lo->label = (u16 *)data; + data += (u16_strlen(lo->label) + 1) * sizeof(u16); - lo->label = ptr; - ptr += (u16_strlen(lo->label) + 1) * 2; + /* FIXME */ + lo->file_path = (struct efi_device_path *)data; + data += lo->file_path_length; - lo->file_path = ptr; - ptr += lo->file_path_length; + lo->optional_data = data; +} - lo->optional_data = ptr; +/* + * Serialize efi_load_option structure into byte stream for BootXXXX. + * Return a size of allocated data. + */ +unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data) +{ + unsigned long label_len, option_len; + unsigned long size; + u8 *p; + + label_len = (u16_strlen(lo->label) + 1) * sizeof(u16); + option_len = strlen((char *)lo->optional_data); + + /* total size */ + size = sizeof(lo->attributes); + size += sizeof(lo->file_path_length); + size += label_len; + size += lo->file_path_length; + size += option_len + 1; + p = malloc(size); + if (!p) + return 0; + + /* copy data */ + *data = p; + memcpy(p, &lo->attributes, sizeof(lo->attributes)); + p += sizeof(lo->attributes); + + memcpy(p, &lo->file_path_length, sizeof(lo->file_path_length)); + p += sizeof(lo->file_path_length); + + memcpy(p, lo->label, label_len); + p += label_len; + + memcpy(p, lo->file_path, lo->file_path_length); + p += lo->file_path_length; + + memcpy(p, lo->optional_data, option_len); + p += option_len; + *(char *)p = '\0'; + + return size; } /* free() the result */ @@ -100,7 +127,7 @@ static void *get_var(u16 *name, const efi_guid_t *vendor, static void *try_load_entry(uint16_t n, struct efi_device_path **device_path, struct efi_device_path **file_path) { - struct load_option lo; + struct efi_load_option lo; u16 varname[] = L"Boot0000"; u16 hexmap[] = L"0123456789ABCDEF"; void *load_option, *image = NULL; @@ -115,7 +142,7 @@ static void *try_load_entry(uint16_t n, struct efi_device_path **device_path, if (!load_option) return NULL; - parse_load_option(&lo, load_option); + efi_deserialize_load_option(&lo, load_option); if (lo.attributes & LOAD_OPTION_ACTIVE) { efi_status_t ret; -- cgit v1.2.3