From f260bd30e8f5651d81665aa68c090b415ef566e7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 15 Jun 2018 06:02:18 +0200 Subject: [PATCH 01/50] efi_selftest: update .gitignore The following generated files should be ignored by git: efi_miniapp_file_image_exit.h efi_miniapp_file_image_return.h *.so files are normally deleted during the build but should be ignored too. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/.gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/efi_selftest/.gitignore b/lib/efi_selftest/.gitignore index c527e46..293a17b 100644 --- a/lib/efi_selftest/.gitignore +++ b/lib/efi_selftest/.gitignore @@ -1,2 +1,4 @@ -efi_miniapp_file_image.h +efi_miniapp_file_image_exit.h +efi_miniapp_file_image_return.h *.efi +*.so From 907ee2945e78c66aaefabaabada4d092fd8e3d58 Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Fri, 15 Jun 2018 23:47:11 +0200 Subject: [PATCH 02/50] ARM: HYP/non-sec: migrate stack The current code that switches into HYP mode doesn't bother to set up a stack for HYP mode. This doesn't work for EFI applications as they expect a usable stack. Fix this by migrating the stack pointer from SP_svc to SP_hyp while in Monitor mode. This restores the stack pointer when we drop into HYP mode. Signed-off-by: Mark Kettenis Signed-off-by: Alexander Graf --- arch/arm/cpu/armv7/nonsec_virt.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/cpu/armv7/nonsec_virt.S b/arch/arm/cpu/armv7/nonsec_virt.S index 56bdba1..1773fae 100644 --- a/arch/arm/cpu/armv7/nonsec_virt.S +++ b/arch/arm/cpu/armv7/nonsec_virt.S @@ -80,6 +80,8 @@ _secure_monitor: #ifdef CONFIG_ARMV7_VIRT orreq r5, r5, #0x100 @ allow HVC instruction moveq r6, #HYP_MODE @ Enter the kernel as HYP + mrseq r3, sp_svc + msreq sp_hyp, r3 @ migrate SP #endif mcr p15, 0, r5, c1, c1, 0 @ write SCR (with NS bit set) From dc500c369486fbe04000fd325c46bb309e4a1827 Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Fri, 15 Jun 2018 23:47:12 +0200 Subject: [PATCH 03/50] efi_loader: ARM: run EFI payloads non-secure If desired (and possible) switch into HYP mode or non-secure SVC mode before calling the entry point of an EFI application. This allows U-Boot to provide a usable PSCI implementation and makes it possible to boot kernels into hypervisor mode using an EFI bootloader. Based on diffs from Heinrich Schuchardt and Alexander Graf. Signed-off-by: Mark Kettenis [agraf: Fix indentation] Signed-off-by: Alexander Graf --- cmd/bootefi.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index cd755b6..c8c2564 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -20,6 +20,11 @@ #include #include +#ifdef CONFIG_ARMV7_NONSEC +#include +#include +#endif + DECLARE_GLOBAL_DATA_PTR; #define OBJ_LIST_NOT_INITIALIZED 1 @@ -194,6 +199,18 @@ static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)( } #endif +#ifdef CONFIG_ARMV7_NONSEC +static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)( + efi_handle_t image_handle, struct efi_system_table *st), + efi_handle_t image_handle, struct efi_system_table *st) +{ + /* Enable caches again */ + dcache_enable(); + + return efi_do_enter(image_handle, st, entry); +} +#endif + /* Carve out DT reserved memory ranges */ static efi_status_t efi_carve_out_dt_rsv(void *fdt) { @@ -350,6 +367,22 @@ static efi_status_t do_bootefi_exec(void *efi, } #endif +#ifdef CONFIG_ARMV7_NONSEC + if (armv7_boot_nonsec()) { + dcache_disable(); /* flush cache before switch to HYP */ + + armv7_init_nonsec(); + secure_ram_addr(_do_nonsec_entry)( + efi_run_in_hyp, + (uintptr_t)entry, + (uintptr_t)loaded_image_info_obj.handle, + (uintptr_t)&systab); + + /* Should never reach here, efi exits with longjmp */ + while (1) { } + } +#endif + ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry); exit: From f17f2001ebe1e8a78e0ef0f99e63134f91ee1354 Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Fri, 15 Jun 2018 23:47:13 +0200 Subject: [PATCH 04/50] efi_loader: ARM: don't attempt to enter non-secure mode twice Multiple EFI binaries may be executed in sequence. So if we already are in non-secure mode after running the first one we should skip the switching code since it no longer works once we're non-secure. Signed-off-by: Mark Kettenis Signed-off-by: Alexander Graf --- cmd/bootefi.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index c8c2564..bbfea91 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -200,6 +200,8 @@ static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)( #endif #ifdef CONFIG_ARMV7_NONSEC +static bool is_nonsec; + static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)( efi_handle_t image_handle, struct efi_system_table *st), efi_handle_t image_handle, struct efi_system_table *st) @@ -207,6 +209,8 @@ static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)( /* Enable caches again */ dcache_enable(); + is_nonsec = true; + return efi_do_enter(image_handle, st, entry); } #endif @@ -368,7 +372,7 @@ static efi_status_t do_bootefi_exec(void *efi, #endif #ifdef CONFIG_ARMV7_NONSEC - if (armv7_boot_nonsec()) { + if (armv7_boot_nonsec() && !is_nonsec) { dcache_disable(); /* flush cache before switch to HYP */ armv7_init_nonsec(); From d32e86bde8a31a49cf4a9b233ad91ecdfc96ba2a Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Fri, 15 Jun 2018 23:47:14 +0200 Subject: [PATCH 05/50] ARM: HYP/non-sec: enable ARMV7_LPAE if HYP mode is supported ARMV7_LPAE is required in order to enable the MMU in HYP mode. And we really want to enable the MMU in HYP mode such that we can enable the the caches. Otherwise U-Boot code (such as the EFI implementation) that runs in HYP mode will run at a snils pace. Signed-off-by: Mark Kettenis Signed-off-by: Alexander Graf --- arch/arm/cpu/armv7/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv7/Kconfig b/arch/arm/cpu/armv7/Kconfig index 37a0be9..73d57a2 100644 --- a/arch/arm/cpu/armv7/Kconfig +++ b/arch/arm/cpu/armv7/Kconfig @@ -53,7 +53,7 @@ config ARMV7_PSCI_NR_CPUS config ARMV7_LPAE bool "Use LPAE page table format" if EXPERT depends on CPU_V7A - default n + default y if ARMV7_VIRT ---help--- Say Y here to use the long descriptor page table format. This is required if U-Boot runs in HYP mode. From c726913a98dfefca013d061aee0d88b27606c77c Mon Sep 17 00:00:00 2001 From: Mark Kettenis Date: Fri, 15 Jun 2018 23:47:15 +0200 Subject: [PATCH 06/50] Revert "efi_loader: no support for ARMV7_NONSEC=y" This reverts commit c524997acb3d322e1bbd36c06ad02ef589705e7c. Booting ARMv7 in non-secure mode using bootefi works now. Signed-off-by: Mark Kettenis Signed-off-by: Alexander Graf --- doc/README.uefi | 2 -- lib/efi_loader/Kconfig | 2 -- 2 files changed, 4 deletions(-) diff --git a/doc/README.uefi b/doc/README.uefi index d4031ef..6b9759c 100644 --- a/doc/README.uefi +++ b/doc/README.uefi @@ -329,8 +329,6 @@ This driver is only available if U-Boot is configured with * persistence * runtime support -* support bootefi booting ARMv7 in non-secure mode (CONFIG_ARMV7_NONSEC=y) - ## Links * [1](http://uefi.org/specifications) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index df58e63..ce6a09f 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -1,8 +1,6 @@ config EFI_LOADER bool "Support running EFI Applications in U-Boot" depends on (ARM || X86 || RISCV) && OF_LIBFDT - # We do not support bootefi booting ARMv7 in non-secure mode - depends on !ARMV7_NONSEC # We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT # We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB From b59f69712b6af5e2b95e154a873f59948a754cc9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:22:57 +0200 Subject: [PATCH 07/50] efi_loader: Use compiler constants for image loader The EFI image loader tries to determine which target architecture we're working with to only load PE binaries that match. So far this has worked based on CONFIG defines, because the target CPU was always indicated by a config define. With sandbox however, this is not longer true as all sandbox targets only encompass a single CONFIG option and so we need to use compiler defines to determine the CPU architecture. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_image_loader.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index ecdb77e..fdf40a6 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -19,25 +19,25 @@ const efi_guid_t efi_simple_file_system_protocol_guid = const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID; static int machines[] = { -#if defined(CONFIG_ARM64) +#if defined(__aarch64__) IMAGE_FILE_MACHINE_ARM64, -#elif defined(CONFIG_ARM) +#elif defined(__arm__) IMAGE_FILE_MACHINE_ARM, IMAGE_FILE_MACHINE_THUMB, IMAGE_FILE_MACHINE_ARMNT, #endif -#if defined(CONFIG_X86_64) +#if defined(__x86_64__) IMAGE_FILE_MACHINE_AMD64, -#elif defined(CONFIG_X86) +#elif defined(__i386__) IMAGE_FILE_MACHINE_I386, #endif -#if defined(CONFIG_CPU_RISCV_32) +#if defined(__riscv) && (__riscv_xlen == 32) IMAGE_FILE_MACHINE_RISCV32, #endif -#if defined(CONFIG_CPU_RISCV_64) +#if defined(__riscv) && (__riscv_xlen == 64) IMAGE_FILE_MACHINE_RISCV64, #endif 0 }; From 354264b31d3c536ce0c4d3ac87acfd3fa7ac808a Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:22:58 +0200 Subject: [PATCH 08/50] efi_loader: Use map_sysmem() in bootefi command The bootefi command gets a few addresses as values passed in. In sandbox, these values are in U-Boot address space, so we need to make sure we explicitly call map_sysmem() on them to be able to access them. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index bbfea91..a0fd1a3 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -431,7 +432,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) unsigned long addr; char *saddr; efi_status_t r; - void *fdt_addr; + unsigned long fdt_addr; + void *fdt; /* Allow unaligned memory access */ allow_unaligned(); @@ -448,11 +450,12 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return CMD_RET_USAGE; if (argc > 2) { - fdt_addr = (void *)simple_strtoul(argv[2], NULL, 16); + fdt_addr = simple_strtoul(argv[2], NULL, 16); if (!fdt_addr && *argv[2] != '0') return CMD_RET_USAGE; /* Install device tree */ - r = efi_install_fdt(fdt_addr); + fdt = map_sysmem(fdt_addr, 0); + r = efi_install_fdt(fdt); if (r != EFI_SUCCESS) { printf("ERROR: failed to install device tree\n"); return CMD_RET_FAILURE; @@ -471,7 +474,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) addr = simple_strtoul(saddr, NULL, 16); else addr = CONFIG_SYS_LOAD_ADDR; - memcpy((char *)addr, __efi_helloworld_begin, size); + memcpy(map_sysmem(addr, size), __efi_helloworld_begin, size); } else #endif #ifdef CONFIG_CMD_BOOTEFI_SELFTEST @@ -517,7 +520,7 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } printf("## Starting EFI application at %08lx ...\n", addr); - r = do_bootefi_exec((void *)addr, bootefi_device_path, + r = do_bootefi_exec(map_sysmem(addr, 0), bootefi_device_path, bootefi_image_path); printf("## Application terminated, r = %lu\n", r & ~EFI_ERROR_MASK); From 62f375787084b1835967bc4d735bc245096b99fc Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:23:00 +0200 Subject: [PATCH 09/50] efi_loader: Allow SMBIOS tables in highmem We try hard to make sure that SMBIOS tables live in the lower 32bit. However, when we can not find any space at all there, we should not error out but instead just fall back to map them in the full address space instead. This can for example happen on systems that do not have any RAM mapped in the lower 32bits of address space. In that case having any SMBIOS tables at all is better than having none. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_smbios.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/efi_loader/efi_smbios.c b/lib/efi_loader/efi_smbios.c index 7c3fc8a..932f758 100644 --- a/lib/efi_loader/efi_smbios.c +++ b/lib/efi_loader/efi_smbios.c @@ -26,8 +26,15 @@ efi_status_t efi_smbios_register(void) /* Reserve 4kiB page for SMBIOS */ ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS, EFI_RUNTIME_SERVICES_DATA, 1, &dmi); - if (ret != EFI_SUCCESS) - return ret; + + 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); + + if (ret != EFI_SUCCESS) + return ret; + } /* * Generate SMBIOS tables - we know that efi_allocate_pages() returns From aa909462d01866354f4cd4534db5f571c2cf1fbb Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 18 Jun 2018 17:23:02 +0200 Subject: [PATCH 10/50] efi_loader: efi_allocate_pages is too restrictive When running on the sandbox the stack is not necessarily at a higher memory address than the highest free memory. There is no reason why the checking of the highest memory address should be more restrictive for EFI_ALLOCATE_ANY_PAGES than for EFI_ALLOCATE_MAX_ADDRESS. Signed-off-by: Heinrich Schuchardt [agraf: use -1ULL instead] Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ec66af9..ce29bcc 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -295,7 +295,7 @@ efi_status_t efi_allocate_pages(int type, int memory_type, switch (type) { case EFI_ALLOCATE_ANY_PAGES: /* Any page */ - addr = efi_find_free_memory(len, gd->start_addr_sp); + addr = efi_find_free_memory(len, -1ULL); if (!addr) { r = EFI_NOT_FOUND; break; From c034bfab2975f4a02ef20f0e88ac82a451696f79 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:23:03 +0200 Subject: [PATCH 11/50] efi_loader: Disable miniapps on sandbox In the sandbox environment we can not easily build efi stub binaries right now, so let's disable the respective test cases for the efi selftest suite. Signed-off-by: Alexander Graf Reviewed-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 4fe404d..bf5c819 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -41,7 +41,7 @@ endif # TODO: As of v2018.01 the relocation code for the EFI application cannot # be built on x86_64. -ifeq ($(CONFIG_X86_64),) +ifeq ($(CONFIG_X86_64)$(CONFIG_SANDBOX),) ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST),) From beb077a2a8201c4b215d82e58c4d1d8ec8e48b58 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:23:05 +0200 Subject: [PATCH 12/50] efi_loader: Introduce ms abi vararg helpers Varargs differ between sysv and ms abi. On x86_64 we have to follow the ms abi though, so we also need to make sure we use x86_64 varargs helpers. This patch introduces generic efi vararg helpers that adhere to the respective EFI ABI. That way we can deal with them properly from efi loader code and properly interpret variable arguments. This fixes the InstallMultipleProtocolInterfaces tests in the efi selftests on x86_64 for me. Signed-off-by: Alexander Graf --- include/efi.h | 8 ++++++++ lib/efi_loader/efi_boottime.c | 36 ++++++++++++++++++------------------ 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/efi.h b/include/efi.h index 0fe15e6..41530a7 100644 --- a/include/efi.h +++ b/include/efi.h @@ -29,8 +29,16 @@ */ #ifdef __x86_64__ #define EFIAPI __attribute__((ms_abi)) +#define efi_va_list __builtin_ms_va_list +#define efi_va_start __builtin_ms_va_start +#define efi_va_arg __builtin_va_arg +#define efi_va_end __builtin_ms_va_end #else #define EFIAPI asmlinkage +#define efi_va_list va_list +#define efi_va_start va_start +#define efi_va_arg va_arg +#define efi_va_end va_end #endif /* __x86_64__ */ struct efi_device_path; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index eeefe0b..46c8ecd 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2302,7 +2302,7 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( { EFI_ENTRY("%p", handle); - va_list argptr; + efi_va_list argptr; const efi_guid_t *protocol; void *protocol_interface; efi_status_t r = EFI_SUCCESS; @@ -2311,12 +2311,12 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( if (!handle) return EFI_EXIT(EFI_INVALID_PARAMETER); - va_start(argptr, handle); + efi_va_start(argptr, handle); for (;;) { - protocol = va_arg(argptr, efi_guid_t*); + protocol = efi_va_arg(argptr, efi_guid_t*); if (!protocol) break; - protocol_interface = va_arg(argptr, void*); + protocol_interface = efi_va_arg(argptr, void*); r = EFI_CALL(efi_install_protocol_interface( handle, protocol, EFI_NATIVE_INTERFACE, @@ -2325,19 +2325,19 @@ static efi_status_t EFIAPI efi_install_multiple_protocol_interfaces( break; i++; } - va_end(argptr); + efi_va_end(argptr); if (r == EFI_SUCCESS) return EFI_EXIT(r); /* If an error occurred undo all changes. */ - va_start(argptr, handle); + efi_va_start(argptr, handle); for (; i; --i) { - protocol = va_arg(argptr, efi_guid_t*); - protocol_interface = va_arg(argptr, void*); + protocol = efi_va_arg(argptr, efi_guid_t*); + protocol_interface = efi_va_arg(argptr, void*); EFI_CALL(efi_uninstall_protocol_interface(handle, protocol, protocol_interface)); } - va_end(argptr); + efi_va_end(argptr); return EFI_EXIT(r); } @@ -2361,7 +2361,7 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( { EFI_ENTRY("%p", handle); - va_list argptr; + efi_va_list argptr; const efi_guid_t *protocol; void *protocol_interface; efi_status_t r = EFI_SUCCESS; @@ -2370,12 +2370,12 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( if (!handle) return EFI_EXIT(EFI_INVALID_PARAMETER); - va_start(argptr, handle); + efi_va_start(argptr, handle); for (;;) { - protocol = va_arg(argptr, efi_guid_t*); + protocol = efi_va_arg(argptr, efi_guid_t*); if (!protocol) break; - protocol_interface = va_arg(argptr, void*); + protocol_interface = efi_va_arg(argptr, void*); r = EFI_CALL(efi_uninstall_protocol_interface( handle, protocol, protocol_interface)); @@ -2383,20 +2383,20 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( break; i++; } - va_end(argptr); + efi_va_end(argptr); if (r == EFI_SUCCESS) return EFI_EXIT(r); /* If an error occurred undo all changes. */ - va_start(argptr, handle); + efi_va_start(argptr, handle); for (; i; --i) { - protocol = va_arg(argptr, efi_guid_t*); - protocol_interface = va_arg(argptr, void*); + protocol = efi_va_arg(argptr, efi_guid_t*); + protocol_interface = efi_va_arg(argptr, void*); EFI_CALL(efi_install_protocol_interface(&handle, protocol, EFI_NATIVE_INTERFACE, protocol_interface)); } - va_end(argptr); + efi_va_end(argptr); return EFI_EXIT(r); } From bc028919e4e3c1e69437ba0d93751ff099f6c6c9 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:23:08 +0200 Subject: [PATCH 13/50] efi_loader: Move to compiler based target architecture determination Thanks to CONFIG_SANDBOX, we can not rely on config options to tell us what CPU architecture we're running on. The compiler however does know that, so let's just move the ifdefs over to compiler based defines rather than kconfig based options. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 4874eb6..bc44e43 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -32,18 +32,18 @@ static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void); * TODO(sjg@chromium.org): These defines and structs should come from the elf * header for each arch (or a generic header) rather than being repeated here. */ -#if defined(CONFIG_ARM64) +#if defined(__aarch64__) #define R_RELATIVE 1027 #define R_MASK 0xffffffffULL #define IS_RELA 1 -#elif defined(CONFIG_ARM) +#elif defined(__arm__) #define R_RELATIVE 23 #define R_MASK 0xffULL -#elif defined(CONFIG_X86) +#elif defined(__x86_64__) || defined(__i386__) #include #define R_RELATIVE R_386_RELATIVE #define R_MASK 0xffULL -#elif defined(CONFIG_RISCV) +#elif defined(__riscv) #include #define R_RELATIVE R_RISCV_RELATIVE #define R_MASK 0xffULL @@ -55,12 +55,14 @@ struct dyn_sym { u32 foo2; u32 foo3; }; -#ifdef CONFIG_CPU_RISCV_32 +#if (__riscv_xlen == 32) #define R_ABSOLUTE R_RISCV_32 #define SYM_INDEX 8 -#else +#elif (__riscv_xlen == 64) #define R_ABSOLUTE R_RISCV_64 #define SYM_INDEX 32 +#else +#error unknown riscv target #endif #else #error Need to add relocation awareness From dae73c4cdc862017a10d09588571e7f98de0cdd4 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:23:10 +0200 Subject: [PATCH 14/50] elf: Move x86 reloc defines to common elf.h We need to know about x86 relocation definitions even in cases where we don't officially build against the x86 target, such as with sandbox. So let's move the x86 definitions into the common elf header, where all other architectures already have them. Signed-off-by: Alexander Graf --- arch/x86/include/asm/elf.h | 45 ----------------------------------------- arch/x86/lib/reloc_ia32_efi.c | 1 - arch/x86/lib/reloc_x86_64_efi.c | 1 - include/elf.h | 35 ++++++++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 47 deletions(-) delete mode 100644 arch/x86/include/asm/elf.h diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h deleted file mode 100644 index 7ae9c7d..0000000 --- a/arch/x86/include/asm/elf.h +++ /dev/null @@ -1,45 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Brought in from Linux 4.1, removed things not useful to U-Boot. - * The definitions perhaps came from the GNU Library which is GPL. - */ - -#ifndef _ASM_X86_ELF_H -#define _ASM_X86_ELF_H - -/* ELF register definitions */ -#define R_386_NONE 0 -#define R_386_32 1 -#define R_386_PC32 2 -#define R_386_GOT32 3 -#define R_386_PLT32 4 -#define R_386_COPY 5 -#define R_386_GLOB_DAT 6 -#define R_386_JMP_SLOT 7 -#define R_386_RELATIVE 8 -#define R_386_GOTOFF 9 -#define R_386_GOTPC 10 -#define R_386_NUM 11 - -/* x86-64 relocation types */ -#define R_X86_64_NONE 0 /* No reloc */ -#define R_X86_64_64 1 /* Direct 64 bit */ -#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ -#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ -#define R_X86_64_PLT32 4 /* 32 bit PLT address */ -#define R_X86_64_COPY 5 /* Copy symbol at runtime */ -#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ -#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ -#define R_X86_64_RELATIVE 8 /* Adjust by program base */ -/* 32 bit signed pc relative offset to GOT */ -#define R_X86_64_GOTPCREL 9 -#define R_X86_64_32 10 /* Direct 32 bit zero extended */ -#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ -#define R_X86_64_16 12 /* Direct 16 bit zero extended */ -#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ -#define R_X86_64_8 14 /* Direct 8 bit sign extended */ -#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ - -#define R_X86_64_NUM 16 - -#endif diff --git a/arch/x86/lib/reloc_ia32_efi.c b/arch/x86/lib/reloc_ia32_efi.c index a262533..d56cd50 100644 --- a/arch/x86/lib/reloc_ia32_efi.c +++ b/arch/x86/lib/reloc_ia32_efi.c @@ -10,7 +10,6 @@ #include #include #include -#include efi_status_t EFIAPI _relocate(long ldbase, Elf32_Dyn *dyn) { diff --git a/arch/x86/lib/reloc_x86_64_efi.c b/arch/x86/lib/reloc_x86_64_efi.c index 59d6f8d..2694de7 100644 --- a/arch/x86/lib/reloc_x86_64_efi.c +++ b/arch/x86/lib/reloc_x86_64_efi.c @@ -12,7 +12,6 @@ #include #include #include -#include efi_status_t EFIAPI _relocate(long ldbase, Elf64_Dyn *dyn) { diff --git a/include/elf.h b/include/elf.h index 0d3845e..6802428 100644 --- a/include/elf.h +++ b/include/elf.h @@ -550,6 +550,41 @@ unsigned long elf_hash(const unsigned char *name); #endif /* __ASSEMBLER */ +/* ELF register definitions */ +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +/* x86-64 relocation types */ +#define R_X86_64_NONE 0 /* No reloc */ +#define R_X86_64_64 1 /* Direct 64 bit */ +#define R_X86_64_PC32 2 /* PC relative 32 bit signed */ +#define R_X86_64_GOT32 3 /* 32 bit GOT entry */ +#define R_X86_64_PLT32 4 /* 32 bit PLT address */ +#define R_X86_64_COPY 5 /* Copy symbol at runtime */ +#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */ +#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */ +#define R_X86_64_RELATIVE 8 /* Adjust by program base */ +/* 32 bit signed pc relative offset to GOT */ +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 /* Direct 32 bit zero extended */ +#define R_X86_64_32S 11 /* Direct 32 bit sign extended */ +#define R_X86_64_16 12 /* Direct 16 bit zero extended */ +#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */ +#define R_X86_64_8 14 /* Direct 8 bit sign extended */ +#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */ + +#define R_X86_64_NUM 16 + /* * XXX - PowerPC defines really don't belong in here, * but we'll put them in for simplicity. From b34662d03bb9e695d12bf995df4bec8998f91609 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:23:11 +0200 Subject: [PATCH 15/50] efi_loader: Use common elf.h reloc defines Now that elf.h contains relocation defines for all architectures we care about, let's just include it unconditionally and refer to the defines. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index bc44e43..dd3ff8a 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -33,18 +34,16 @@ static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void); * header for each arch (or a generic header) rather than being repeated here. */ #if defined(__aarch64__) -#define R_RELATIVE 1027 +#define R_RELATIVE R_AARCH64_RELATIVE #define R_MASK 0xffffffffULL #define IS_RELA 1 #elif defined(__arm__) -#define R_RELATIVE 23 +#define R_RELATIVE R_ARM_RELATIVE #define R_MASK 0xffULL #elif defined(__x86_64__) || defined(__i386__) -#include #define R_RELATIVE R_386_RELATIVE #define R_MASK 0xffULL #elif defined(__riscv) -#include #define R_RELATIVE R_RISCV_RELATIVE #define R_MASK 0xffULL #define IS_RELA 1 From 69259b83670661ad530442e1ebb788e96a7676cb Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 18 Jun 2018 17:23:12 +0200 Subject: [PATCH 16/50] efi: sandbox: Adjust memory usage for sandbox With sandbox the U-Boot code is not mapped into the sandbox memory range so does not need to be excluded when allocating EFI memory. Update the EFI memory init code to take account of that. Signed-off-by: Simon Glass [agraf: Remove map_sysmem() call and header reference] Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index ce29bcc..d533aee 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -496,14 +496,13 @@ __weak void efi_add_known_memory(void) } } -int efi_memory_init(void) +/* Add memory regions for U-Boot's memory and for the runtime services code */ +static void add_u_boot_and_runtime(void) { unsigned long runtime_start, runtime_end, runtime_pages; unsigned long uboot_start, uboot_pages; unsigned long uboot_stack_size = 16 * 1024 * 1024; - efi_add_known_memory(); - /* Add U-Boot */ uboot_start = (gd->start_addr_sp - uboot_stack_size) & ~EFI_PAGE_MASK; uboot_pages = (gd->ram_top - uboot_start) >> EFI_PAGE_SHIFT; @@ -516,6 +515,14 @@ int efi_memory_init(void) runtime_pages = (runtime_end - runtime_start) >> EFI_PAGE_SHIFT; efi_add_memory_map(runtime_start, runtime_pages, EFI_RUNTIME_SERVICES_CODE, false); +} + +int efi_memory_init(void) +{ + efi_add_known_memory(); + + if (!IS_ENABLED(CONFIG_SANDBOX)) + add_u_boot_and_runtime(); #ifdef CONFIG_EFI_LOADER_BOUNCE_BUFFER /* Request a 32bit 64MB bounce buffer region */ From 282a06cbcae84acd86125210dbd54a10ff41e809 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Mon, 18 Jun 2018 17:23:15 +0200 Subject: [PATCH 17/50] efi_loader: Expose U-Boot addresses in memory map for sandbox We currently expose host addresses in the EFI memory map. That can be bad if we ever want to use sandbox to boot strap a real kernel, because then the kernel would fetch its memory table from our host virtual address map. But to make that use case work, we would need to have full control over the address space the EFI application sees. So let's expose only U-Boot addresses to the guest until we get to the point of allocation. EFI's allocation functions are fun - they can take U-Boot addresses as input values for hints and return host addresses as allocation results through the same uint64_t * parameter. So we need to be extra careful on what to pass in when. With this patch I am successfully able to run the efi selftest suite as well as grub.efi on aarch64. Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index d533aee..86edfc9 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -325,7 +326,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 = addr; + *memory = (uintptr_t)map_sysmem(addr, len); } else { /* Map would overlap, bail out */ r = EFI_OUT_OF_RESOURCES; @@ -359,11 +360,12 @@ 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(memory, pages, EFI_CONVENTIONAL_MEMORY, false); + r = efi_add_memory_map(addr, pages, EFI_CONVENTIONAL_MEMORY, false); /* Merging of adjacent free regions is missing */ - if (r == memory) + if (r == addr) return EFI_SUCCESS; return EFI_NOT_FOUND; @@ -380,7 +382,7 @@ efi_status_t efi_free_pages(uint64_t memory, efi_uintn_t pages) efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) { efi_status_t r; - efi_physical_addr_t t; + struct efi_pool_allocation *alloc; u64 num_pages = (size + sizeof(struct efi_pool_allocation) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; @@ -390,10 +392,9 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) } r = efi_allocate_pages(EFI_ALLOCATE_ANY_PAGES, pool_type, num_pages, - &t); + (uint64_t *)&alloc); if (r == EFI_SUCCESS) { - struct efi_pool_allocation *alloc = (void *)(uintptr_t)t; alloc->num_pages = num_pages; *buffer = alloc->data; } From d7ae1609a9d5a76235978e34de0e9928979af781 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 18 Jun 2018 08:08:20 -0600 Subject: [PATCH 18/50] vsprintf: Handle NULL with %pU At present a NULL pointer passed to printf for a %pU argument will cause U-Boot to access memory at 0. Fix this by adding a check, and print "(null)" instead. Signed-off-by: Simon Glass Reviewed-by: Alexander Graf [agraf: s/(null)//] Signed-off-by: Alexander Graf --- lib/vsprintf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 8b1b29f..914fbd3 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -407,7 +407,10 @@ static char *uuid_string(char *buf, char *end, u8 *addr, int field_width, break; } - uuid_bin_to_str(addr, uuid, str_format); + if (addr) + uuid_bin_to_str(addr, uuid, str_format); + else + strcpy(uuid, ""); return string(buf, end, uuid, field_width, precision, flags); } From 404ea59364f1355afcd845a7405599fdc2303231 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 18 Jun 2018 08:08:21 -0600 Subject: [PATCH 19/50] efi_selftest: Clean up a few comments and messages Fix the 'amp' typo, expand on what 'steps' is and fix a few other minor things. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/efi_selftest/efi_selftest.c b/lib/efi_selftest/efi_selftest.c index 13eb2cd..dd338db 100644 --- a/lib/efi_selftest/efi_selftest.c +++ b/lib/efi_selftest/efi_selftest.c @@ -8,9 +8,7 @@ #include #include -/* - * Constants for test step bitmap - */ +/* Constants for test step bitmap */ #define EFI_ST_SETUP 1 #define EFI_ST_EXECUTE 2 #define EFI_ST_TEARDOWN 4 @@ -26,7 +24,7 @@ static u16 reset_message[] = L"Selftest completed"; * * The size of the memory map is determined. * Pool memory is allocated to copy the memory map. - * The memory amp is copied and the map key is obtained. + * The memory map is copied and the map key is obtained. * The map key is used to exit the boot services. */ void efi_st_exit_boot_services(void) @@ -146,7 +144,7 @@ static int teardown(struct efi_unit_test *test, unsigned int *failures) * Check that a test exists. * * @testname: name of the test - * @return: test + * @return: test, or NULL if not found */ static struct efi_unit_test *find_test(const u16 *testname) { @@ -182,7 +180,7 @@ static void list_all_tests(void) * * @testname name of a single selected test or NULL * @phase test phase - * @steps steps to execute + * @steps steps to execute (mask with bits from EFI_ST_...) * failures returns EFI_ST_SUCCESS if all test steps succeeded */ void efi_st_do_tests(const u16 *testname, unsigned int phase, @@ -296,12 +294,12 @@ efi_status_t EFIAPI efi_selftest(efi_handle_t image_handle, efi_st_printc(EFI_WHITE, "\nSummary: %u failures\n\n", failures); /* Reset system */ - efi_st_printf("Preparing for reset. Press any key.\n"); + efi_st_printf("Preparing for reset. Press any key...\n"); efi_st_get_key(); runtime->reset_system(EFI_RESET_WARM, EFI_NOT_READY, sizeof(reset_message), reset_message); efi_st_printf("\n"); - efi_st_error("Reset failed.\n"); + efi_st_error("Reset failed\n"); return EFI_UNSUPPORTED; } From bc9a638a1031a171f0b2dfa4438aa3903fa589ae Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 18 Jun 2018 08:08:25 -0600 Subject: [PATCH 20/50] efi: Tidy up device-tree-size calculation in copy_fdt() This is a bit confusing at present since it adds 4KB to the pointer, then rounds it up. It looks like a bug, but is not. Move the 4KB addition into a separate statement and expand the comment. Signed-off-by: Simon Glass Signed-off-by: Alexander Graf --- cmd/bootefi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index a0fd1a3..d0f2c03 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -148,8 +148,12 @@ static void *copy_fdt(void *fdt) fdt_ram_start = ram_start; } - /* Give us at least 4kb breathing room */ - fdt_size = ALIGN(fdt_size + 4096, EFI_PAGE_SIZE); + /* + * 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. + */ + fdt_size += 4096; + fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE); fdt_pages = fdt_size >> EFI_PAGE_SHIFT; /* Safe fdt location is at 128MB */ From 416e07e2cfcfc18e36c9c83ed3ba52c910bf767d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 18 Jun 2018 08:08:28 -0600 Subject: [PATCH 21/50] efi: Drop error return in efi_carve_out_dt_rsv() This function currently returns an error code, but never uses it. There is no function comment so it is not obvious why. Presuambly the error is not important. Update the function to explain its purpose and why it ignores the error. Drop the useful error return value. Signed-off-by: Simon Glass Reviewed-by: Alexander Graf Signed-off-by: Alexander Graf --- cmd/bootefi.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index d0f2c03..4097277 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -220,8 +220,16 @@ static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)( } #endif -/* Carve out DT reserved memory ranges */ -static efi_status_t efi_carve_out_dt_rsv(void *fdt) +/* + * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges + * + * The mem_rsv entries of the FDT are added to the memory map. Any failures are + * ignored because this is not critical and we would rather continue to try to + * boot. + * + * @fdt: Pointer to device tree + */ +static void efi_carve_out_dt_rsv(void *fdt) { int nr_rsv, i; uint64_t addr, size, pages; @@ -234,11 +242,10 @@ static efi_status_t efi_carve_out_dt_rsv(void *fdt) continue; pages = ALIGN(size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT; - efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, - false); + if (!efi_add_memory_map(addr, pages, EFI_RESERVED_MEMORY_TYPE, + false)) + printf("FDT memrsv map %d: Failed to add to map\n", i); } - - return EFI_SUCCESS; } static efi_status_t efi_install_fdt(void *fdt) @@ -262,10 +269,7 @@ static efi_status_t efi_install_fdt(void *fdt) return EFI_LOAD_ERROR; } - if (efi_carve_out_dt_rsv(fdt) != EFI_SUCCESS) { - printf("ERROR: failed to carve out memory\n"); - return EFI_LOAD_ERROR; - } + efi_carve_out_dt_rsv(fdt); /* Link to it in the efi tables */ ret = efi_install_configuration_table(&efi_guid_fdt, fdt); From 7e21fbca26d18327cf7cabaad08df276a06a07d8 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 12 Jun 2018 07:48:37 +0200 Subject: [PATCH 22/50] efi_loader: Rename sections to allow for implicit data Some times gcc may generate data that is then used within code that may be part of an efi runtime section. That data could be jump tables, constants or strings. In order to make sure we catch these, we need to ensure that gcc emits them into a section that we can relocate together with all the other efi runtime bits. This only works if the -ffunction-sections and -fdata-sections flags are passed and the efi runtime functions are in a section that starts with ".text". Up to now we had all efi runtime bits in sections that did not interfere with the normal section naming scheme, but this forces us to do so. Hence we need to move the efi_loader text/data/rodata sections before the global *(.text*) catch-all section. With this patch in place, we should hopefully have an easier time to extend the efi runtime functionality in the future. Signed-off-by: Alexander Graf [agraf: Fix x86_64 breakage] --- arch/arm/config.mk | 4 ++-- arch/arm/cpu/armv8/u-boot.lds | 24 +++++++++++++-------- arch/arm/cpu/u-boot.lds | 36 ++++++++++++++++++------------- arch/arm/mach-zynq/u-boot.lds | 36 ++++++++++++++++++------------- arch/riscv/cpu/ax25/u-boot.lds | 26 +++++++++++++--------- arch/sandbox/config.mk | 3 +++ arch/sandbox/cpu/u-boot.lds | 9 ++++---- arch/x86/config.mk | 2 ++ arch/x86/cpu/start.S | 2 +- arch/x86/cpu/start64.S | 2 +- arch/x86/cpu/u-boot-64.lds | 3 +++ arch/x86/cpu/u-boot.lds | 34 ++++++++++++++++------------- board/qualcomm/dragonboard410c/u-boot.lds | 17 +++++++++++++-- board/qualcomm/dragonboard820c/u-boot.lds | 24 +++++++++++++-------- board/ti/am335x/u-boot.lds | 36 ++++++++++++++++++------------- include/efi_loader.h | 4 ++-- 16 files changed, 162 insertions(+), 100 deletions(-) diff --git a/arch/arm/config.mk b/arch/arm/config.mk index efafc69..f256031 100644 --- a/arch/arm/config.mk +++ b/arch/arm/config.mk @@ -134,11 +134,11 @@ endif ifdef CONFIG_ARM64 OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .data \ -j .u_boot_list -j .rela.dyn -j .got -j .got.plt \ - -j .binman_sym_table + -j .binman_sym_table -j .text_rest else OBJCOPYFLAGS += -j .text -j .secure_text -j .secure_data -j .rodata -j .hash \ -j .data -j .got -j .got.plt -j .u_boot_list -j .rel.dyn \ - -j .binman_sym_table + -j .binman_sym_table -j .text_rest endif # if a dtb section exists we always have to include it diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds index eb926b3..53de80f 100644 --- a/arch/arm/cpu/armv8/u-boot.lds +++ b/arch/arm/cpu/armv8/u-boot.lds @@ -25,6 +25,19 @@ SECTIONS { *(.__image_copy_start) CPUDIR/start.o (.text*) + } + + /* This needs to come before *(.text*) */ + .efi_runtime : { + __efi_runtime_start = .; + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + __efi_runtime_stop = .; + } + + .text_rest : + { *(.text*) } @@ -98,17 +111,10 @@ SECTIONS . = ALIGN(8); - .efi_runtime : { - __efi_runtime_start = .; - *(efi_runtime_text) - *(efi_runtime_data) - __efi_runtime_stop = .; - } - .efi_runtime_rel : { __efi_runtime_rel_start = .; - *(.relaefi_runtime_text) - *(.relaefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) __efi_runtime_rel_stop = .; } diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds index 4157374..834dc99 100644 --- a/arch/arm/cpu/u-boot.lds +++ b/arch/arm/cpu/u-boot.lds @@ -43,6 +43,25 @@ SECTIONS *(.__image_copy_start) *(.vectors) CPUDIR/start.o (.text*) + } + + /* This needs to come before *(.text*) */ + .__efi_runtime_start : { + *(.__efi_runtime_start) + } + + .efi_runtime : { + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + } + + .__efi_runtime_stop : { + *(.__efi_runtime_stop) + } + + .text_rest : + { *(.text*) } @@ -136,27 +155,14 @@ SECTIONS . = ALIGN(4); - .__efi_runtime_start : { - *(.__efi_runtime_start) - } - - .efi_runtime : { - *(efi_runtime_text) - *(efi_runtime_data) - } - - .__efi_runtime_stop : { - *(.__efi_runtime_stop) - } - .efi_runtime_rel_start : { *(.__efi_runtime_rel_start) } .efi_runtime_rel : { - *(.relefi_runtime_text) - *(.relefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) } .efi_runtime_rel_stop : diff --git a/arch/arm/mach-zynq/u-boot.lds b/arch/arm/mach-zynq/u-boot.lds index ec9a0a0..91c32e8 100644 --- a/arch/arm/mach-zynq/u-boot.lds +++ b/arch/arm/mach-zynq/u-boot.lds @@ -19,6 +19,25 @@ SECTIONS *(.__image_copy_start) *(.vectors) CPUDIR/start.o (.text*) + } + + /* This needs to come before *(.text*) */ + .__efi_runtime_start : { + *(.__efi_runtime_start) + } + + .efi_runtime : { + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + } + + .__efi_runtime_stop : { + *(.__efi_runtime_stop) + } + + .text_rest : + { *(.text*) } @@ -41,27 +60,14 @@ SECTIONS . = ALIGN(4); - .__efi_runtime_start : { - *(.__efi_runtime_start) - } - - .efi_runtime : { - *(efi_runtime_text) - *(efi_runtime_data) - } - - .__efi_runtime_stop : { - *(.__efi_runtime_stop) - } - .efi_runtime_rel_start : { *(.__efi_runtime_rel_start) } .efi_runtime_rel : { - *(.relefi_runtime_text) - *(.relefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) } .efi_runtime_rel_stop : diff --git a/arch/riscv/cpu/ax25/u-boot.lds b/arch/riscv/cpu/ax25/u-boot.lds index 1589bab..3cc8974 100644 --- a/arch/riscv/cpu/ax25/u-boot.lds +++ b/arch/riscv/cpu/ax25/u-boot.lds @@ -12,7 +12,20 @@ SECTIONS .text : { arch/riscv/cpu/ax25/start.o (.text) - *(.text) + } + + /* This needs to come before *(.text*) */ + .efi_runtime : { + __efi_runtime_start = .; + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + __efi_runtime_stop = .; + } + + .text_rest : + { + *(.text*) } . = ALIGN(4); @@ -39,17 +52,10 @@ SECTIONS . = ALIGN(4); - .efi_runtime : { - __efi_runtime_start = .; - *(efi_runtime_text) - *(efi_runtime_data) - __efi_runtime_stop = .; - } - .efi_runtime_rel : { __efi_runtime_rel_start = .; - *(.relaefi_runtime_text) - *(.relaefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) __efi_runtime_rel_stop = .; } diff --git a/arch/sandbox/config.mk b/arch/sandbox/config.mk index 2babcde..5e7077b 100644 --- a/arch/sandbox/config.mk +++ b/arch/sandbox/config.mk @@ -5,6 +5,9 @@ PLATFORM_CPPFLAGS += -D__SANDBOX__ -U_FORTIFY_SOURCE PLATFORM_CPPFLAGS += -DCONFIG_ARCH_MAP_SYSMEM PLATFORM_LIBS += -lrt +LDFLAGS_FINAL += --gc-sections +PLATFORM_RELFLAGS += -ffunction-sections -fdata-sections + # Define this to avoid linking with SDL, which requires SDL libraries # This can solve 'sdl-config: Command not found' errors ifneq ($(NO_SDL),) diff --git a/arch/sandbox/cpu/u-boot.lds b/arch/sandbox/cpu/u-boot.lds index 3a6cf55..727bcc3 100644 --- a/arch/sandbox/cpu/u-boot.lds +++ b/arch/sandbox/cpu/u-boot.lds @@ -24,8 +24,9 @@ SECTIONS } .efi_runtime : { - *(efi_runtime_text) - *(efi_runtime_data) + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) } .__efi_runtime_stop : { @@ -38,8 +39,8 @@ SECTIONS } .efi_runtime_rel : { - *(.relefi_runtime_text) - *(.relefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) } .efi_runtime_rel_stop : diff --git a/arch/x86/config.mk b/arch/x86/config.mk index 5f77f98..586e11a 100644 --- a/arch/x86/config.mk +++ b/arch/x86/config.mk @@ -23,6 +23,8 @@ endif ifeq ($(IS_32BIT),y) PLATFORM_CPPFLAGS += -march=i386 -m32 +# TODO: These break on x86_64; need to debug further +PLATFORM_RELFLAGS += -fdata-sections else PLATFORM_CPPFLAGS += $(if $(CONFIG_SPL_BUILD),,-fpic) -fno-common -m64 endif diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index e4e997e..e1f634f 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -17,7 +17,7 @@ #include #include -.section .text +.section .text.start .code32 .globl _start .type _start, @function diff --git a/arch/x86/cpu/start64.S b/arch/x86/cpu/start64.S index 234482b..a473fd1 100644 --- a/arch/x86/cpu/start64.S +++ b/arch/x86/cpu/start64.S @@ -8,7 +8,7 @@ #include -.section .text +.section .text.start .code64 .globl _start .type _start, @function diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds index 3f38681..9a9d39c 100644 --- a/arch/x86/cpu/u-boot-64.lds +++ b/arch/x86/cpu/u-boot-64.lds @@ -17,6 +17,9 @@ SECTIONS . = CONFIG_SYS_TEXT_BASE; /* Location of bootcode in flash */ __text_start = .; + + .text.start : { *(.text.start); } + .text : { *(.text*); } . = ALIGN(4); diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds index f071936..a1cc19c 100644 --- a/arch/x86/cpu/u-boot.lds +++ b/arch/x86/cpu/u-boot.lds @@ -17,6 +17,23 @@ SECTIONS . = CONFIG_SYS_TEXT_BASE; /* Location of bootcode in flash */ __text_start = .; + + .text.start : { *(.text.start); } + + .__efi_runtime_start : { + *(.__efi_runtime_start) + } + + .efi_runtime : { + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + } + + .__efi_runtime_stop : { + *(.__efi_runtime_stop) + } + .text : { *(.text*); } . = ALIGN(4); @@ -43,27 +60,14 @@ SECTIONS . = ALIGN(4); - .__efi_runtime_start : { - *(.__efi_runtime_start) - } - - .efi_runtime : { - *(efi_runtime_text) - *(efi_runtime_data) - } - - .__efi_runtime_stop : { - *(.__efi_runtime_stop) - } - .efi_runtime_rel_start : { *(.__efi_runtime_rel_start) } .efi_runtime_rel : { - *(.relefi_runtime_text) - *(.relefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) } .efi_runtime_rel_stop : diff --git a/board/qualcomm/dragonboard410c/u-boot.lds b/board/qualcomm/dragonboard410c/u-boot.lds index dc3f718..fc1bba8 100644 --- a/board/qualcomm/dragonboard410c/u-boot.lds +++ b/board/qualcomm/dragonboard410c/u-boot.lds @@ -20,6 +20,19 @@ SECTIONS *(.__image_copy_start) board/qualcomm/dragonboard410c/head.o (.text*) CPUDIR/start.o (.text*) + } + + /* This needs to come before *(.text*) */ + .efi_runtime : { + __efi_runtime_start = .; + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + __efi_runtime_stop = .; + } + + .text_rest : + { *(.text*) } @@ -51,8 +64,8 @@ SECTIONS .efi_runtime_rel : { __efi_runtime_rel_start = .; - *(.relaefi_runtime_text) - *(.relaefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) __efi_runtime_rel_stop = .; } diff --git a/board/qualcomm/dragonboard820c/u-boot.lds b/board/qualcomm/dragonboard820c/u-boot.lds index bcf5738..dcf8256 100644 --- a/board/qualcomm/dragonboard820c/u-boot.lds +++ b/board/qualcomm/dragonboard820c/u-boot.lds @@ -20,6 +20,19 @@ SECTIONS *(.__image_copy_start) board/qualcomm/dragonboard820c/head.o (.text*) CPUDIR/start.o (.text*) + } + + /* This needs to come before *(.text*) */ + .efi_runtime : { + __efi_runtime_start = .; + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + __efi_runtime_stop = .; + } + + .text_rest : + { *(.text*) } @@ -42,17 +55,10 @@ SECTIONS . = ALIGN(8); - .efi_runtime : { - __efi_runtime_start = .; - *(efi_runtime_text) - *(efi_runtime_data) - __efi_runtime_stop = .; - } - .efi_runtime_rel : { __efi_runtime_rel_start = .; - *(.relaefi_runtime_text) - *(.relaefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) __efi_runtime_rel_stop = .; } diff --git a/board/ti/am335x/u-boot.lds b/board/ti/am335x/u-boot.lds index a56cc82..03c1d5f 100644 --- a/board/ti/am335x/u-boot.lds +++ b/board/ti/am335x/u-boot.lds @@ -37,6 +37,25 @@ SECTIONS *(.vectors) CPUDIR/start.o (.text*) board/ti/am335x/built-in.o (.text*) + } + + /* This needs to come before *(.text*) */ + .__efi_runtime_start : { + *(.__efi_runtime_start) + } + + .efi_runtime : { + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + } + + .__efi_runtime_stop : { + *(.__efi_runtime_stop) + } + + .text_rest : + { *(.text*) } @@ -59,27 +78,14 @@ SECTIONS . = ALIGN(4); - .__efi_runtime_start : { - *(.__efi_runtime_start) - } - - .efi_runtime : { - *(efi_runtime_text) - *(efi_runtime_data) - } - - .__efi_runtime_stop : { - *(.__efi_runtime_stop) - } - .efi_runtime_rel_start : { *(.__efi_runtime_rel_start) } .efi_runtime_rel : { - *(.relefi_runtime_text) - *(.relefi_runtime_data) + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) } .efi_runtime_rel_stop : diff --git a/include/efi_loader.h b/include/efi_loader.h index d837e7b..a0495db 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -406,8 +406,8 @@ static inline int guidcmp(const efi_guid_t *g1, const efi_guid_t *g2) * Use these to indicate that your code / data should go into the EFI runtime * section and thus still be available when the OS is running */ -#define __efi_runtime_data __attribute__ ((section ("efi_runtime_data"))) -#define __efi_runtime __attribute__ ((section ("efi_runtime_text"))) +#define __efi_runtime_data __attribute__ ((section (".data.efi_runtime"))) +#define __efi_runtime __attribute__ ((section (".text.efi_runtime"))) /* Call this with mmio_ptr as the _pointer_ to a pointer to an MMIO region * to make it available at runtime */ From 42a3d42688d8a389237cce2df18976d51c13b07f Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Wed, 11 Jul 2018 01:39:31 +0200 Subject: [PATCH 23/50] x86: Add efi_loader bits to x86_64 linker script The x86_64 linker script was missing efi runtime information. Add it. Signed-off-by: Alexander Graf --- arch/x86/cpu/u-boot-64.lds | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/arch/x86/cpu/u-boot-64.lds b/arch/x86/cpu/u-boot-64.lds index 9a9d39c..862aa2d 100644 --- a/arch/x86/cpu/u-boot-64.lds +++ b/arch/x86/cpu/u-boot-64.lds @@ -20,6 +20,20 @@ SECTIONS .text.start : { *(.text.start); } + .__efi_runtime_start : { + *(.__efi_runtime_start) + } + + .efi_runtime : { + *(.text.efi_runtime*) + *(.rodata.efi_runtime*) + *(.data.efi_runtime*) + } + + .__efi_runtime_stop : { + *(.__efi_runtime_stop) + } + .text : { *(.text*); } . = ALIGN(4); @@ -30,7 +44,10 @@ SECTIONS } . = ALIGN(4); - .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + .rodata : { + *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) + KEEP(*(.rodata.efi.init)); + } . = ALIGN(4); .data : { *(.data*) } @@ -41,6 +58,21 @@ SECTIONS . = ALIGN(4); .got : { *(.got*) } + .efi_runtime_rel_start : + { + *(.__efi_runtime_rel_start) + } + + .efi_runtime_rel : { + *(.rel*.efi_runtime) + *(.rel*.efi_runtime.*) + } + + .efi_runtime_rel_stop : + { + *(.__efi_runtime_rel_stop) + } + . = ALIGN(4); __data_end = .; __init_end = .; From 21b3edfc9644f1cef3798f57f965aa44a78d9d22 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 2 Jul 2018 12:53:52 +0200 Subject: [PATCH 24/50] efi_loader: check parameters of CreateEvent Rigorously check the TPL level and the event type. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 46c8ecd..86cb9ba 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -191,6 +191,25 @@ static void efi_queue_event(struct efi_event *event, bool check_tpl) } /** + * is_valid_tpl() - check if the task priority level is valid + * + * @tpl: TPL level to check + * ReturnValue: status code + */ +efi_status_t is_valid_tpl(efi_uintn_t tpl) +{ + switch (tpl) { + case TPL_APPLICATION: + case TPL_CALLBACK: + case TPL_NOTIFY: + case TPL_HIGH_LEVEL: + return EFI_SUCCESS; + default: + return EFI_INVALID_PARAMETER; + } +} + +/** * efi_signal_event() - signal an EFI event * @event: event to signal * @check_tpl: check the TPL level @@ -592,11 +611,21 @@ efi_status_t efi_create_event(uint32_t type, efi_uintn_t notify_tpl, if (event == NULL) return EFI_INVALID_PARAMETER; - if ((type & EVT_NOTIFY_SIGNAL) && (type & EVT_NOTIFY_WAIT)) + switch (type) { + case 0: + case EVT_TIMER: + case EVT_NOTIFY_SIGNAL: + case EVT_TIMER | EVT_NOTIFY_SIGNAL: + case EVT_NOTIFY_WAIT: + case EVT_TIMER | EVT_NOTIFY_WAIT: + case EVT_SIGNAL_EXIT_BOOT_SERVICES: + case EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE: + break; + default: return EFI_INVALID_PARAMETER; + } - if ((type & (EVT_NOTIFY_SIGNAL | EVT_NOTIFY_WAIT)) && - notify_function == NULL) + if (is_valid_tpl(notify_tpl) != EFI_SUCCESS) return EFI_INVALID_PARAMETER; evt = calloc(1, sizeof(struct efi_event)); From 4d5e071ee06429d3a6136888d75d8473d8cbdfff Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 2 Jul 2018 12:53:53 +0200 Subject: [PATCH 25/50] efi_loader: check parameters in memory allocation If no pointer is provided throw an error. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index 86edfc9..f5aecd4 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -293,6 +293,9 @@ efi_status_t efi_allocate_pages(int type, int memory_type, efi_status_t r = EFI_SUCCESS; uint64_t addr; + if (!memory) + return EFI_INVALID_PARAMETER; + switch (type) { case EFI_ALLOCATE_ANY_PAGES: /* Any page */ @@ -386,6 +389,9 @@ efi_status_t efi_allocate_pool(int pool_type, efi_uintn_t size, void **buffer) u64 num_pages = (size + sizeof(struct efi_pool_allocation) + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT; + if (!buffer) + return EFI_INVALID_PARAMETER; + if (size == 0) { *buffer = NULL; return EFI_SUCCESS; From 8e835554b36b57a32a59de643056723a01525c3b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 2 Jul 2018 12:53:54 +0200 Subject: [PATCH 26/50] efi_loader: check parameters of GetMemoryMap Check the parameters of boottime service GetMemoryMap(). Return EFI_INVALID_PARAMETER where required by the UEFI spec. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_memory.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index f5aecd4..bad8704 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -453,6 +453,9 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, struct list_head *lhandle; efi_uintn_t provided_map_size = *memory_map_size; + if (!memory_map_size) + return EFI_INVALID_PARAMETER; + list_for_each(lhandle, &efi_mem) map_entries++; @@ -463,6 +466,9 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, if (provided_map_size < map_size) return EFI_BUFFER_TOO_SMALL; + if (!memory_map) + return EFI_INVALID_PARAMETER; + if (descriptor_size) *descriptor_size = sizeof(struct efi_mem_desc); @@ -470,19 +476,18 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, *descriptor_version = EFI_MEMORY_DESCRIPTOR_VERSION; /* Copy list into array */ - if (memory_map) { - /* Return the list in ascending order */ - memory_map = &memory_map[map_entries - 1]; - list_for_each(lhandle, &efi_mem) { - struct efi_mem_list *lmem; + /* Return the list in ascending order */ + memory_map = &memory_map[map_entries - 1]; + list_for_each(lhandle, &efi_mem) { + struct efi_mem_list *lmem; - lmem = list_entry(lhandle, struct efi_mem_list, link); - *memory_map = lmem->desc; - memory_map--; - } + lmem = list_entry(lhandle, struct efi_mem_list, link); + *memory_map = lmem->desc; + memory_map--; } - *map_key = 0; + if (map_key) + *map_key = 0; return EFI_SUCCESS; } From 1fcb7ea28400aa69e157dc4b19c9667e96d3a033 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 2 Jul 2018 12:53:55 +0200 Subject: [PATCH 27/50] efi_loader: check map_key in ExitBootServices The UEFI spec requires that the memory map key is checked in ExitBootServices(). Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_loader.h | 3 +++ lib/efi_loader/efi_boottime.c | 4 ++++ lib/efi_loader/efi_memory.c | 8 +++++++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index a0495db..3cbec15 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -82,6 +82,9 @@ const char *__efi_nesting_dec(void); #define EFI_CACHELINE_SIZE 128 #endif +/* Key identifying current memory map */ +extern efi_uintn_t efi_memory_map_key; + extern struct efi_runtime_services efi_runtime_services; extern struct efi_system_table systab; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 86cb9ba..6bd64b9 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1854,6 +1854,10 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, EFI_ENTRY("%p, %ld", image_handle, map_key); + /* Check that the caller has read the current memory map */ + if (map_key != efi_memory_map_key) + return EFI_INVALID_PARAMETER; + /* Make sure that notification functions are not called anymore */ efi_tpl = TPL_HIGH_LEVEL; diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c index bad8704..967c3f7 100644 --- a/lib/efi_loader/efi_memory.c +++ b/lib/efi_loader/efi_memory.c @@ -15,6 +15,8 @@ DECLARE_GLOBAL_DATA_PTR; +efi_uintn_t efi_memory_map_key; + struct efi_mem_list { struct list_head link; struct efi_mem_desc desc; @@ -160,9 +162,13 @@ uint64_t efi_add_memory_map(uint64_t start, uint64_t pages, int memory_type, debug("%s: 0x%" PRIx64 " 0x%" PRIx64 " %d %s\n", __func__, start, pages, memory_type, overlap_only_ram ? "yes" : "no"); + if (memory_type >= EFI_MAX_MEMORY_TYPE) + return EFI_INVALID_PARAMETER; + if (!pages) return start; + ++efi_memory_map_key; newlist = calloc(1, sizeof(*newlist)); newlist->desc.type = memory_type; newlist->desc.physical_start = start; @@ -487,7 +493,7 @@ efi_status_t efi_get_memory_map(efi_uintn_t *memory_map_size, } if (map_key) - *map_key = 0; + *map_key = efi_memory_map_key; return EFI_SUCCESS; } From 0dc1bfb7302d220a48364263d5632d6d572b069b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 2 Jul 2018 02:41:23 +0200 Subject: [PATCH 28/50] fs: fat: cannot write to subdirectories fs_fat_write() is not able to write to subdirectories. Currently if a filepath with a leading slash is passed, the slash is treated as part of the filename to be created in the root directory. Strip leading (back-)slashes. Check that the remaining filename does not contain any illegal characters (<>:"/\|?*). This way we will throw an error when trying to write to a subdirectory. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- fs/fat/fat_write.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c index 3b77557..27e0ff6 100644 --- a/fs/fat/fat_write.c +++ b/fs/fat/fat_write.c @@ -909,9 +909,11 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, volume_info volinfo; fsdata datablock; fsdata *mydata = &datablock; - int cursect; + int cursect, i; int ret = -1, name_len; char l_filename[VFAT_MAXLEN_BYTES]; + char bad[2] = " "; + const char illegal[] = "<>:\"/\\|?*"; *actwrite = size; dir_curclust = 0; @@ -971,6 +973,18 @@ static int do_fat_write(const char *filename, void *buffer, loff_t size, } dentptr = (dir_entry *) do_fat_read_at_block; + /* Strip leading (back-)slashes */ + while ISDIRDELIM(*filename) + ++filename; + /* Check that the filename is valid */ + for (i = 0; i < strlen(illegal); ++i) { + *bad = illegal[i]; + if (strstr(filename, bad)) { + printf("FAT: illegal filename (%s)\n", filename); + return -1; + } + } + name_len = strlen(filename); if (name_len >= VFAT_MAXLEN_BYTES) name_len = VFAT_MAXLEN_BYTES - 1; From 1bfb1579be510ebad9656eb68fac48f1086431e7 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 2 Jul 2018 02:41:24 +0200 Subject: [PATCH 29/50] efi_selftest: test writing to file Provide a unit test for writing to a FAT file system. Add some additional comments in block device unit test. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_block_device.c | 70 ++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/lib/efi_selftest/efi_selftest_block_device.c b/lib/efi_selftest/efi_selftest_block_device.c index 4af8bd8..b82e405 100644 --- a/lib/efi_selftest/efi_selftest_block_device.c +++ b/lib/efi_selftest/efi_selftest_block_device.c @@ -309,11 +309,14 @@ static int execute(void) efi_uintn_t buf_size; char buf[16] __aligned(ARCH_DMA_MINALIGN); + /* Connect controller to virtual disk */ ret = boottime->connect_controller(disk_handle, NULL, NULL, 1); if (ret != EFI_SUCCESS) { efi_st_error("Failed to connect controller\n"); return EFI_ST_FAILURE; } + + /* Get the handle for the partition */ ret = boottime->locate_handle_buffer( BY_PROTOCOL, &guid_device_path, NULL, &no_handles, &handles); @@ -347,6 +350,8 @@ static int execute(void) efi_st_error("Partition handle not found\n"); return EFI_ST_FAILURE; } + + /* Open the simple file system protocol */ ret = boottime->open_protocol(handle_partition, &guid_simple_file_system_protocol, (void **)&file_system, NULL, NULL, @@ -355,6 +360,8 @@ static int execute(void) efi_st_error("Failed to open simple file system protocol\n"); return EFI_ST_FAILURE; } + + /* Open volume */ ret = file_system->open_volume(file_system, &root); if (ret != EFI_SUCCESS) { efi_st_error("Failed to open volume\n"); @@ -377,6 +384,8 @@ static int execute(void) "Wrong volume label '%ps', expected 'U-BOOT TEST'\n", system_info.info.volume_label); } + + /* Read file */ ret = root->open(root, &file, (s16 *)L"hello.txt", EFI_FILE_MODE_READ, 0); if (ret != EFI_SUCCESS) { @@ -389,6 +398,11 @@ static int execute(void) efi_st_error("Failed to read file\n"); return EFI_ST_FAILURE; } + if (buf_size != 13) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } if (efi_st_memcmp(buf, "Hello world!", 12)) { efi_st_error("Unexpected file content\n"); return EFI_ST_FAILURE; @@ -398,6 +412,62 @@ static int execute(void) efi_st_error("Failed to close file\n"); return EFI_ST_FAILURE; } + +#ifdef CONFIG_FAT_WRITE + /* Write file */ + ret = root->open(root, &file, (s16 *)L"u-boot.txt", + EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE, 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = 7; + boottime->set_mem(buf, sizeof(buf), 0); + boottime->copy_mem(buf, "U-Boot", buf_size); + ret = file->write(file, &buf_size, buf); + if (ret != EFI_SUCCESS || buf_size != 7) { + efi_st_error("Failed to write file\n"); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } + + /* Verify file */ + boottime->set_mem(buf, sizeof(buf), 0); + ret = root->open(root, &file, (s16 *)L"u-boot.txt", EFI_FILE_MODE_READ, + 0); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to open file\n"); + return EFI_ST_FAILURE; + } + buf_size = sizeof(buf) - 1; + ret = file->read(file, &buf_size, buf); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to read file\n"); + return EFI_ST_FAILURE; + } + if (buf_size != 7) { + efi_st_error("Wrong number of bytes read: %u\n", + (unsigned int)buf_size); + return EFI_ST_FAILURE; + } + if (efi_st_memcmp(buf, "U-Boot", 7)) { + efi_st_error("Unexpected file content %s\n", buf); + return EFI_ST_FAILURE; + } + ret = file->close(file); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close file\n"); + return EFI_ST_FAILURE; + } +#else + efi_st_todo("CONFIG_FAT_WRITE is not set\n"); +#endif /* CONFIG_FAT_WRITE */ + + /* Close volume */ ret = root->close(root); if (ret != EFI_SUCCESS) { efi_st_error("Failed to close volume\n"); From df76431b11396b940b5aa9b25edd5b0a33b18911 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 30 Jun 2018 07:11:32 +0200 Subject: [PATCH 30/50] efi_driver: set DM_FLAG_NAME_ALLOCED flag Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak when the block device is removed. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_driver/efi_block_device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/efi_driver/efi_block_device.c b/lib/efi_driver/efi_block_device.c index 9c807ff..5b9c139 100644 --- a/lib/efi_driver/efi_block_device.c +++ b/lib/efi_driver/efi_block_device.c @@ -161,6 +161,8 @@ static int efi_bl_bind(efi_handle_t handle, void *interface) return ret; if (!bdev) return -ENOENT; + /* Set the DM_FLAG_NAME_ALLOCED flag to avoid a memory leak */ + device_set_name_alloced(bdev); /* Allocate priv */ ret = device_probe(bdev); if (ret) From 95147313a98c2403589c6bd9a6768c657442e16c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Jul 2018 08:17:58 +0200 Subject: [PATCH 31/50] efi_loader: set revision in loaded image protocol The revision number has to be set in the loaded image protocol. The problem was detected by running the SCT in Protocol/LoadedImage/BlackBoxTest/LoadedImageBBTestMain.c:890 Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 2 ++ lib/efi_loader/efi_boottime.c | 1 + 2 files changed, 3 insertions(+) diff --git a/include/efi_api.h b/include/efi_api.h index 0c3dd3c..53798d5 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -318,6 +318,8 @@ struct efi_system_table { EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, \ 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) +#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000 + struct efi_loaded_image { u32 revision; void *parent_handle; diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 6bd64b9..1869856 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1497,6 +1497,7 @@ efi_status_t efi_setup_loaded_image( /* efi_exit() assumes that the handle points to the info */ obj->handle = info; + info->revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; info->file_path = file_path; if (device_path) { From 4f187897703ab38b12bb9b5a733028aa0083a618 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Jul 2018 08:17:59 +0200 Subject: [PATCH 32/50] efi_loader: EFI_SIMPLE_TEXT_INPUT_PROTOCOL.Reset() Implement the reset service of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL. This should resolve the error reported by the SCT in Protocol/SimpleTextIn/BlackBoxTest/SimpleTextInBBTestFunction.c:193 Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_console.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index ce66c93..1d52753 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -381,7 +381,12 @@ static efi_status_t EFIAPI efi_cin_reset( bool extended_verification) { EFI_ENTRY("%p, %d", this, extended_verification); - return EFI_EXIT(EFI_UNSUPPORTED); + + /* Empty input buffer */ + while (tstc()) + getc(); + + return EFI_EXIT(EFI_SUCCESS); } /* From e67ff94deda15f344af62b46ef21b3bb10d1c0f1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Jul 2018 08:18:00 +0200 Subject: [PATCH 33/50] efi_loader: clear screen has to reset cursor position After clearing the screen the cursor position is row 0, column 0. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_console.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c index 1d52753..3fd0d2f 100644 --- a/lib/efi_loader/efi_console.c +++ b/lib/efi_loader/efi_console.c @@ -335,6 +335,8 @@ static efi_status_t EFIAPI efi_cout_clear_screen( EFI_ENTRY("%p", this); printf(ESC"[2J"); + efi_con_mode.cursor_column = 0; + efi_con_mode.cursor_row = 0; return EFI_EXIT(EFI_SUCCESS); } From 112f24301696d015e25090d713e2e5c73f4b8a3c Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Jun 2018 12:45:27 +0200 Subject: [PATCH 34/50] efi_loader: specify UEFI spec revision Both in the boot and the runtime services tables we have to specify the UEFI spec revision. The same value is already used for the system table. So let's use a common constant. In the boot services table we have to provide the header signature. Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Signed-off-by: Alexander Graf --- include/efi_api.h | 5 ++++- lib/efi_loader/efi_boottime.c | 4 +++- lib/efi_loader/efi_runtime.c | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index 53798d5..696cb26 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -21,6 +21,9 @@ #include #endif +/* UEFI spec version 2.7 */ +#define EFI_SPECIFICATION_VERSION (2 << 16 | 70) + /* Types and defines for EFI CreateEvent */ enum efi_timer_delay { EFI_TIMER_STOP = 0, @@ -46,6 +49,7 @@ typedef uint16_t *efi_string_t; struct efi_event; /* EFI Boot Services table */ +#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42 struct efi_boot_services { struct efi_table_hdr hdr; efi_status_t (EFIAPI *raise_tpl)(efi_uintn_t new_tpl); @@ -186,7 +190,6 @@ enum efi_reset_type { /* EFI Runtime Services table */ #define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552ULL -#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 1869856..9a0c323 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3058,6 +3058,8 @@ out: static const struct efi_boot_services efi_boot_services = { .hdr = { + .signature = EFI_BOOT_SERVICES_SIGNATURE, + .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_table_hdr), }, .raise_tpl = efi_raise_tpl, @@ -3113,7 +3115,7 @@ static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot"; struct efi_system_table __efi_runtime_data systab = { .hdr = { .signature = EFI_SYSTEM_TABLE_SIGNATURE, - .revision = 2 << 16 | 70, /* 2.7 */ + .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_table_hdr), }, .fw_vendor = (long)firmware_vendor, diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index dd3ff8a..cfa60b8 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -459,7 +459,7 @@ efi_status_t __efi_runtime EFIAPI efi_query_variable_info( struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .hdr = { .signature = EFI_RUNTIME_SERVICES_SIGNATURE, - .revision = EFI_RUNTIME_SERVICES_REVISION, + .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_table_hdr), }, .get_time = &efi_get_time_boottime, From bdfb894a3efbb35e184e9afece15d44bc59db43a Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Jun 2018 12:45:28 +0200 Subject: [PATCH 35/50] efi_loader: correct EFI_RUNTIME_SERVICES_SIGNATURE The value for EFI_RUNTIME_SERVICES_SIGNATURE does not match the UEFI spec 2.7. Reported-by: Takahiro Akashi Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Signed-off-by: Alexander Graf --- include/efi_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/efi_api.h b/include/efi_api.h index 696cb26..3a9da32 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -189,7 +189,7 @@ enum efi_reset_type { }; /* EFI Runtime Services table */ -#define EFI_RUNTIME_SERVICES_SIGNATURE 0x5652453544e5552ULL +#define EFI_RUNTIME_SERVICES_SIGNATURE 0x56524553544e5552ULL #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 #define CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE 0x00020000 From 71c846ab84c81b0ef7786ee5ea02bb05d5ca5bb8 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Jun 2018 12:45:29 +0200 Subject: [PATCH 36/50] efi_loader: correct headersize EFI tables The headersize field has to be set to the size of the whole table including the header. Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 4 ++-- lib/efi_loader/efi_runtime.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 9a0c323..f6df6df 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3060,7 +3060,7 @@ static const struct efi_boot_services efi_boot_services = { .hdr = { .signature = EFI_BOOT_SERVICES_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, - .headersize = sizeof(struct efi_table_hdr), + .headersize = sizeof(struct efi_boot_services), }, .raise_tpl = efi_raise_tpl, .restore_tpl = efi_restore_tpl, @@ -3116,7 +3116,7 @@ struct efi_system_table __efi_runtime_data systab = { .hdr = { .signature = EFI_SYSTEM_TABLE_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, - .headersize = sizeof(struct efi_table_hdr), + .headersize = sizeof(struct efi_system_table), }, .fw_vendor = (long)firmware_vendor, .con_in = (void *)&efi_con_in, diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index cfa60b8..1acb06a 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -460,7 +460,7 @@ struct efi_runtime_services __efi_runtime_data efi_runtime_services = { .hdr = { .signature = EFI_RUNTIME_SERVICES_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, - .headersize = sizeof(struct efi_table_hdr), + .headersize = sizeof(struct efi_runtime_services), }, .get_time = &efi_get_time_boottime, .set_time = (void *)&efi_device_error, From 0b386537a51d5ac6e2da022ade49424ecc50ffa1 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Jun 2018 12:45:30 +0200 Subject: [PATCH 37/50] efi_loader: provide firmware revision Provide a firmware revision in the system table using the Makefile variables VERSION and PATCHLEVEL, e.g. 0x20180700 for v2018.07. Correct the type of the firmware vendor. It is a u16* pointer. Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Signed-off-by: Alexander Graf --- include/efi_api.h | 2 +- lib/efi_loader/Makefile | 3 +++ lib/efi_loader/efi_boottime.c | 5 +++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index 3a9da32..c98cc34 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -303,7 +303,7 @@ struct efi_configuration_table struct efi_system_table { struct efi_table_hdr hdr; - unsigned long fw_vendor; /* physical addr of wchar_t vendor string */ + u16 *fw_vendor; /* physical addr of wchar_t vendor string */ u32 fw_revision; efi_handle_t con_in_handle; struct efi_simple_input_interface *con_in; diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index d6402c4..1ffbf52 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -6,6 +6,9 @@ # This file only gets included with CONFIG_EFI_LOADER set, so all # object inclusion implicitly depends on it +CFLAGS_efi_boottime.o += \ + -DFW_VERSION="0x$(VERSION)" \ + -DFW_PATCHLEVEL="0x$(PATCHLEVEL)" CFLAGS_helloworld.o := $(CFLAGS_EFI) -Os -ffreestanding CFLAGS_REMOVE_helloworld.o := $(CFLAGS_NON_EFI) -Os diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index f6df6df..c5d45dc 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -3110,7 +3110,7 @@ static const struct efi_boot_services efi_boot_services = { .create_event_ex = efi_create_event_ex, }; -static uint16_t __efi_runtime_data firmware_vendor[] = L"Das U-Boot"; +static u16 __efi_runtime_data firmware_vendor[] = L"Das U-Boot"; struct efi_system_table __efi_runtime_data systab = { .hdr = { @@ -3118,7 +3118,8 @@ struct efi_system_table __efi_runtime_data systab = { .revision = EFI_SPECIFICATION_VERSION, .headersize = sizeof(struct efi_system_table), }, - .fw_vendor = (long)firmware_vendor, + .fw_vendor = firmware_vendor, + .fw_revision = FW_VERSION << 16 | FW_PATCHLEVEL << 8, .con_in = (void *)&efi_con_in, .con_out = (void *)&efi_con_out, .std_err = (void *)&efi_con_out, From 640adadf811e9c229ddec597595a00db3f5304b0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Jun 2018 12:45:31 +0200 Subject: [PATCH 38/50] efi_loader: calculate crc32 for EFI tables For the boot and runtime services tables and for the system table the crc32 has to be set in the header. Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Signed-off-by: Alexander Graf --- cmd/bootefi.c | 5 +++++ include/efi_loader.h | 2 ++ lib/efi_loader/efi_boottime.c | 32 ++++++++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 4097277..e57e70f 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -44,6 +44,11 @@ efi_status_t efi_init_obj_list(void) if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) return efi_obj_list_initialized; + /* Initialize system table */ + ret = efi_initialize_system_table(); + if (ret != EFI_SUCCESS) + goto out; + /* Initialize EFI driver uclass */ ret = efi_driver_init(); if (ret != EFI_SUCCESS) diff --git a/include/efi_loader.h b/include/efi_loader.h index 3cbec15..06f74e2 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -202,6 +202,8 @@ extern struct list_head efi_obj_list; /* List of all events */ extern struct list_head efi_events; +/* Called by bootefi to initialize runtime */ +efi_status_t efi_initialize_system_table(void); /* Called by bootefi to make console interface available */ int efi_console_register(void); /* Called by bootefi to make all disk storage accessible as EFI objects */ diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c5d45dc..5fea8b1 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -164,6 +164,18 @@ const char *__efi_nesting_dec(void) } /** + * efi_update_table_header_crc32() - Update CRC32 in table header + * + * @table: EFI table + */ +static void efi_update_table_header_crc32(struct efi_table_hdr *table) +{ + table->crc32 = 0; + table->crc32 = crc32(0, (const unsigned char *)table, + table->headersize); +} + +/** * efi_queue_event() - queue an EFI event * @event: event to signal * @check_tpl: check the TPL level @@ -1901,9 +1913,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle, systab.boottime = NULL; /* Recalculate CRC32 */ - systab.hdr.crc32 = 0; - systab.hdr.crc32 = crc32(0, (const unsigned char *)&systab, - sizeof(struct efi_system_table)); + efi_update_table_header_crc32(&systab.hdr); /* Give the payload some time to boot */ efi_set_watchdog(0); @@ -3056,7 +3066,7 @@ out: return EFI_EXIT(r); } -static const struct efi_boot_services efi_boot_services = { +static struct efi_boot_services efi_boot_services = { .hdr = { .signature = EFI_BOOT_SERVICES_SIGNATURE, .revision = EFI_SPECIFICATION_VERSION, @@ -3128,3 +3138,17 @@ struct efi_system_table __efi_runtime_data systab = { .nr_tables = 0, .tables = (void *)efi_conf_table, }; + +/** + * efi_initialize_system_table() - Initialize system table + * + * Return Value: status code + */ +efi_status_t efi_initialize_system_table(void) +{ + /* Set crc32 field in table headers */ + efi_update_table_header_crc32(&systab.hdr); + efi_update_table_header_crc32(&efi_runtime_services.hdr); + efi_update_table_header_crc32(&efi_boot_services.hdr); + return EFI_SUCCESS; +} From 4182a129ef735bfd6c54788affe1b649ab85b851 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Jun 2018 12:45:32 +0200 Subject: [PATCH 39/50] efi_loader: allocate configuration table array The system table contains a link to the list of configurations tables. These include the device tree, SMBIOS table, and the ACPI table. This array is currently statically linked. With the patch it is allocated as EFI_RUNTIME_SERVICES_DATA. Due to the structure of the system table we cannot work with a linked list here. Signed-off-by: Heinrich Schuchardt Reviewed-by: Bin Meng Signed-off-by: Alexander Graf --- include/efi_loader.h | 3 +++ lib/efi_loader/efi_boottime.c | 39 +++++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index 06f74e2..051f9c4 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -17,6 +17,9 @@ #include +/* Maximum number of configuration tables */ +#define EFI_MAX_CONFIGURATION_TABLES 16 + int __efi_entry_check(void); int __efi_exit_check(void); const char *__efi_nesting(void); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 5fea8b1..c035425 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -35,16 +35,6 @@ LIST_HEAD(efi_events); */ static bool efi_is_direct_boot = true; -/* - * EFI can pass arbitrary additional "tables" containing vendor specific - * information to the payload. One such table is the FDT table which contains - * a pointer to a flattened device tree blob. - * - * In most cases we want to pass an FDT to the payload, so reserve one slot of - * config table space for it. The pointer gets populated by do_bootefi_exec(). - */ -static struct efi_configuration_table __efi_runtime_data efi_conf_table[16]; - #ifdef CONFIG_ARM /* * The "gd" pointer lives in a register on ARM and AArch64 that we declare @@ -1402,9 +1392,9 @@ static efi_status_t EFIAPI efi_locate_handle_ext( */ static void efi_remove_configuration_table(int i) { - struct efi_configuration_table *this = &efi_conf_table[i]; - struct efi_configuration_table *next = &efi_conf_table[i + 1]; - struct efi_configuration_table *end = &efi_conf_table[systab.nr_tables]; + struct efi_configuration_table *this = &systab.tables[i]; + struct efi_configuration_table *next = &systab.tables[i + 1]; + struct efi_configuration_table *end = &systab.tables[systab.nr_tables]; memmove(this, next, (ulong)end - (ulong)next); systab.nr_tables--; @@ -1432,9 +1422,9 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, /* Check for guid override */ for (i = 0; i < systab.nr_tables; i++) { - if (!guidcmp(guid, &efi_conf_table[i].guid)) { + if (!guidcmp(guid, &systab.tables[i].guid)) { if (table) - efi_conf_table[i].table = table; + systab.tables[i].table = table; else efi_remove_configuration_table(i); goto out; @@ -1445,12 +1435,12 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, return EFI_NOT_FOUND; /* No override, check for overflow */ - if (i >= ARRAY_SIZE(efi_conf_table)) + if (i >= EFI_MAX_CONFIGURATION_TABLES) return EFI_OUT_OF_RESOURCES; /* Add a new entry */ - memcpy(&efi_conf_table[i].guid, guid, sizeof(*guid)); - efi_conf_table[i].table = table; + memcpy(&systab.tables[i].guid, guid, sizeof(*guid)); + systab.tables[i].table = table; systab.nr_tables = i + 1; out: @@ -3136,7 +3126,7 @@ struct efi_system_table __efi_runtime_data systab = { .runtime = (void *)&efi_runtime_services, .boottime = (void *)&efi_boot_services, .nr_tables = 0, - .tables = (void *)efi_conf_table, + .tables = NULL, }; /** @@ -3146,9 +3136,18 @@ struct efi_system_table __efi_runtime_data systab = { */ efi_status_t efi_initialize_system_table(void) { + efi_status_t ret; + + /* Allocate configuration table array */ + ret = efi_allocate_pool(EFI_RUNTIME_SERVICES_DATA, + EFI_MAX_CONFIGURATION_TABLES * + sizeof(struct efi_configuration_table), + (void **)&systab.tables); + /* Set crc32 field in table headers */ efi_update_table_header_crc32(&systab.hdr); efi_update_table_header_crc32(&efi_runtime_services.hdr); efi_update_table_header_crc32(&efi_boot_services.hdr); - return EFI_SUCCESS; + + return ret; } From 9b30232bfc6b98e7caa517bbec77f00fb46c93de Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 28 Jun 2018 12:45:33 +0200 Subject: [PATCH 40/50] efi_selftest: test InstallConfigurationTable() Provide a unit test for InstallConfigurationTable(). A table is installed, updated, removed. The table entry and the triggering of events is checked. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_config_table.c | 223 +++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_config_table.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index bf5c819..c0fd490 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -13,6 +13,7 @@ CFLAGS_REMOVE_efi_selftest_miniapp_return.o := $(CFLAGS_NON_EFI) -Os obj-$(CONFIG_CMD_BOOTEFI_SELFTEST) += \ efi_selftest.o \ efi_selftest_bitblt.o \ +efi_selftest_config_table.o \ efi_selftest_controllers.o \ efi_selftest_console.o \ efi_selftest_devicepath.o \ diff --git a/lib/efi_selftest/efi_selftest_config_table.c b/lib/efi_selftest/efi_selftest_config_table.c new file mode 100644 index 0000000..627b73c --- /dev/null +++ b/lib/efi_selftest/efi_selftest_config_table.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_config_tables + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * This test checks the following service: + * InstallConfigurationTable. + */ + +#include + +static const struct efi_system_table *sys_table; +static struct efi_boot_services *boottime; + +static efi_guid_t table_guid = + EFI_GUID(0xff1c3f9e, 0x795b, 0x1529, 0xf1, 0x55, + 0x17, 0x2e, 0x51, 0x6b, 0x49, 0x75); + +/* + * Notification function, increments the notfication count if parameter + * context is provided. + * + * @event notified event + * @context pointer to the notification count + */ +static void EFIAPI notify(struct efi_event *event, void *context) +{ + unsigned int *count = context; + + if (count) + ++*count; +} + +/* + * 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) +{ + sys_table = systable; + boottime = systable->boottime; + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * A table is installed, updated, removed. The table entry and the + * triggering of events is checked. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + unsigned int counter = 0; + struct efi_event *event; + void *table; + const unsigned int tables[2]; + efi_uintn_t i; + efi_uintn_t tabcnt; + efi_uintn_t table_count = sys_table->nr_tables; + + ret = boottime->create_event_ex(0, TPL_NOTIFY, + notify, (void *)&counter, + &table_guid, &event); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to create event\n"); + return EFI_ST_FAILURE; + } + + /* Try to delete non-existent table */ + ret = boottime->install_configuration_table(&table_guid, NULL); + if (ret != EFI_NOT_FOUND) { + efi_st_error("Failed to detect missing table\n"); + return EFI_ST_FAILURE; + } + if (counter) { + efi_st_error("Notification function was called.\n"); + return EFI_ST_FAILURE; + } + /* Check if the event was signaled */ + ret = boottime->check_event(event); + if (ret == EFI_SUCCESS) { + efi_st_error("Event was signaled on EFI_NOT_FOUND\n"); + return EFI_ST_FAILURE; + } + if (counter != 1) { + efi_st_error("Notification function was not called.\n"); + return EFI_ST_FAILURE; + } + if (table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + + /* Install table */ + ret = boottime->install_configuration_table(&table_guid, + (void *)&tables[0]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to install table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on insert\n"); + return EFI_ST_FAILURE; + } + if (++table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) + table = sys_table->tables[i].table; + } + if (!table) { + efi_st_error("Installed table not found\n"); + return EFI_ST_FAILURE; + } + if (table != &tables[0]) { + efi_st_error("Incorrect table address\n"); + return EFI_ST_FAILURE; + } + /* Update table */ + ret = boottime->install_configuration_table(&table_guid, + (void *)&tables[1]); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to update table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on update\n"); + return EFI_ST_FAILURE; + } + if (table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + tabcnt = 0; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) { + table = sys_table->tables[i].table; + ++tabcnt; + } + } + if (!table) { + efi_st_error("Installed table not found\n"); + return EFI_ST_FAILURE; + } + if (tabcnt > 1) { + efi_st_error("Duplicate table guid\n"); + return EFI_ST_FAILURE; + } + if (table != &tables[1]) { + efi_st_error("Incorrect table address\n"); + return EFI_ST_FAILURE; + } + + /* Delete table */ + ret = boottime->install_configuration_table(&table_guid, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to delete table\n"); + return EFI_ST_FAILURE; + } + /* Check signaled state */ + ret = boottime->check_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Event was not signaled on delete\n"); + return EFI_ST_FAILURE; + } + if (--table_count != sys_table->nr_tables) { + efi_st_error("Incorrect table count %u, expected %u\n", + (unsigned int)sys_table->nr_tables, + (unsigned int)table_count); + return EFI_ST_FAILURE; + } + table = NULL; + for (i = 0; i < sys_table->nr_tables; ++i) { + if (!efi_st_memcmp(&sys_table->tables[i].guid, &table_guid, + sizeof(efi_guid_t))) { + table = sys_table->tables[i].table; + } + } + if (table) { + efi_st_error("Wrong table deleted\n"); + return EFI_ST_FAILURE; + } + + ret = boottime->close_event(event); + if (ret != EFI_SUCCESS) { + efi_st_error("Failed to close event\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(configtables) = { + .name = "configuration tables", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; From 8aa8360eca31b3b9f34645015df0556ce0e20e6d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 15:36:04 +0200 Subject: [PATCH 41/50] efi_loader: correct signature of CalculateCrc32() Use const for the buffer. We are not changing the buffer. Use efi_uintn_t where prescribed by the UEFI spec. Prefer u32 over uint32_t. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- include/efi_api.h | 5 +++-- lib/efi_loader/efi_boottime.c | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index c98cc34..ebf2a3b 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -165,8 +165,9 @@ struct efi_boot_services { void **handle, ...); efi_status_t (EFIAPI *uninstall_multiple_protocol_interfaces)( void *handle, ...); - efi_status_t (EFIAPI *calculate_crc32)(void *data, - unsigned long data_size, uint32_t *crc32); + efi_status_t (EFIAPI *calculate_crc32)(const void *data, + efi_uintn_t data_size, + u32 *crc32); void (EFIAPI *copy_mem)(void *destination, const void *source, size_t length); void (EFIAPI *set_mem)(void *buffer, size_t size, uint8_t value); diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index c035425..820d766 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -2448,11 +2448,11 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces( * * Return: status code */ -static efi_status_t EFIAPI efi_calculate_crc32(void *data, - unsigned long data_size, - uint32_t *crc32_p) +static efi_status_t EFIAPI efi_calculate_crc32(const void *data, + efi_uintn_t data_size, + u32 *crc32_p) { - EFI_ENTRY("%p, %ld", data, data_size); + EFI_ENTRY("%p, %zu", data, data_size); *crc32_p = crc32(0, data, data_size); return EFI_EXIT(EFI_SUCCESS); } From 55d8ee3b7bfc7222fb9782737b73364e78364792 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 15:36:05 +0200 Subject: [PATCH 42/50] efi_loader: update crc32 in InstallConfigurationTable If the number of installed tables is changed in InstallConfigurationTable() update the crc32 of the system table. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_boottime.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c index 820d766..b9e54f5 100644 --- a/lib/efi_loader/efi_boottime.c +++ b/lib/efi_loader/efi_boottime.c @@ -1444,6 +1444,9 @@ efi_status_t efi_install_configuration_table(const efi_guid_t *guid, systab.nr_tables = i + 1; out: + /* systab.nr_tables may have changed. So we need to update the crc32 */ + efi_update_table_header_crc32(&systab.hdr); + /* Notify that the configuration table was changed */ list_for_each_entry(evt, &efi_events, link) { if (evt->group && !guidcmp(evt->group, guid)) { From 74fc044574e780c4af790b1f88dd74b317787eff Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 15:36:06 +0200 Subject: [PATCH 43/50] efi_selftest: check crc32 for InstallConfigurationTable InstallConfigurationTable() may change the number of installed configuration tables. Check the crc32 of the system table. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_config_table.c | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/lib/efi_selftest/efi_selftest_config_table.c b/lib/efi_selftest/efi_selftest_config_table.c index 627b73c..2aa3fc7 100644 --- a/lib/efi_selftest/efi_selftest_config_table.c +++ b/lib/efi_selftest/efi_selftest_config_table.c @@ -33,6 +33,36 @@ static void EFIAPI notify(struct efi_event *event, void *context) } /* + * 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 */ + 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 + * copying + */ + hdr->crc32 = 0; + ret = boottime->calculate_crc32(table, hdr->headersize, &res); + /* Reset table crc32 so it stays constant */ + hdr->crc32 = crc32; + if (ret != EFI_ST_SUCCESS) { + efi_st_error("CalculateCrc32 failed\n"); + return EFI_ST_FAILURE; + } + if (res != crc32) { + efi_st_error("Incorrect CRC32\n"); + return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* * Setup unit test. * * @handle: handle of the loaded image @@ -135,6 +165,11 @@ static int execute(void) efi_st_error("Incorrect table address\n"); return EFI_ST_FAILURE; } + if (check_table(sys_table) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + /* Update table */ ret = boottime->install_configuration_table(&table_guid, (void *)&tables[1]); @@ -175,6 +210,10 @@ static int execute(void) efi_st_error("Incorrect table address\n"); return EFI_ST_FAILURE; } + if (check_table(sys_table) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } /* Delete table */ ret = boottime->install_configuration_table(&table_guid, NULL); @@ -211,6 +250,10 @@ static int execute(void) efi_st_error("Failed to close event\n"); return EFI_ST_FAILURE; } + if (check_table(sys_table) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } return EFI_ST_SUCCESS; } From 62045b0eb43285424712875b92ddc683cd00991e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 15:36:07 +0200 Subject: [PATCH 44/50] efi_selftest: unit test for CalculateCrc32() This unit test checks the CalculateCrc32 bootservice and checks the headers of the system table, the boot services tablle, and the runtime services table before and after ExitBootServices(). Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_crc32.c | 141 ++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_crc32.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index c0fd490..1f3084c 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -16,6 +16,7 @@ efi_selftest_bitblt.o \ efi_selftest_config_table.o \ efi_selftest_controllers.o \ efi_selftest_console.o \ +efi_selftest_crc32.o \ efi_selftest_devicepath.o \ efi_selftest_devicepath_util.o \ efi_selftest_events.o \ diff --git a/lib/efi_selftest/efi_selftest_crc32.c b/lib/efi_selftest/efi_selftest_crc32.c new file mode 100644 index 0000000..8555b8f --- /dev/null +++ b/lib/efi_selftest/efi_selftest_crc32.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_crc32 + * + * 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 + * services table before and after ExitBootServices(). + */ + +#include + +const struct efi_system_table *st; +efi_status_t (EFIAPI *bs_crc32)(const void *data, efi_uintn_t data_size, + u32 *crc32); + +static int check_table(const void *table) +{ + efi_status_t ret; + u32 crc32, res; + /* Casting from const to not const */ + struct efi_table_hdr *hdr = (struct efi_table_hdr *)table; + + if (!hdr->signature) { + efi_st_error("Missing header signature\n"); + return EFI_ST_FAILURE; + } + if (!hdr->revision) { + efi_st_error("Missing header revision\n"); + return EFI_ST_FAILURE; + } + if (hdr->headersize <= sizeof(struct efi_table_hdr)) { + efi_st_error("Incorrect headersize value\n"); + return EFI_ST_FAILURE; + } + if (hdr->reserved) { + efi_st_error("Reserved header field is not zero\n"); + return EFI_ST_FAILURE; + } + + crc32 = hdr->crc32; + /* + * Setting the crc32 of the 'const' table to zero is easier than + * copying + */ + hdr->crc32 = 0; + ret = bs_crc32(table, hdr->headersize, &res); + /* Reset table crc32 so it stays constant */ + hdr->crc32 = crc32; + if (ret != EFI_ST_SUCCESS) { + efi_st_error("CalculateCrc32 failed\n"); + return EFI_ST_FAILURE; + } + if (res != crc32) { + efi_st_error("Incorrect CRC32\n"); + // return EFI_ST_FAILURE; + } + return EFI_ST_SUCCESS; +} + +/* + * Setup unit test. + * + * Check that CalculateCrc32 is working correctly. + * Check tables before ExitBootServices(). + * + * @handle: handle of the loaded image + * @systable: system table + * @return: EFI_ST_SUCCESS for success + */ +static int setup(const efi_handle_t handle, + const struct efi_system_table *systable) +{ + efi_status_t ret; + u32 res; + + st = systable; + bs_crc32 = systable->boottime->calculate_crc32; + + /* Check that CalculateCrc32 is working */ + ret = bs_crc32("U-Boot", 6, &res); + if (ret != EFI_ST_SUCCESS) { + efi_st_error("CalculateCrc32 failed\n"); + return EFI_ST_FAILURE; + } + if (res != 0x134b0db4) { + efi_st_error("Incorrect CRC32\n"); + return EFI_ST_FAILURE; + } + + /* Check tables before ExitBootServices() */ + if (check_table(st) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + if (check_table(st->boottime) != EFI_ST_SUCCESS) { + efi_st_error("Checking boottime table\n"); + return EFI_ST_FAILURE; + } + if (check_table(st->runtime) != EFI_ST_SUCCESS) { + efi_st_error("Checking runtime table\n"); + return EFI_ST_FAILURE; + } + + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test + * + * Check tables after ExitBootServices() + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + if (check_table(st) != EFI_ST_SUCCESS) { + efi_st_error("Checking system table\n"); + return EFI_ST_FAILURE; + } + if (check_table(st->runtime) != EFI_ST_SUCCESS) { + efi_st_error("Checking runtime table\n"); + return EFI_ST_FAILURE; + } + + /* + * We cannot call SetVirtualAddressMap() and recheck the runtime + * table afterwards because this would invalidate the addresses of the + * unit tests. + */ + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(crc32) = { + .name = "crc32", + .phase = EFI_SETUP_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; From 5d889024010e0d2397c2bd3e6dd66e12e9f657d0 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 23:39:12 +0200 Subject: [PATCH 45/50] rtc: remove CONFIG_CMD_DATE dependency The EFI subsystem accesses the real time clock and is enabled by default. So we should drop any CONFIG_CMD_DATE dependency from the real time clock drivers. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- drivers/rtc/at91sam9_rtt.c | 4 ---- drivers/rtc/davinci.c | 2 -- drivers/rtc/ds1302.c | 4 ---- drivers/rtc/ds1306.c | 4 ---- drivers/rtc/ds1307.c | 4 ---- drivers/rtc/ds1337.c | 4 ---- drivers/rtc/ds1374.c | 3 --- drivers/rtc/ds164x.c | 4 ---- drivers/rtc/ds174x.c | 4 ---- drivers/rtc/ds3231.c | 4 ---- drivers/rtc/imxdi.c | 4 ---- drivers/rtc/m41t11.c | 3 --- drivers/rtc/m41t60.c | 3 --- drivers/rtc/m41t62.c | 4 ---- drivers/rtc/m48t35ax.c | 4 ---- drivers/rtc/max6900.c | 4 ---- drivers/rtc/mc146818.c | 3 --- drivers/rtc/mcfrtc.c | 4 ---- drivers/rtc/mk48t59.c | 4 ---- drivers/rtc/pcf8563.c | 4 ---- drivers/rtc/rs5c372.c | 3 --- drivers/rtc/rx8025.c | 4 ---- drivers/rtc/s3c24x0_rtc.c | 4 ---- drivers/rtc/x1205.c | 4 ---- 24 files changed, 89 deletions(-) diff --git a/drivers/rtc/at91sam9_rtt.c b/drivers/rtc/at91sam9_rtt.c index da5bb3e..6f92660 100644 --- a/drivers/rtc/at91sam9_rtt.c +++ b/drivers/rtc/at91sam9_rtt.c @@ -27,8 +27,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - int rtc_get (struct rtc_time *tmp) { at91_rtt_t *rtt = (at91_rtt_t *) ATMEL_BASE_RTT; @@ -78,5 +76,3 @@ void rtc_reset (void) while (readl(&rtt->vr) != 0) ; } - -#endif diff --git a/drivers/rtc/davinci.c b/drivers/rtc/davinci.c index f03dc56..b6930bd 100644 --- a/drivers/rtc/davinci.c +++ b/drivers/rtc/davinci.c @@ -9,7 +9,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) int rtc_get(struct rtc_time *tmp) { struct davinci_rtc *rtc = (struct davinci_rtc *)DAVINCI_RTC_BASE; @@ -79,4 +78,3 @@ void rtc_reset(void) /* run RTC counter */ writel(0x01, &rtc->ctrl); } -#endif diff --git a/drivers/rtc/ds1302.c b/drivers/rtc/ds1302.c index 87ddd01..b94163f 100644 --- a/drivers/rtc/ds1302.c +++ b/drivers/rtc/ds1302.c @@ -9,8 +9,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - /* GPP Pins */ #define DATA 0x200 #define SCLK 0x400 @@ -328,5 +326,3 @@ int rtc_set(struct rtc_time *tmp) return 0; } - -#endif diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c index bd1e084..02d617e 100644 --- a/drivers/rtc/ds1306.c +++ b/drivers/rtc/ds1306.c @@ -19,8 +19,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - #define RTC_SECONDS 0x00 #define RTC_MINUTES 0x01 #define RTC_HOURS 0x02 @@ -437,5 +435,3 @@ static void rtc_write (unsigned char reg, unsigned char val) } #endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */ - -#endif diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index cdb088c..48220b4 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -51,8 +51,6 @@ enum ds_type { #ifndef CONFIG_DM_RTC -#if defined(CONFIG_CMD_DATE) - /*---------------------------------------------------------------------*/ #undef DEBUG_RTC @@ -204,8 +202,6 @@ static void rtc_write (uchar reg, uchar val) i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } -#endif /* CONFIG_CMD_DATE*/ - #endif /* !CONFIG_DM_RTC */ #ifdef CONFIG_DM_RTC diff --git a/drivers/rtc/ds1337.c b/drivers/rtc/ds1337.c index 9a0a214..9b31048 100644 --- a/drivers/rtc/ds1337.c +++ b/drivers/rtc/ds1337.c @@ -15,8 +15,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - /* * RTC register addresses */ @@ -190,5 +188,3 @@ static void rtc_write (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } - -#endif diff --git a/drivers/rtc/ds1374.c b/drivers/rtc/ds1374.c index bc27f61..5a2060f 100644 --- a/drivers/rtc/ds1374.c +++ b/drivers/rtc/ds1374.c @@ -18,8 +18,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - /*---------------------------------------------------------------------*/ #undef DEBUG_RTC #define DEBUG_RTC @@ -214,4 +212,3 @@ static void rtc_write_raw (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } -#endif diff --git a/drivers/rtc/ds164x.c b/drivers/rtc/ds164x.c index 7ee6214..f870789 100644 --- a/drivers/rtc/ds164x.c +++ b/drivers/rtc/ds164x.c @@ -20,8 +20,6 @@ #include -#if defined(CONFIG_CMD_DATE) - static uchar rtc_read(unsigned int addr ); static void rtc_write(unsigned int addr, uchar val); @@ -171,5 +169,3 @@ static void rtc_write( unsigned int addr, uchar val ) #endif *(volatile unsigned char*)(addr) = val; } - -#endif diff --git a/drivers/rtc/ds174x.c b/drivers/rtc/ds174x.c index b6daf59..94f943d 100644 --- a/drivers/rtc/ds174x.c +++ b/drivers/rtc/ds174x.c @@ -16,8 +16,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - static uchar rtc_read( unsigned int addr ); static void rtc_write( unsigned int addr, uchar val); @@ -172,5 +170,3 @@ static void rtc_write( unsigned int addr, uchar val ) #endif out8( addr, val ); } - -#endif diff --git a/drivers/rtc/ds3231.c b/drivers/rtc/ds3231.c index 0e66f6e..9352ff8 100644 --- a/drivers/rtc/ds3231.c +++ b/drivers/rtc/ds3231.c @@ -16,8 +16,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - /* * RTC register addresses */ @@ -166,5 +164,3 @@ static void rtc_write (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } - -#endif diff --git a/drivers/rtc/imxdi.c b/drivers/rtc/imxdi.c index 3c4797f..39920f1 100644 --- a/drivers/rtc/imxdi.c +++ b/drivers/rtc/imxdi.c @@ -17,8 +17,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - #include #include @@ -222,5 +220,3 @@ void rtc_reset(void) { di_init(); } - -#endif diff --git a/drivers/rtc/m41t11.c b/drivers/rtc/m41t11.c index e997152..960348b 100644 --- a/drivers/rtc/m41t11.c +++ b/drivers/rtc/m41t11.c @@ -29,8 +29,6 @@ #endif */ -#if defined(CONFIG_SYS_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE) - /* ------------------------------------------------------------------------- */ /* these are simple defines for the chip local to here so they aren't too @@ -167,4 +165,3 @@ void rtc_reset (void) val = val & 0x3F;/*turn off freq test keep calibration*/ i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1); } -#endif diff --git a/drivers/rtc/m41t60.c b/drivers/rtc/m41t60.c index 7846193..c84c8e1 100644 --- a/drivers/rtc/m41t60.c +++ b/drivers/rtc/m41t60.c @@ -20,8 +20,6 @@ #include #include -#if defined(CONFIG_SYS_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE) - /* * Convert between century and "century bits" (CB1 and CB0). These routines * assume years are in the range 1900 - 2299. @@ -237,4 +235,3 @@ void rtc_reset(void) } rtc_dump("end reset"); } -#endif /* CONFIG_RTC_M41T60 && CONFIG_SYS_I2C_RTC_ADDR && CONFIG_CMD_DATE */ diff --git a/drivers/rtc/m41t62.c b/drivers/rtc/m41t62.c index d53ef7d..1374383 100644 --- a/drivers/rtc/m41t62.c +++ b/drivers/rtc/m41t62.c @@ -18,8 +18,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - #define M41T62_REG_SSEC 0 #define M41T62_REG_SEC 1 #define M41T62_REG_MIN 2 @@ -130,5 +128,3 @@ void rtc_reset(void) val &= ~M41T80_ALHOUR_HT; i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1); } - -#endif diff --git a/drivers/rtc/m48t35ax.c b/drivers/rtc/m48t35ax.c index 0b035ce..1cc24cc 100644 --- a/drivers/rtc/m48t35ax.c +++ b/drivers/rtc/m48t35ax.c @@ -16,8 +16,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - static uchar rtc_read (uchar reg); static void rtc_write (uchar reg, uchar val); @@ -135,5 +133,3 @@ static void rtc_write (uchar reg, uchar val) *(unsigned char *) ((CONFIG_SYS_NVRAM_BASE_ADDR + CONFIG_SYS_NVRAM_SIZE - 8) + reg) = val; } - -#endif diff --git a/drivers/rtc/max6900.c b/drivers/rtc/max6900.c index f5c651b..b351865 100644 --- a/drivers/rtc/max6900.c +++ b/drivers/rtc/max6900.c @@ -15,8 +15,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - #ifndef CONFIG_SYS_I2C_RTC_ADDR #define CONFIG_SYS_I2C_RTC_ADDR 0x50 #endif @@ -104,5 +102,3 @@ int rtc_set (struct rtc_time *tmp) void rtc_reset (void) { } - -#endif diff --git a/drivers/rtc/mc146818.c b/drivers/rtc/mc146818.c index ee29c71..744c0f4 100644 --- a/drivers/rtc/mc146818.c +++ b/drivers/rtc/mc146818.c @@ -19,8 +19,6 @@ #define out8(p, v) outb(v, p) #endif -#if defined(CONFIG_CMD_DATE) - /* Set this to 1 to clear the CMOS RAM */ #define CLEAR_CMOS 0 @@ -195,7 +193,6 @@ static void mc146818_init(void) /* Clear any pending interrupts */ mc146818_read8(RTC_CONFIG_C); } -#endif /* CONFIG_CMD_DATE */ #ifdef CONFIG_DM_RTC diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c index 0ac8e4d..e10638e 100644 --- a/drivers/rtc/mcfrtc.c +++ b/drivers/rtc/mcfrtc.c @@ -6,8 +6,6 @@ #include -#if defined(CONFIG_CMD_DATE) - #include #include #include @@ -104,5 +102,3 @@ void rtc_reset(void) rtc->cr |= RTC_CR_SWR; } - -#endif /* CONFIG_MCFRTC && CONFIG_CMD_DATE */ diff --git a/drivers/rtc/mk48t59.c b/drivers/rtc/mk48t59.c index d29d5ce..8c90a70 100644 --- a/drivers/rtc/mk48t59.c +++ b/drivers/rtc/mk48t59.c @@ -70,8 +70,6 @@ void nvram_write(short dest, const void *src, size_t count) rtc_write(d++, *s++); } -#if defined(CONFIG_CMD_DATE) - /* ------------------------------------------------------------------------- */ int rtc_get (struct rtc_time *tmp) @@ -175,5 +173,3 @@ void rtc_set_watchdog(short multi, short res) wd_value = RTC_WDS | ((multi & 0x1F) << 2) | (res & 0x3); rtc_write(RTC_WATCHDOG, wd_value); } - -#endif diff --git a/drivers/rtc/pcf8563.c b/drivers/rtc/pcf8563.c index e2fa6b6..a839d6c 100644 --- a/drivers/rtc/pcf8563.c +++ b/drivers/rtc/pcf8563.c @@ -15,8 +15,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - static uchar rtc_read (uchar reg); static void rtc_write (uchar reg, uchar val); @@ -117,5 +115,3 @@ static void rtc_write (uchar reg, uchar val) { i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val); } - -#endif diff --git a/drivers/rtc/rs5c372.c b/drivers/rtc/rs5c372.c index c815c91..97ec001 100644 --- a/drivers/rtc/rs5c372.c +++ b/drivers/rtc/rs5c372.c @@ -24,7 +24,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) /* * Reads are always done starting with register 15, which requires some * jumping-through-hoops to access the data correctly. @@ -255,5 +254,3 @@ rtc_reset (void) if (!setup_done) rs5c372_enable(); } - -#endif diff --git a/drivers/rtc/rx8025.c b/drivers/rtc/rx8025.c index 1c2b92f..7bd9f8b 100644 --- a/drivers/rtc/rx8025.c +++ b/drivers/rtc/rx8025.c @@ -13,8 +13,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - /*---------------------------------------------------------------------*/ #undef DEBUG_RTC @@ -190,5 +188,3 @@ static void rtc_write (uchar reg, uchar val) printf("Error writing to RTC\n"); } - -#endif /* CONFIG_RTC_RX8025 && CONFIG_CMD_DATE */ diff --git a/drivers/rtc/s3c24x0_rtc.c b/drivers/rtc/s3c24x0_rtc.c index 1253085..96ea3cf 100644 --- a/drivers/rtc/s3c24x0_rtc.c +++ b/drivers/rtc/s3c24x0_rtc.c @@ -11,8 +11,6 @@ #include #include -#if (defined(CONFIG_CMD_DATE)) - #include #include @@ -149,5 +147,3 @@ void rtc_reset(void) writeb((readb(&rtc->rtccon) & ~0x06) | 0x08, &rtc->rtccon); writeb(readb(&rtc->rtccon) & ~(0x08 | 0x01), &rtc->rtccon); } - -#endif diff --git a/drivers/rtc/x1205.c b/drivers/rtc/x1205.c index e9d8390..ed6aaa5 100644 --- a/drivers/rtc/x1205.c +++ b/drivers/rtc/x1205.c @@ -22,8 +22,6 @@ #include #include -#if defined(CONFIG_CMD_DATE) - #define CCR_SEC 0 #define CCR_MIN 1 #define CCR_HOUR 2 @@ -160,5 +158,3 @@ void rtc_reset(void) * Nothing to do */ } - -#endif From 197005ae2a78f14e02d44096c3ecb59b921c0467 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 23:39:13 +0200 Subject: [PATCH 46/50] efi_loader: remove unused efi_get_time_init() Remove unused function efi_get_time_init(). Initialization of the RTC has to be done in board bring up not in the EFI subsystem. There is no RTC device in the UEFI spec. The RTC is only accessed through the runtime services. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- cmd/bootefi.c | 3 --- include/efi_loader.h | 1 - lib/efi_loader/efi_runtime.c | 5 ----- 3 files changed, 9 deletions(-) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index e57e70f..b60c151 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -90,9 +90,6 @@ efi_status_t efi_init_obj_list(void) ret = efi_reset_system_init(); if (ret != EFI_SUCCESS) goto out; - ret = efi_get_time_init(); - if (ret != EFI_SUCCESS) - goto out; out: efi_obj_list_initialized = ret; diff --git a/include/efi_loader.h b/include/efi_loader.h index 051f9c4..57ca550 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -434,7 +434,6 @@ efi_status_t efi_reset_system_init(void); efi_status_t __efi_runtime EFIAPI efi_get_time( struct efi_time *time, struct efi_time_cap *capabilities); -efi_status_t efi_get_time_init(void); #ifdef CONFIG_CMD_BOOTEFI_SELFTEST /* diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 1acb06a..8663875 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -174,11 +174,6 @@ efi_status_t __weak __efi_runtime EFIAPI efi_get_time( return EFI_DEVICE_ERROR; } -efi_status_t __weak efi_get_time_init(void) -{ - return EFI_SUCCESS; -} - struct efi_runtime_detach_list_struct { void *ptr; void *patchto; From 49de24559df6d87bf83ac1a836ddc2620c91c667 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 23:39:14 +0200 Subject: [PATCH 47/50] efi_loader: complete implementation of GetTime() Implement the missing parts of the GetTime() runtime service. Fill seconds. Fill daylight saving time flag correctly. Provide dummy values for capabilities. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 53 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 8663875..06958f2 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -117,24 +117,41 @@ static void EFIAPI efi_reset_system_boottime( while (1) { } } +/** + * efi_get_time_boottime - get current time + * + * This function implements the GetTime runtime service. + * See the Unified Extensible Firmware Interface (UEFI) specification + * for details. + * + * @time: pointer to structure to receive current time + * @capabilities: pointer to structure to receive RTC properties + * Return Value: status code + */ static efi_status_t EFIAPI efi_get_time_boottime( struct efi_time *time, struct efi_time_cap *capabilities) { -#if defined(CONFIG_CMD_DATE) && defined(CONFIG_DM_RTC) - struct rtc_time tm; +#ifdef CONFIG_DM_RTC + efi_status_t ret = EFI_SUCCESS; int r; + struct rtc_time tm; struct udevice *dev; EFI_ENTRY("%p %p", time, capabilities); - r = uclass_get_device(UCLASS_RTC, 0, &dev); - if (r) - return EFI_EXIT(EFI_DEVICE_ERROR); + if (!time) { + ret = EFI_INVALID_PARAMETER; + goto out; + } - r = dm_rtc_get(dev, &tm); - if (r) - return EFI_EXIT(EFI_DEVICE_ERROR); + r = uclass_get_device(UCLASS_RTC, 0, &dev); + if (!r) + r = dm_rtc_get(dev, &tm); + if (r) { + ret = EFI_DEVICE_ERROR; + goto out; + } memset(time, 0, sizeof(*time)); time->year = tm.tm_year; @@ -142,11 +159,23 @@ static efi_status_t EFIAPI efi_get_time_boottime( time->day = tm.tm_mday; time->hour = tm.tm_hour; time->minute = tm.tm_min; - time->daylight = tm.tm_isdst; - - return EFI_EXIT(EFI_SUCCESS); + time->second = tm.tm_sec; + time->daylight = EFI_TIME_ADJUST_DAYLIGHT; + if (tm.tm_isdst > 0) + time->daylight |= EFI_TIME_IN_DAYLIGHT; + time->timezone = EFI_UNSPECIFIED_TIMEZONE; + + if (capabilities) { + /* Set reasonable dummy values */ + capabilities->resolution = 1; /* 1 Hz */ + capabilities->accuracy = 100000000; /* 100 ppm */ + capabilities->sets_to_zero = false; + } +out: + return EFI_EXIT(ret); #else - return EFI_DEVICE_ERROR; + EFI_ENTRY("%p %p", time, capabilities); + return EFI_EXIT(EFI_DEVICE_ERROR); #endif } From 42e2b563f6faca0325d4c88f0a17742c02875020 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 23:39:15 +0200 Subject: [PATCH 48/50] efi_selftest: support printing leading zeroes Allow specifying the precision when printing integers, e.g. efi_st_printf("%.4u-%.2u-%.2u\n", year, month, day); Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/efi_selftest_console.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c index c3655a1..eb139c1 100644 --- a/lib/efi_selftest/efi_selftest_console.c +++ b/lib/efi_selftest/efi_selftest_console.c @@ -70,11 +70,12 @@ static void pointer(void *pointer, u16 **buf) /* * Print an unsigned 32bit value as decimal number to an u16 string * - * @value: value to be printed - * @buf: pointer to buffer address - * on return position of terminating zero word + * @value: value to be printed + * @prec: minimum number of digits to display + * @buf: pointer to buffer address + * on return position of terminating zero word */ -static void uint2dec(u32 value, u16 **buf) +static void uint2dec(u32 value, int prec, u16 **buf) { u16 *pos = *buf; int i; @@ -93,7 +94,7 @@ static void uint2dec(u32 value, u16 **buf) for (i = 0; i < 10; ++i) { /* Write current digit */ c = f >> 60; - if (c || pos != *buf) + if (c || pos != *buf || 10 - i <= prec) *pos++ = c + '0'; /* Eliminate current digit */ f &= 0xfffffffffffffff; @@ -109,11 +110,12 @@ static void uint2dec(u32 value, u16 **buf) /* * Print a signed 32bit value as decimal number to an u16 string * - * @value: value to be printed - * @buf: pointer to buffer address + * @value: value to be printed + * @prec: minimum number of digits to display + * @buf: pointer to buffer address * on return position of terminating zero word */ -static void int2dec(s32 value, u16 **buf) +static void int2dec(s32 value, int prec, u16 **buf) { u32 u; u16 *pos = *buf; @@ -124,7 +126,7 @@ static void int2dec(s32 value, u16 **buf) } else { u = value; } - uint2dec(u, &pos); + uint2dec(u, prec, &pos); *buf = pos; } @@ -143,6 +145,7 @@ void efi_st_printc(int color, const char *fmt, ...) u16 *pos = buf; const char *s; u16 *u; + int prec; va_start(args, fmt); @@ -172,12 +175,20 @@ void efi_st_printc(int color, const char *fmt, ...) break; case '%': ++c; + /* Parse precision */ + if (*c == '.') { + ++c; + prec = *c - '0'; + ++c; + } else { + prec = 0; + } switch (*c) { case '\0': --c; break; case 'd': - int2dec(va_arg(args, s32), &pos); + int2dec(va_arg(args, s32), prec, &pos); break; case 'p': ++c; @@ -209,7 +220,7 @@ void efi_st_printc(int color, const char *fmt, ...) *pos++ = *s; break; case 'u': - uint2dec(va_arg(args, u32), &pos); + uint2dec(va_arg(args, u32), prec, &pos); break; default: break; From 8c588a5886ef51c600cc816abc8bb366fe0a1877 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 7 Jul 2018 23:39:16 +0200 Subject: [PATCH 49/50] efi_selftest: unit test for GetTime() Provide a unit test for the GetTime() runtime service. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_selftest/Makefile | 1 + lib/efi_selftest/efi_selftest_rtc.c | 67 +++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 lib/efi_selftest/efi_selftest_rtc.c diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile index 1f3084c..590f90b 100644 --- a/lib/efi_selftest/Makefile +++ b/lib/efi_selftest/Makefile @@ -25,6 +25,7 @@ efi_selftest_exitbootservices.o \ efi_selftest_fdt.o \ efi_selftest_gop.o \ efi_selftest_manageprotocols.o \ +efi_selftest_rtc.o \ efi_selftest_snp.o \ efi_selftest_textinput.o \ efi_selftest_textoutput.o \ diff --git a/lib/efi_selftest/efi_selftest_rtc.c b/lib/efi_selftest/efi_selftest_rtc.c new file mode 100644 index 0000000..8d440dc --- /dev/null +++ b/lib/efi_selftest/efi_selftest_rtc.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * efi_selftest_rtc + * + * Copyright (c) 2018 Heinrich Schuchardt + * + * Test the real time clock runtime services. + */ + +#include + +#define EFI_ST_NO_RTC "Could not read real time clock\n" + +static struct efi_runtime_services *runtime; + +/* + * 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) +{ + runtime = systable->runtime; + return EFI_ST_SUCCESS; +} + +/* + * Execute unit test. + * + * Display current time. + * + * @return: EFI_ST_SUCCESS for success + */ +static int execute(void) +{ + efi_status_t ret; + struct efi_time tm; + + /* Display current time */ + ret = runtime->get_time(&tm, NULL); + if (ret != EFI_SUCCESS) { +#ifdef CONFIG_CMD_DATE + efi_st_error(EFI_ST_NO_RTC); + return EFI_ST_FAILURE; +#else + efi_st_todo(EFI_ST_NO_RTC); + return EFI_ST_SUCCESS; +#endif + } else { + efi_st_printf("Time according to real time clock: " + "%.4u-%.2u-%.2u %.2u:%.2u:%.2u\n", + tm.year, tm.month, tm.day, + tm.hour, tm.minute, tm.second); + } + + return EFI_ST_SUCCESS; +} + +EFI_UNIT_TEST(rtc) = { + .name = "real time clock", + .phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT, + .setup = setup, + .execute = execute, +}; From 0b8a88ab6aa24de0ef2bf1e8109409f71e770a8e Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 5 Jul 2018 19:43:50 +0200 Subject: [PATCH 50/50] MAINTAINERS: assign lib/charset.c lib/charset.c is only used by the EFI subsystem. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a2293b7..988fb1a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -368,6 +368,7 @@ F: doc/README.iscsi F: include/efi* F: include/pe.h F: include/asm-generic/pe.h +F: lib/charset.c F: lib/efi*/ F: test/py/tests/test_efi* F: cmd/bootefi.c