riscv: Add EFI application infrastructure

The hello world binary and a few selftests require to build EFI target
binaries, not just the EFI host environment.

This patch adds all required files to generate an EFI binary for
RISC-V.

Signed-off-by: Alexander Graf <agraf@suse.de>
lime2-spi
Alexander Graf 6 years ago committed by Andes
parent 6cc1a2af46
commit 493d1e88b6
  1. 5
      arch/riscv/config.mk
  2. 11
      arch/riscv/lib/Makefile
  3. 152
      arch/riscv/lib/crt0_riscv_efi.S
  4. 70
      arch/riscv/lib/elf_riscv32_efi.lds
  5. 70
      arch/riscv/lib/elf_riscv64_efi.lds
  6. 97
      arch/riscv/lib/reloc_riscv_efi.c

@ -19,10 +19,12 @@ endif
ifdef CONFIG_32BIT
PLATFORM_LDFLAGS += -m $(32bit-emul)
EFI_LDS := elf_riscv32_efi.lds
endif
ifdef CONFIG_64BIT
PLATFORM_LDFLAGS += -m $(64bit-emul)
EFI_LDS := elf_riscv64_efi.lds
endif
CONFIG_STANDALONE_LOAD_ADDR = 0x00000000 \
@ -31,3 +33,6 @@ CONFIG_STANDALONE_LOAD_ADDR = 0x00000000 \
PLATFORM_CPPFLAGS += -ffixed-gp -fpic
PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -gdwarf-2 -ffunction-sections
LDFLAGS_u-boot += --gc-sections -static -pie
EFI_CRT0 := crt0_riscv_efi.o
EFI_RELOC := reloc_riscv_efi.o

@ -11,3 +11,14 @@ obj-$(CONFIG_CMD_GO) += boot.o
obj-y += cache.o
obj-y += interrupts.o
obj-y += setjmp.o
# For building EFI apps
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)

@ -0,0 +1,152 @@
/*
* crt0-efi-riscv.S - PE/COFF header for RISC-V EFI applications
*
* Copright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
* Copright (C) 2018 Alexander Graf <agraf@suse.de>
*
* SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
*
* This file is inspired by arch/arm/lib/crt0_aarch64_efi.S
*/
#include <asm-generic/pe.h>
#if __riscv_xlen == 64
#define SIZE_LONG 8
#define SAVE_LONG(reg, idx) sd reg, (idx*SIZE_LONG)(sp)
#define LOAD_LONG(reg, idx) ld reg, (idx*SIZE_LONG)(sp)
#define PE_MACHINE 0x5064
#else
#define SIZE_LONG 4
#define SAVE_LONG(reg, idx) sw reg, (idx*SIZE_LONG)(sp)
#define LOAD_LONG(reg, idx) lw reg, (idx*SIZE_LONG)(sp)
#define PE_MACHINE 0x5032
#endif
.section .text.head
/*
* Magic "MZ" signature for PE/COFF
*/
.globl ImageBase
ImageBase:
.ascii "MZ"
.skip 58 /* 'MZ' + pad + offset == 64 */
.long pe_header - ImageBase /* Offset to the PE header */
pe_header:
.ascii "PE"
.short 0
coff_header:
.short PE_MACHINE /* RISC-V 64/32-bit */
.short 2 /* nr_sections */
.long 0 /* TimeDateStamp */
.long 0 /* PointerToSymbolTable */
.long 1 /* NumberOfSymbols */
.short section_table - optional_header /* SizeOfOptionalHeader */
/*
* Characteristics: IMAGE_FILE_DEBUG_STRIPPED |
* IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_LINE_NUMS_STRIPPED
*/
.short 0x206
optional_header:
.short 0x20b /* 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 */
extra_header_fields:
.quad 0 /* ImageBase */
.long 0x20 /* SectionAlignment */
.long 0x8 /* FileAlignment */
.short 0 /* MajorOperatingSystemVersion */
.short 0 /* MinorOperatingSystemVersion */
.short 0 /* 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 */
.short 0 /* DllCharacteristics */
.quad 0 /* SizeOfStackReserve */
.quad 0 /* SizeOfStackCommit */
.quad 0 /* SizeOfHeapReserve */
.quad 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 _edata - _start /* VirtualSize */
.long _start - ImageBase /* VirtualAddress */
.long _edata - _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) */
.long 0xe0500020 /* Characteristics (section flags) */
_start:
addi sp, sp, -(SIZE_LONG * 3)
SAVE_LONG(a0, 0)
SAVE_LONG(a1, 1)
SAVE_LONG(ra, 2)
lla a0, ImageBase
lla a1, _DYNAMIC
call _relocate
bne a0, zero, 0f
LOAD_LONG(a1, 1)
LOAD_LONG(a0, 0)
call efi_main
LOAD_LONG(ra, 2)
0: addi sp, sp, (SIZE_LONG * 3)
ret

@ -0,0 +1,70 @@
/*
* U-Boot riscv32 EFI linker script
*
* SPDX-License-Identifier: BSD-2-Clause
*
* Modified from arch/arm/lib/elf_aarch64_efi.lds
*/
OUTPUT_FORMAT("elf32-littleriscv", "elf32-littleriscv", "elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
.text 0x0 : {
_text = .;
*(.text.head)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.srodata)
*(.rodata*)
. = ALIGN(16);
}
_etext = .;
_text_size = . - _text;
.dynamic : { *(.dynamic) }
.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(16);
_bss_end = .;
_edata = .;
}
.rela.dyn : { *(.rela.dyn) }
.rela.plt : { *(.rela.plt) }
.rela.got : { *(.rela.got) }
.rela.data : { *(.rela.data) *(.rela.data*) }
_data_size = . - _etext;
. = 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) }
}

@ -0,0 +1,70 @@
/*
* U-Boot riscv64 EFI linker script
*
* SPDX-License-Identifier: BSD-2-Clause
*
* Modified from arch/arm/lib/elf_aarch64_efi.lds
*/
OUTPUT_FORMAT("elf64-littleriscv", "elf64-littleriscv", "elf64-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
SECTIONS
{
.text 0x0 : {
_text = .;
*(.text.head)
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
*(.srodata)
*(.rodata*)
. = ALIGN(16);
}
_etext = .;
_text_size = . - _text;
.dynamic : { *(.dynamic) }
.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(16);
_bss_end = .;
_edata = .;
}
.rela.dyn : { *(.rela.dyn) }
.rela.plt : { *(.rela.plt) }
.rela.got : { *(.rela.got) }
.rela.data : { *(.rela.data) *(.rela.data*) }
_data_size = . - _etext;
. = 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) }
}

@ -0,0 +1,97 @@
/* reloc_riscv.c - position independent ELF shared object relocator
Copyright (C) 2018 Alexander Graf <agraf@suse.de>
Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
Copyright (C) 1999 Hewlett-Packard Co.
Contributed by David Mosberger <davidm@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>
#if __riscv_xlen == 64
#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 _relocate(long ldbase, Elf_Dyn *dyn, efi_handle_t image,
struct efi_system_table *systab)
{
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 *)((ulong)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;
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_RISCV_RELATIVE:
addr = (ulong *)(ldbase + rel->r_offset);
*addr = ldbase + rel->r_addend;
break;
default:
/* Panic */
while (1) ;
}
rel = (Elf_Rela *)((char *)rel + relent);
relsz -= relent;
}
return EFI_SUCCESS;
}
Loading…
Cancel
Save