[PATCH 7/7] MIPS: Implement EFI supporting stuff
Jiaxun Yang
jiaxun.yang at flygoat.com
Fri May 17 18:32:58 CEST 2024
Implemented crt, ELF and EFI linking, ELF relocation handling
and other necessary bits for MIPS EFI.
Signed-off-by: Jiaxun Yang <jiaxun.yang at flygoat.com>
---
arch/mips/config.mk | 9 ++
arch/mips/lib/Makefile | 13 +++
arch/mips/lib/crt0_mips_efi.S | 239 +++++++++++++++++++++++++++++++++++++++++
arch/mips/lib/elf_mips_efi.lds | 113 +++++++++++++++++++
arch/mips/lib/reloc_mips_efi.c | 99 +++++++++++++++++
lib/efi_loader/Kconfig | 2 +-
6 files changed, 474 insertions(+), 1 deletion(-)
diff --git a/arch/mips/config.mk b/arch/mips/config.mk
index 745f03190e98..e970858c1e59 100644
--- a/arch/mips/config.mk
+++ b/arch/mips/config.mk
@@ -36,6 +36,10 @@ endif
PLATFORM_CPPFLAGS += -D__MIPS__
PLATFORM_ELFFLAGS += -B mips $(OBJCOPYFLAGS)
+EFI_LDS := elf_mips_efi.lds
+EFI_CRT0 := crt0_mips_efi.o
+EFI_RELOC := reloc_mips_efi.o
+
#
# From Linux arch/mips/Makefile
#
@@ -66,3 +70,8 @@ LDFLAGS_FINAL += --gc-sections
OBJCOPYFLAGS += -j .text -j .rodata -j .data -j __u_boot_list
LDFLAGS_STANDALONE += --gc-sections
+
+CFLAGS_EFI := -fPIE -mabicalls
+AFLAGS_EFI := -fPIE -mabicalls
+CFLAGS_NON_EFI := -mno-abicalls -fno-pic -fno-PIE
+AFLAGS_NON_EFI := -mno-abicalls -fno-pic -fno-PIE
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index e36dfd0547b5..eef663febe47 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -17,3 +17,16 @@ obj-$(CONFIG_CMD_GO) += boot.o
obj-$(CONFIG_SPL_BUILD) += spl.o
lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o udivdi3.o
+
+# For building EFI apps
+CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI)
+CFLAGS_REMOVE_$(EFI_CRT0) := $(CFLAGS_NON_EFI)
+AFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI)
+AFLAGS_REMOVE_$(EFI_CRT0) := $(CFLAGS_NON_EFI)
+
+CFLAGS_$(EFI_RELOC) := $(CFLAGS_EFI)
+CFLAGS_REMOVE_$(EFI_RELOC) := $(CFLAGS_NON_EFI)
+
+extra-$(CONFIG_CMD_BOOTEFI_HELLO_COMPILE) += $(EFI_CRT0) $(EFI_RELOC)
+extra-$(CONFIG_CMD_BOOTEFI_SELFTEST) += $(EFI_CRT0) $(EFI_RELOC)
+extra-$(CONFIG_EFI) += $(EFI_CRT0) $(EFI_RELOC)
diff --git a/arch/mips/lib/crt0_mips_efi.S b/arch/mips/lib/crt0_mips_efi.S
new file mode 100644
index 000000000000..84acee620d14
--- /dev/null
+++ b/arch/mips/lib/crt0_mips_efi.S
@@ -0,0 +1,239 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * crt0-efi-mips64el.S - PE/COFF header for MIPS64 EFI applications
+ *
+ * Copright (C) 2014 Linaro Ltd. <ard.biesheuvel at linaro.org>
+ * Copright (C) 2017 Heiher <r at hev.cc>
+ * Copright (C) 2024 Jiaxun Yang <jiaxun.yang at flygoat.com>
+ */
+
+#include <asm/asm.h>
+#include <asm-generic/pe.h>
+
+#if __mips == 64
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define PE_MACHINE IMAGE_FILE_MACHINE_R4000
+#else
+#define PE_MACHINE IMAGE_FILE_MACHINE_R4000_BE
+#endif
+#define PE_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC
+#define IMG_CHARACTERISTICS \
+ (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED | \
+ IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
+ IMAGE_FILE_LARGE_ADDRESS_AWARE | \
+ IMAGE_FILE_DEBUG_STRIPPED)
+#else
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define PE_MACHINE IMAGE_FILE_MACHINE_R3000
+#else
+#define PE_MACHINE IMAGE_FILE_MACHINE_R3000_BE
+#endif
+#define PE_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC
+#define IMG_CHARACTERISTICS \
+ (IMAGE_FILE_EXECUTABLE_IMAGE | \
+ IMAGE_FILE_LINE_NUMS_STRIPPED | \
+ IMAGE_FILE_LOCAL_SYMS_STRIPPED | \
+ IMAGE_FILE_DEBUG_STRIPPED)
+#endif
+
+
+ .section .text.head
+
+ /*
+ * Magic "MZ" signature for PE/COFF
+ */
+ .globl ImageBase
+ImageBase:
+ .2byte IMAGE_DOS_SIGNATURE /* 'MZ' */
+ .skip 58 /* 'MZ' + pad + offset == 64 */
+ .4byte pe_header - ImageBase /* Offset to the PE header */
+pe_header:
+ .4byte IMAGE_NT_SIGNATURE /* 'PE' */
+coff_header:
+ .2byte PE_MACHINE /* Machine Magic */
+ .2byte 3 /* nr_sections */
+ .4byte 0 /* TimeDateStamp */
+ .4byte 0 /* PointerToSymbolTable */
+ .4byte 0 /* NumberOfSymbols */
+ .2byte section_table - optional_header /* SizeOfOptionalHeader */
+ .2byte IMG_CHARACTERISTICS /* Characteristics */
+
+optional_header:
+ .2byte PE_MAGIC /* PE32(+) format */
+ .byte 0x02 /* MajorLinkerVersion */
+ .byte 0x14 /* MinorLinkerVersion */
+ .4byte _edata - _start /* SizeOfCode */
+ .4byte 0 /* SizeOfInitializedData */
+ .4byte 0 /* SizeOfUninitializedData */
+ .4byte _start - ImageBase /* AddressOfEntryPoint */
+ .4byte _start - ImageBase /* BaseOfCode */
+#if __mips != 64
+ .4byte 0 /* BaseOfData */
+#endif
+
+extra_header_fields:
+#if __mips == 64
+ .8byte 0 /* ImageBase */
+#else
+ .4byte 0 /* ImageBase */
+#endif
+ .4byte 0x20 /* SectionAlignment */
+ .4byte 0x8 /* FileAlignment */
+ .2byte 0 /* MajorOperatingSystemVersion */
+ .2byte 0 /* MinorOperatingSystemVersion */
+ .2byte 1 /* MajorImageVersion */
+ .2byte 0 /* MinorImageVersion */
+ .2byte 0 /* MajorSubsystemVersion */
+ .2byte 0 /* MinorSubsystemVersion */
+ .4byte 0 /* Win32VersionValue */
+
+ .4byte _edata - ImageBase /* SizeOfImage */
+
+ /*
+ * Everything before the kernel image is considered part of the header
+ */
+ .4byte _start - ImageBase /* SizeOfHeaders */
+ .4byte 0 /* CheckSum */
+ .short IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */
+#if CONFIG_VENDOR_EFI
+ .short 0 /* DllCharacteristics */
+#else
+ .short IMAGE_DLLCHARACTERISTICS_NX_COMPAT
+#endif
+#if __mips == 64
+ .8byte 0 /* SizeOfStackReserve */
+ .8byte 0 /* SizeOfStackCommit */
+ .8byte 0 /* SizeOfHeapReserve */
+ .8byte 0 /* SizeOfHeapCommit */
+#else
+ .4byte 0 /* SizeOfStackReserve */
+ .4byte 0 /* SizeOfStackCommit */
+ .4byte 0 /* SizeOfHeapReserve */
+ .4byte 0 /* SizeOfHeapCommit */
+#endif
+ .4byte 0 /* LoaderFlags */
+ .4byte 0x6 /* LoaderFlags */
+
+ .4byte 0 /* ExportTable */
+ .4byte 0 /* ImportTable */
+ .4byte 0 /* ResourceTable */
+ .4byte 0 /* ExceptionTable */
+ .4byte 0 /* CertificationTable */
+ .4byte 0 /* BaseRelocationTable */
+
+ // Section table
+section_table:
+
+ /*
+ * The EFI application loader requires a relocation section
+ * because EFI applications must be relocatable. This is a
+ * dummy section as far as we are concerned.
+ */
+ .ascii ".reloc"
+ .byte 0
+ .byte 0 /* end of 0 padding of section name */
+ .4byte 0
+ .4byte 0
+ .4byte 0 /* SizeOfRawData */
+ .4byte 0 /* PointerToRawData */
+ .4byte 0 /* PointerToRelocations */
+ .4byte 0 /* PointerToLineNumbers */
+ .short 0 /* NumberOfRelocations */
+ .short 0 /* NumberOfLineNumbers */
+ .4byte 0x42100040 /* Characteristics (section flags) */
+
+ .ascii ".text"
+ .byte 0
+ .byte 0
+ .byte 0 /* end of 0 padding of section name */
+ .4byte _etext - _start /* VirtualSize */
+ .4byte _start - ImageBase /* VirtualAddress */
+ .4byte _etext - _start /* SizeOfRawData */
+ .4byte _start - ImageBase /* PointerToRawData */
+
+ .4byte 0 /* PointerToRelocations (0 for executables) */
+ .4byte 0 /* PointerToLineNumbers (0 for executables) */
+ .2byte 0 /* NumberOfRelocations (0 for executables) */
+ .2byte 0 /* NumberOfLineNumbers (0 for executables) */
+ /* Characteristics (section flags) */
+ .4byte (IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_EXECUTE | \
+ IMAGE_SCN_CNT_CODE)
+
+ .ascii ".data"
+ .byte 0
+ .byte 0
+ .byte 0 /* end of 0 padding of section name */
+ .4byte _data_size /* VirtualSize */
+ .4byte _etext - ImageBase /* VirtualAddress */
+ .4byte _data_size /* SizeOfRawData */
+ .4byte _etext - ImageBase /* PointerToRawData */
+ .4byte 0 /* PointerToRelocations */
+ .4byte 0 /* PointerToLineNumbers */
+ .2byte 0 /* NumberOfRelocations */
+ .2byte 0 /* NumberOfLineNumbers */
+ /* Characteristics (section flags) */
+ .4byte (IMAGE_SCN_MEM_WRITE | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_CNT_INITIALIZED_DATA)
+
+ .align 4
+
+ .globl _start
+ .ent _start
+ .type _start, @function
+_start:
+ LONG_ADDIU $sp, -(LONGSIZE * 4)
+ LONG_S $ra, ($sp)
+
+ // Get pc & gp
+ .set push
+ .set noreorder
+ .align LONGLOG
+ bal 1f
+ LONG_S $gp, (1 * LONGSIZE)($sp) /* Delay slot */
+_pc:
+ PTR _gp
+ PTR _DYNAMIC
+ PTR _relocate
+1:
+ .set pop
+ // pc in ra
+ PTR_L $gp, ($ra)
+ PTR_LI $t0, _pc
+ PTR_SUBU $gp, $t0
+ PTR_ADDU $gp, $ra
+
+ LONG_S $a0, (2 * LONGSIZE)($sp)
+ LONG_S $a1, (3 * LONGSIZE)($sp)
+
+ /* a0: ImageBase */
+ PTR_LI $t1, ImageBase - _pc
+ PTR_ADDU $a0, $ra, $t1
+ /* a1: DynamicSection */
+ PTR_L $t1, (1 * PTRSIZE)($ra)
+ PTR_SUBU $t1, $t0
+ PTR_ADDU $a1, $ra, $t1
+ /* call _relocate */
+ PTR_L $t1, (2 * PTRSIZE)($ra)
+ PTR_SUBU $t1, $t0
+ PTR_ADDU $t9, $ra, $t1
+ jalr $t9
+ /* Return early */
+ bnez $v0, 1b
+
+ /* a0: ImageHandle */
+ LONG_L $a0, (2 * LONGSIZE)($sp)
+ /* a1: SystemTable */
+ LONG_L $a1, (3 * LONGSIZE)($sp)
+ /* Load the entry point */
+ PTR_LA $t9, efi_main
+ jalr $t9
+
+1:
+ LONG_L $gp, (1 * LONGSIZE)($sp)
+ LONG_L $ra, ($sp)
+ LONG_ADDIU $sp, (LONGSIZE * 4)
+ jr $ra
+.end _start
diff --git a/arch/mips/lib/elf_mips_efi.lds b/arch/mips/lib/elf_mips_efi.lds
new file mode 100644
index 000000000000..31039c3d4843
--- /dev/null
+++ b/arch/mips/lib/elf_mips_efi.lds
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * U-Boot MIPS EFI linker script
+ *
+ * Modified from elf_mips64el_efi.lds in gnu-efi
+ */
+
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+
+SECTIONS
+{
+ .text 0x0 : {
+ _text = .;
+ *(.text.head)
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t.*)
+ *(.plt)
+ . = ALIGN(16);
+ }
+ _etext = .;
+ _text_size = _etext - _text;
+ . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
+ .dynamic : { *(.dynamic) }
+ . = ALIGN(4096);
+ .data :
+ {
+ _data = .;
+ *(.sdata)
+ *(.data)
+ *(.data1)
+ *(.data.*)
+ *(.got.plt)
+ HIDDEN (_gp = ALIGN (16) + 0x7ff0);
+ *(.got)
+
+ /*
+ * Note that these aren't the using the GNU "CONSTRUCTOR" output section
+ * command, so they don't start with a size. Because of p2align and the
+ * end/END definitions, and the fact that they're mergeable, they can also
+ * have NULLs which aren't guaranteed to be at the end.
+ */
+ . = ALIGN(16);
+ __init_array_start = .;
+ *(SORT(.init_array.*))
+ *(.init_array)
+ __init_array_end = .;
+ . = ALIGN(16);
+ __CTOR_LIST__ = .;
+ *(SORT(.ctors.*))
+ *(.ctors)
+ __CTOR_END__ = .;
+ . = ALIGN(16);
+ __DTOR_LIST__ = .;
+ *(SORT(.dtors.*))
+ *(.dtors)
+ __DTOR_END__ = .;
+ . = ALIGN(16);
+ __fini_array_start = .;
+ *(SORT(.fini_array.*))
+ *(.fini_array)
+ __fini_array_end = .;
+
+ /* the EFI loader doesn't seem to like a .bss section, so we stick
+ it all into .data: */
+ . = ALIGN(16);
+ _bss = .;
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(16);
+ _bss_end = .;
+ }
+
+ . = ALIGN(4096);
+ .rel :
+ {
+ *(.rel.text*)
+ *(.rel.data*)
+ *(.rel.got)
+ *(.rel.dyn)
+ *(.rel.stab)
+ *(.rel.init_array*)
+ *(.rel.fini_array*)
+ *(.rel.ctors*)
+ *(.rel.dtors*)
+ }
+ . = ALIGN(4096);
+ .rel.plt : { *(.rel.plt) }
+ . = ALIGN(4096);
+ .rodata : { *(.rodata*) }
+ _edata = .;
+ _data_size = _edata - _etext;
+
+ . = ALIGN(4096);
+ .dynsym : { *(.dynsym) }
+ . = ALIGN(4096);
+ .dynstr : { *(.dynstr) }
+ . = ALIGN(4096);
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ . = DATA_SEGMENT_END (.);
+ /DISCARD/ :
+ {
+ *(.rel.reloc)
+ *(.eh_frame)
+ *(.MIPS.abiflags)
+ *(.note.GNU-stack)
+ }
+ .comment 0 : { *(.comment) }
+}
diff --git a/arch/mips/lib/reloc_mips_efi.c b/arch/mips/lib/reloc_mips_efi.c
new file mode 100644
index 000000000000..ee4f95d9e783
--- /dev/null
+++ b/arch/mips/lib/reloc_mips_efi.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * reloc_mips64el.c - position independent MIPS64 ELF shared object relocator
+ *
+ * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel at linaro.org>
+ * Copyright (C) 1999 Hewlett-Packard Co.
+ * Contributed by David Mosberger <davidm at hpl.hp.com>.
+ * Copyright (C) 2017 Lemote Co.
+ * Contributed by Heiher <r at hev.cc>
+ * Copyright (C) 2024 Jiaxun Yang <jiaxun.yang at flygoat.com>
+ */
+
+#include <efi.h>
+#include <elf.h>
+
+#include <asm/byteorder.h>
+
+#if __mips == 64
+#define Elf_Dyn Elf64_Dyn
+#define Elf_Rel Elf64_Rel
+#define ELF_R_TYPE ELF64_R_TYPE
+#define R_MIPS_RELATIVE ((R_MIPS_64 << 8) | R_MIPS_REL32)
+#define swabl(x) swab64(x)
+#else
+#define Elf_Dyn Elf32_Dyn
+#define Elf_Rel Elf32_Rel
+#define ELF_R_TYPE ELF32_R_TYPE
+#define R_MIPS_RELATIVE R_MIPS_REL32
+#define swabl(x) swab32(x)
+#endif
+
+efi_status_t EFIAPI _relocate(long ldbase, Elf_Dyn *dyn)
+{
+ long relsz = 0, relent = 0, gotsz = 0;
+ Elf_Rel *rel = 0;
+ unsigned long *addr = 0;
+ int i;
+
+ for (i = 0; dyn[i].d_tag != DT_NULL; ++i) {
+ switch (dyn[i].d_tag) {
+ case DT_REL:
+ rel = (Elf_Rel *)
+ ((unsigned long)dyn[i].d_un.d_ptr
+ + ldbase);
+ break;
+
+ case DT_RELSZ:
+ relsz = dyn[i].d_un.d_val;
+ break;
+
+ case DT_RELENT:
+ relent = dyn[i].d_un.d_val;
+ break;
+
+ case DT_PLTGOT:
+ addr = (unsigned long *)
+ ((unsigned long)dyn[i].d_un.d_ptr
+ + ldbase);
+ break;
+
+ case DT_MIPS_LOCAL_GOTNO:
+ gotsz = dyn[i].d_un.d_val;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if ((!rel && relent == 0) && (!addr && gotsz == 0))
+ return EFI_SUCCESS;
+
+ if ((!rel && relent != 0) || (!addr && gotsz != 0))
+ return EFI_LOAD_ERROR;
+
+ while (gotsz > 0) {
+ *addr += ldbase;
+ addr += 1;
+ gotsz--;
+ }
+
+ while (relsz > 0) {
+ /* apply the relocs */
+ switch (ELF_R_TYPE(swabl(rel->r_info))) {
+ case R_MIPS_NONE:
+ break;
+ case R_MIPS_RELATIVE:
+ addr = (unsigned long *)(ldbase + rel->r_offset);
+ *addr += ldbase;
+ break;
+ default:
+ break;
+ }
+ rel = (Elf_Rel *)((char *) rel + relent);
+ relsz -= relent;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index bc5ae9086ea2..a9b006fa6d24 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -5,7 +5,7 @@ config EFI_LOADER
SYS_CPU = arm1176 || \
SYS_CPU = armv7 || \
SYS_CPU = armv8) || \
- X86 || RISCV || SANDBOX)
+ X86 || RISCV || MIPS || SANDBOX)
# 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
--
2.34.1
More information about the U-Boot
mailing list