Implemented crt, ELF and EFI linking, ELF relocation handling and other necessary bits for MIPS EFI.
Signed-off-by: Jiaxun Yang <jiaxun.y...@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.biesheu...@linaro.org> + * Copright (C) 2017 Heiher <r...@hev.cc> + * Copright (C) 2024 Jiaxun Yang <jiaxun.y...@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.biesheu...@linaro.org> + * Copyright (C) 1999 Hewlett-Packard Co. + * Contributed by David Mosberger <dav...@hpl.hp.com>. + * Copyright (C) 2017 Lemote Co. + * Contributed by Heiher <r...@hev.cc> + * Copyright (C) 2024 Jiaxun Yang <jiaxun.y...@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