Implement crt, reloc, linker scripts, wire things up in Makefiles and Kconfig.
Signed-off-by: Jiaxun Yang <jiaxun.y...@flygoat.com> --- arch/loongarch/config.mk | 4 + arch/loongarch/lib/Makefile | 12 ++ arch/loongarch/lib/crt0_loongarch_efi.S | 182 +++++++++++++++++++++++++++++++ arch/loongarch/lib/elf_loongarch_efi.lds | 76 +++++++++++++ arch/loongarch/lib/reloc_loongarch_efi.c | 107 ++++++++++++++++++ lib/efi_loader/Kconfig | 2 +- 6 files changed, 382 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/config.mk b/arch/loongarch/config.mk index 7c247400e361..bae4566e9b62 100644 --- a/arch/loongarch/config.mk +++ b/arch/loongarch/config.mk @@ -21,3 +21,7 @@ endif PLATFORM_CPPFLAGS += -fpic PLATFORM_RELFLAGS += -fno-common -ffunction-sections -fdata-sections LDFLAGS_u-boot += --gc-sections -static -pie + +EFI_LDS := elf_loongarch_efi.lds +EFI_CRT0 := crt0_loongarch_efi.o +EFI_RELOC := reloc_loongarch_efi.o diff --git a/arch/loongarch/lib/Makefile b/arch/loongarch/lib/Makefile index e65e66357a9b..17d2b1160b41 100644 --- a/arch/loongarch/lib/Makefile +++ b/arch/loongarch/lib/Makefile @@ -12,3 +12,15 @@ ifeq ($(CONFIG_$(SPL_)SYSRESET),) obj-y += reset.o endif obj-y += setjmp.o + +# For building EFI apps +CFLAGS_NON_EFI := -fstack-protector-strong +CFLAGS_$(EFI_CRT0) := $(CFLAGS_EFI) +CFLAGS_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/loongarch/lib/crt0_loongarch_efi.S b/arch/loongarch/lib/crt0_loongarch_efi.S new file mode 100644 index 000000000000..5be47045ad8a --- /dev/null +++ b/arch/loongarch/lib/crt0_loongarch_efi.S @@ -0,0 +1,182 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * crt0-efi-loongarch.S - PE/COFF header for LoongArch EFI applications + * + * Copright (C) 2024 Jiaxun Yang <jiaxun.y...@flygoat.com> + */ + +#include <asm-generic/pe.h> +#include <asm/asm.h> + +#ifdef __loongarch64 +#define PE_MACHINE IMAGE_FILE_MACHINE_LOONGARCH64 +#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 +#define PE_MACHINE IMAGE_FILE_MACHINE_LOONGARCH32 +#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: + .short IMAGE_DOS_SIGNATURE /* 'MZ' */ + .skip 58 + .long pe_header - ImageBase /* Offset to the PE header */ +pe_header: + .long IMAGE_NT_SIGNATURE /* 'PE' */ +coff_header: + .short PE_MACHINE /* LoongArch 64/32-bit */ + .short 3 /* nr_sections */ + .long 0 /* TimeDateStamp */ + .long 0 /* PointerToSymbolTable */ + .long 0 /* NumberOfSymbols */ + .short section_table - optional_header /* SizeOfOptionalHeader */ + .short IMG_CHARACTERISTICS /* Characteristics */ +optional_header: + .short PE_MAGIC /* PE32(+) format */ + .byte 0x02 /* MajorLinkerVersion */ + .byte 0x14 /* MinorLinkerVersion */ + .long _edata - _start /* SizeOfCode */ + .long 0 /* SizeOfInitializedData */ + .long 0 /* SizeOfUninitializedData */ + .long _start - ImageBase /* AddressOfEntryPoint */ + .long _start - ImageBase /* BaseOfCode */ +#ifndef __loongarch64 + .long 0 /* BaseOfData */ +#endif + +extra_header_fields: + LONG 0 + .long 0x200 /* SectionAlignment */ + .long 0x200 /* FileAlignment */ + .short 0 /* MajorOperatingSystemVersion */ + .short 0 /* MinorOperatingSystemVersion */ + .short 1 /* MajorImageVersion */ + .short 0 /* MinorImageVersion */ + .short 0 /* MajorSubsystemVersion */ + .short 0 /* MinorSubsystemVersion */ + .long 0 /* Win32VersionValue */ + + .long _edata - ImageBase /* SizeOfImage */ + + /* + * Everything before the kernel image is considered part of the header + */ + .long _start - ImageBase /* SizeOfHeaders */ + .long 0 /* CheckSum */ + .short IMAGE_SUBSYSTEM_EFI_APPLICATION /* Subsystem */ +#if CONFIG_VENDOR_EFI + .short 0 /* DllCharacteristics */ +#else + .short IMAGE_DLLCHARACTERISTICS_NX_COMPAT +#endif + LONG 0 /* SizeOfStackReserve */ + LONG 0 /* SizeOfStackCommit */ + LONG 0 /* SizeOfHeapReserve */ + LONG 0 /* SizeOfHeapCommit */ + + .long 0 /* LoaderFlags */ + .long 0x6 /* NumberOfRvaAndSizes */ + + .quad 0 /* ExportTable */ + .quad 0 /* ImportTable */ + .quad 0 /* ResourceTable */ + .quad 0 /* ExceptionTable */ + .quad 0 /* CertificationTable */ + .quad 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 */ + .long 0 + .long 0 + .long 0 /* SizeOfRawData */ + .long 0 /* PointerToRawData */ + .long 0 /* PointerToRelocations */ + .long 0 /* PointerToLineNumbers */ + .short 0 /* NumberOfRelocations */ + .short 0 /* NumberOfLineNumbers */ + .long 0x42100040 /* Characteristics (section flags) */ + + + .ascii ".text" + .byte 0 + .byte 0 + .byte 0 /* end of 0 padding of section name */ + .long _etext - _start /* VirtualSize */ + .long _start - ImageBase /* VirtualAddress */ + .long _etext - _start /* SizeOfRawData */ + .long _start - ImageBase /* PointerToRawData */ + .long 0 /* PointerToRelocations (0 for executables) */ + .long 0 /* PointerToLineNumbers (0 for executables) */ + .short 0 /* NumberOfRelocations (0 for executables) */ + .short 0 /* NumberOfLineNumbers (0 for executables) */ + /* Characteristics (section flags) */ + .long (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 */ + .long _edata - _data /* VirtualSize */ + .long _data - ImageBase /* VirtualAddress */ + .long _edata - _data /* SizeOfRawData */ + .long _data - ImageBase /* PointerToRawData */ + .long 0 /* PointerToRelocations */ + .long 0 /* PointerToLineNumbers */ + .short 0 /* NumberOfRelocations */ + .short 0 /* NumberOfLineNumbers */ + /* Characteristics (section flags) */ + .long (IMAGE_SCN_MEM_WRITE | \ + IMAGE_SCN_MEM_READ | \ + IMAGE_SCN_CNT_INITIALIZED_DATA) + + .align 12 + .globl _start + .type _start, @function +_start: + PTR_ADDI sp, sp, -(3 * LONGSIZE) + LONG_S ra, sp, 0 + LONG_S a0, sp, (1 * LONGSIZE) + LONG_S a1, sp, (2 * LONGSIZE) + + move a2, a0 /* a2: ImageHandle */ + move a3, a1 /* a3: SystemTable */ + la.local a0, ImageBase /* a0: ImageBase */ + la.local a1, _DYNAMIC /* a1: DynamicSection */ + bl _relocate + bnez a0, 0f + + LONG_L a0, sp, (1 * LONGSIZE) + LONG_L a1, sp, (2 * LONGSIZE) + bl efi_main + +0: LONG_L ra, sp, 0 + PTR_ADDI sp, sp, (3 * LONGSIZE) + jr ra + .end _start diff --git a/arch/loongarch/lib/elf_loongarch_efi.lds b/arch/loongarch/lib/elf_loongarch_efi.lds new file mode 100644 index 000000000000..050e5a52a0b3 --- /dev/null +++ b/arch/loongarch/lib/elf_loongarch_efi.lds @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: BSD-2-Clause */ +/* + * U-Boot LoongArch + * + * Modified from arch/riscv/lib/elf_riscv64_efi.lds + */ + +OUTPUT_ARCH(loongarch) + +PHDRS +{ + data PT_LOAD FLAGS(3); /* SHF_WRITE | SHF_ALLOC */ +} + +ENTRY(_start) +SECTIONS +{ + .text 0x0 : { + _text = .; + *(.text.head) + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + *(.srodata) + *(.rodata*) + . = ALIGN(16); + *(.dynamic); + . = ALIGN(512); + } + .rela.dyn : { *(.rela.dyn) } + .rela.plt : { *(.rela.plt) } + .rela.got : { *(.rela.got) } + .rela.data : { *(.rela.data) *(.rela.data*) } + _etext = .; + _text_size = . - _text; + . = ALIGN(4096); + .data : { + _data = .; + *(.sdata) + *(.data) + *(.data1) + *(.data.*) + *(.got.plt) + *(.got) + + /* + * 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) + *(.bss.*) + *(COMMON) + . = ALIGN(512); + _bss_end = .; + _edata = .; + } :data + _data_size = _edata - _data; + + . = ALIGN(4096); + .dynsym : { *(.dynsym) } + . = ALIGN(4096); + .dynstr : { *(.dynstr) } + . = ALIGN(4096); + .note.gnu.build-id : { *(.note.gnu.build-id) } + /DISCARD/ : { + *(.rel.reloc) + *(.eh_frame) + *(.note.GNU-stack) + } + .comment 0 : { *(.comment) } +} diff --git a/arch/loongarch/lib/reloc_loongarch_efi.c b/arch/loongarch/lib/reloc_loongarch_efi.c new file mode 100644 index 000000000000..32a7d792103d --- /dev/null +++ b/arch/loongarch/lib/reloc_loongarch_efi.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* reloc_loongarch.c - position independent ELF shared object relocator + Copyright (C) 2018 Alexander Graf <ag...@suse.de> + Copyright (C) 2014 Linaro Ltd. <ard.biesheu...@linaro.org> + Copyright (C) 1999 Hewlett-Packard Co. + Contributed by David Mosberger <dav...@hpl.hp.com>. + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials + provided with the distribution. + * Neither the name of Hewlett-Packard Co. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + BE LIABLE FOR ANYDIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#include <efi.h> + +#include <elf.h> + +#ifdef __loongarch64 +#define Elf_Dyn Elf64_Dyn +#define Elf_Rela Elf64_Rela +#define ELF_R_TYPE ELF64_R_TYPE +#else +#define Elf_Dyn Elf32_Dyn +#define Elf_Rela Elf32_Rela +#define ELF_R_TYPE ELF32_R_TYPE +#endif + +efi_status_t EFIAPI _relocate(long ldbase, Elf_Dyn *dyn) +{ + long relsz = 0, relent = 0; + Elf_Rela *rel = 0; + unsigned long *addr; + int i; + + for (i = 0; dyn[i].d_tag != DT_NULL; ++i) { + switch (dyn[i].d_tag) { + case DT_RELA: + rel = (Elf_Rela *) + ((unsigned long)dyn[i].d_un.d_ptr + + ldbase); + break; + case DT_RELASZ: + relsz = dyn[i].d_un.d_val; + break; + case DT_RELAENT: + relent = dyn[i].d_un.d_val; + break; + case DT_PLTGOT: + addr = (unsigned long *) + ((unsigned long)dyn[i].d_un.d_ptr + + ldbase); + break; + default: + break; + } + } + + if (!rel && relent == 0) + return EFI_SUCCESS; + + if (!rel || relent == 0) + return EFI_LOAD_ERROR; + + while (relsz > 0) { + /* apply the relocs */ + switch (ELF_R_TYPE(rel->r_info)) { + case R_LARCH_NONE: + break; + case R_LARCH_RELATIVE: + addr = (unsigned long *) + (ldbase + rel->r_offset); + *addr += ldbase; + break; + default: + break; + } + rel = (Elf_Rela *)((char *)rel + relent); + relsz -= relent; + } + return EFI_SUCCESS; +} + diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 430bb7f0f7dc..1d82a062a215 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 || LOONGARCH || 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.43.0