From de452c04c391948dbff68029e900fbb10dd5efb2 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 5 Jun 2018 19:20:32 +0200 Subject: riscv: Add support for HI20 PE relocations The PE standard allows for HI20/LOW12 relocations. Within the efi_loader target we always know that our relocation target is 4k aligned, so we don't need to worry about the LOW12 part. This patch adds support for the respective relocations. With this and a few grub patches I have cooking in parallel I'm able to run grub on RISC-V. Signed-off-by: Alexander Graf --- include/pe.h | 3 +++ lib/efi_loader/efi_image_loader.c | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/pe.h b/include/pe.h index d73eb14..36e1908 100644 --- a/include/pe.h +++ b/include/pe.h @@ -201,10 +201,13 @@ typedef struct _IMAGE_RELOCATION #define IMAGE_REL_BASED_MIPS_JMPADDR 5 #define IMAGE_REL_BASED_ARM_MOV32A 5 /* yes, 5 too */ #define IMAGE_REL_BASED_ARM_MOV32 5 /* yes, 5 too */ +#define IMAGE_REL_BASED_RISCV_HI20 5 /* yes, 5 too */ #define IMAGE_REL_BASED_SECTION 6 #define IMAGE_REL_BASED_REL 7 #define IMAGE_REL_BASED_ARM_MOV32T 7 /* yes, 7 too */ #define IMAGE_REL_BASED_THUMB_MOV32 7 /* yes, 7 too */ +#define IMAGE_REL_BASED_RISCV_LOW12I 7 /* yes, 7 too */ +#define IMAGE_REL_BASED_RISCV_LOW12S 8 #define IMAGE_REL_BASED_MIPS_JMPADDR16 9 #define IMAGE_REL_BASED_IA64_IMM64 9 /* yes, 9 too */ #define IMAGE_REL_BASED_DIR64 10 diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 3cffe9e..ecdb77e 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -126,6 +126,20 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel, case IMAGE_REL_BASED_DIR64: *x64 += (uint64_t)delta; break; +#ifdef __riscv + case IMAGE_REL_BASED_RISCV_HI20: + *x32 = ((*x32 & 0xfffff000) + (uint32_t)delta) | + (*x32 & 0x00000fff); + break; + case IMAGE_REL_BASED_RISCV_LOW12I: + case IMAGE_REL_BASED_RISCV_LOW12S: + /* We know that we're 4k aligned */ + if (delta & 0xfff) { + printf("Unsupported reloc offset\n"); + return EFI_LOAD_ERROR; + } + break; +#endif default: printf("Unknown Relocation off %x type %x\n", offset, type); -- cgit v1.1 From e4679489c3fc12f87ce64347d2cebd5090ca9619 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Sun, 10 Jun 2018 21:51:02 +0200 Subject: efi_loader: Convert runtime reset from switch to if statements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We currently handle the UEFI runtime reset / power off case handling via a switch statement. Compilers (gcc in my case) may opt to handle these via jump tables which they may conveniently put into .rodata which is not part of the runtime section, so it will be unreachable when executed. Fix this by just converting the switch statement into an if/else statement. It produces smaller code that is faster and also correct because we no longer refer .rodata from efi runtime code. Reported-by: Andreas Färber Signed-off-by: Alexander Graf --- arch/arm/cpu/armv8/fwcall.c | 11 ++++------- arch/arm/mach-bcm283x/reset.c | 11 ++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/arch/arm/cpu/armv8/fwcall.c b/arch/arm/cpu/armv8/fwcall.c index c5aa41a..0ba3dad 100644 --- a/arch/arm/cpu/armv8/fwcall.c +++ b/arch/arm/cpu/armv8/fwcall.c @@ -143,15 +143,12 @@ void __efi_runtime EFIAPI efi_reset_system( efi_status_t reset_status, unsigned long data_size, void *reset_data) { - switch (reset_type) { - case EFI_RESET_COLD: - case EFI_RESET_WARM: - case EFI_RESET_PLATFORM_SPECIFIC: + if (reset_type == EFI_RESET_COLD || + reset_type == EFI_RESET_WARM || + reset_type == EFI_RESET_PLATFORM_SPECIFIC) { psci_system_reset(); - break; - case EFI_RESET_SHUTDOWN: + } else if (reset_type == EFI_RESET_SHUTDOWN) { psci_system_off(); - break; } while (1) { } diff --git a/arch/arm/mach-bcm283x/reset.c b/arch/arm/mach-bcm283x/reset.c index f8a1775..7712d46 100644 --- a/arch/arm/mach-bcm283x/reset.c +++ b/arch/arm/mach-bcm283x/reset.c @@ -59,13 +59,11 @@ void __efi_runtime EFIAPI efi_reset_system( { u32 val; - switch (reset_type) { - case EFI_RESET_COLD: - case EFI_RESET_WARM: - case EFI_RESET_PLATFORM_SPECIFIC: + if (reset_type == EFI_RESET_COLD || + reset_type == EFI_RESET_WARM || + reset_type == EFI_RESET_PLATFORM_SPECIFIC) { reset_cpu(0); - break; - case EFI_RESET_SHUTDOWN: + } else if (reset_type == EFI_RESET_SHUTDOWN) { /* * We set the watchdog hard reset bit here to distinguish this reset * from the normal (full) reset. bootcode.bin will not reboot after a @@ -76,7 +74,6 @@ void __efi_runtime EFIAPI efi_reset_system( val |= BCM2835_WDOG_RSTS_RASPBERRYPI_HALT; writel(val, &wdog_regs->rsts); reset_cpu(0); - break; } while (1) { } -- cgit v1.1 From 2d2b5b2d007769ba48fd31223997df1d6b662c78 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jun 2018 23:26:40 -0600 Subject: efi: Add a comment about duplicated ELF constants These constants are defined in arch-specific code but redefined here. Add a TODO to clean this up. Signed-off-by: Simon Glass Reviewed-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- lib/efi_loader/efi_runtime.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index 65f2bcf..4874eb6 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -28,6 +28,10 @@ static efi_status_t __efi_runtime EFIAPI efi_unimplemented(void); static efi_status_t __efi_runtime EFIAPI efi_device_error(void); 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) #define R_RELATIVE 1027 #define R_MASK 0xffffffffULL -- cgit v1.1 From 44ab2d325b79d3ce6123495c5ce52410655a58fb Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 9 Jun 2018 17:50:18 +0200 Subject: efi_loader: avoid initializer element is not constant When building with -pedantic the current definition of EFI_GUID() causes an error 'initializer element is not constant'. Currently EFI_GUID() is used both as an anonymous constant and as an intializer. A conversion to efi_guid_t is not allowable when using EFI_GUID() as an initializer. But it is needed when using it as an anonymous constant. We should not use EFI_GUID() for anything but an initializer. So let's introduce a variable where needed and remove the conversion. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- disk/part_efi.c | 9 +++++++-- include/efi.h | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/disk/part_efi.c b/disk/part_efi.c index 5c1039f..2945892 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -23,6 +23,11 @@ DECLARE_GLOBAL_DATA_PTR; +/* + * GUID for basic data partions. + */ +static const efi_guid_t partition_basic_data_guid = PARTITION_BASIC_DATA_GUID; + #ifdef CONFIG_HAVE_BLOCK_DEVICE /** * efi_crc32() - EFI version of crc32 function @@ -502,12 +507,12 @@ int gpt_fill_pte(struct blk_desc *dev_desc, } else { /* default partition type GUID */ memcpy(bin_type_guid, - &PARTITION_BASIC_DATA_GUID, 16); + &partition_basic_data_guid, 16); } #else /* partition type GUID */ memcpy(gpt_e[i].partition_type_guid.b, - &PARTITION_BASIC_DATA_GUID, 16); + &partition_basic_data_guid, 16); #endif #if CONFIG_IS_ENABLED(PARTITION_UUIDS) diff --git a/include/efi.h b/include/efi.h index 98bddba..e30a3c5 100644 --- a/include/efi.h +++ b/include/efi.h @@ -89,12 +89,11 @@ typedef u64 efi_virtual_addr_t; typedef void *efi_handle_t; #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ - ((efi_guid_t) \ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \ ((a) >> 24) & 0xff, \ (b) & 0xff, ((b) >> 8) & 0xff, \ (c) & 0xff, ((c) >> 8) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } }) + (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } } /* Generic EFI table header */ struct efi_table_hdr { -- cgit v1.1 From 2f61b13d6acba787b00598d519c85222e993e4ca Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sat, 2 Jun 2018 19:00:41 +0200 Subject: efi_loader: avoid make race condition When U-Boot is built with 'make -j' there is not guarantee that targets in directory arch/ are built before targets in directory lib/. The current build instruction for EFI binaries in lib/ rely on dependencies in arch/. If $(EFI_CRT0) or $(EFI_RELOC) is not yet built before trying to build %.efi an error *** No rule to make target '%.efi' occurs. With the patch separate copies of $(EFI_CRT0) and $(EFI_RELOC) named efi_crt0.o and efi_reloc.o are built in lib/efi_loader and lib/efi_selftest. Signed-off-by: Heinrich Schuchardt Signed-off-by: Alexander Graf --- scripts/Makefile.lib | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index ef7604c..461f1c7 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -385,8 +385,14 @@ cmd_efi_ld = $(LD) -nostdlib -znocombreloc -T $(EFI_LDS_PATH) -shared \ EFI_LDS_PATH = $(srctree)/arch/$(ARCH)/lib/$(EFI_LDS) -$(obj)/%_efi.so: $(obj)/%.o arch/$(ARCH)/lib/$(EFI_CRT0) \ - arch/$(ARCH)/lib/$(EFI_RELOC) +$(obj)/efi_crt0.o: $(srctree)/arch/$(ARCH)/lib/$(EFI_CRT0:.o=.S) + $(call if_changed_dep,as_o_S) + +$(obj)/efi_reloc.o: $(srctree)/arch/$(ARCH)/lib/$(EFI_RELOC:.o=.c) $(recordmcount_source) FORCE + $(call cmd,force_checksrc) + $(call if_changed_rule,cc_o_c) + +$(obj)/%_efi.so: $(obj)/%.o $(obj)/efi_crt0.o $(obj)/efi_reloc.o $(call cmd,efi_ld) # ACPI -- cgit v1.1 From 58bc69d20aaf2e32e93e977d708fe6a1af0ad6d1 Mon Sep 17 00:00:00 2001 From: Alexander Graf Date: Tue, 12 Jun 2018 10:21:16 +0200 Subject: efi_loader: Allocate memory handle for mem dp When we boot using memdp (bootefi on an address without previous load that populates the device path) then the memory device path we pass in is not backed by any handle. That can result in weird effects. For example grub gets very grumpy about this inside the efi_net module and just loops endlessly. So let's expose a simple handle that the memory device path is backed on. That way any code that looks for the device the dp is on, finds one. Signed-off-by: Alexander Graf --- cmd/bootefi.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 707d159..f55a40d 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -263,6 +263,7 @@ static efi_status_t do_bootefi_exec(void *efi, { struct efi_loaded_image loaded_image_info = {}; struct efi_object loaded_image_info_obj = {}; + struct efi_object mem_obj = {}; struct efi_device_path *memdp = NULL; efi_status_t ret; @@ -279,6 +280,12 @@ static efi_status_t do_bootefi_exec(void *efi, /* actual addresses filled in after efi_load_pe() */ memdp = efi_dp_from_mem(0, 0, 0); device_path = image_path = memdp; + efi_add_handle(&mem_obj); + + ret = efi_add_protocol(mem_obj.handle, &efi_guid_device_path, + device_path); + if (ret != EFI_SUCCESS) + goto exit; } else { assert(device_path && image_path); } @@ -343,6 +350,8 @@ static efi_status_t do_bootefi_exec(void *efi, exit: /* image has returned, loaded-image obj goes *poof*: */ list_del(&loaded_image_info_obj.link); + if (mem_obj.handle) + list_del(&mem_obj.link); return ret; } -- cgit v1.1