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(-) (limited to 'lib') 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.3.1 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 (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(+) (limited to 'lib') 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.3.1 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(+) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(+) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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 (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1 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(-) (limited to 'lib') 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.3.1