From b95f138fa1550040e68ac3dd34cfce7d148d7984 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 19 Mar 2021 17:38:42 +0100 Subject: [PATCH] Initial support for RISCV64 Add the RISCV64 architecture Signed-off-by: Heinrich Schuchardt --- Make.defaults | 2 + gnuefi/crt0-efi-riscv64.S | 136 +++++++++++++++++++++++++++++++++++++ gnuefi/elf_riscv64_efi.lds | 77 +++++++++++++++++++++ gnuefi/reloc_riscv64.c | 91 +++++++++++++++++++++++++ inc/efi.h | 2 + inc/efilib.h | 2 + inc/efirtlib.h | 2 + inc/riscv64/efibind.h | 31 +++++++++ inc/riscv64/efilibplat.h | 7 ++ lib/Makefile | 2 +- lib/riscv64/initplat.c | 11 +++ lib/riscv64/math.c | 62 +++++++++++++++++ lib/riscv64/setjmp.S | 69 +++++++++++++++++++ 13 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 gnuefi/crt0-efi-riscv64.S create mode 100644 gnuefi/elf_riscv64_efi.lds create mode 100644 gnuefi/reloc_riscv64.c create mode 100644 inc/riscv64/efibind.h create mode 100644 inc/riscv64/efilibplat.h create mode 100644 lib/riscv64/initplat.c create mode 100644 lib/riscv64/math.c create mode 100644 lib/riscv64/setjmp.S diff --git a/Make.defaults b/Make.defaults index 5695b2a..47ed361 100755 --- a/Make.defaults +++ b/Make.defaults @@ -142,10 +142,12 @@ endif ifneq ($(ARCH),aarch64) ifneq ($(ARCH),arm) ifneq ($(ARCH),mips64el) +ifneq ($(ARCH),riscv64) export HAVE_EFI_OBJCOPY=y endif endif endif +endif ifneq ($(ARCH),arm) export LIBGCC=$(shell $(CC) $(ARCH3264) -print-libgcc-file-name) diff --git a/gnuefi/crt0-efi-riscv64.S b/gnuefi/crt0-efi-riscv64.S new file mode 100644 index 0000000..f8949a7 --- /dev/null +++ b/gnuefi/crt0-efi-riscv64.S @@ -0,0 +1,136 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copright (C) 2014 Linaro Ltd. + * Copright (C) 2018 Alexander Graf + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice and this list of conditions, without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License as published by the Free Software Foundation; + * either version 2 of the License, or (at your option) any later version. + */ + +#ifndef EFI_SUBSYSTEM +#define EFI_SUBSYSTEM 10 +#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 0x5064 // riscv64 + .short 2 // nr_sections + .long 0 // TimeDateStamp + .long 0 // PointerToSymbolTable + .long 1 // NumberOfSymbols + .short section_table - optional_header // SizeOfOptionalHeader + .short 0x206 // Characteristics. + // IMAGE_FILE_DEBUG_STRIPPED | + // IMAGE_FILE_EXECUTABLE_IMAGE | + // IMAGE_FILE_LINE_NUMS_STRIPPED +optional_header: + .short 0x20b // PE32+ format + .byte 0x02 // MajorLinkerVersion + .byte 0x14 // MinorLinkerVersion + .long _data - _start // SizeOfCode + .long _data_size // SizeOfInitializedData + .long 0 // SizeOfUninitializedData + .long _start - ImageBase // AddressOfEntryPoint + .long _start - ImageBase // BaseOfCode + +extra_header_fields: + .quad 0 // ImageBase + .long 0x1000 // SectionAlignment + .long 0x200 // 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 EFI_SUBSYSTEM // 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\0\0" + .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\0\0\0" + .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) + + .align 12 + .globl _start +_start: + addi sp, sp, -24 + sd a0, 0(sp) + sd a1, 8(sp) + sd ra, 16(sp) + lla a0, ImageBase + lla a1, _DYNAMIC + call _relocate + bne a0, zero, 0f + ld a1, 8(sp) + ld a0, 0(sp) + call efi_main + ld ra, 16(sp) +0: addi sp, sp, 24 + ret diff --git a/gnuefi/elf_riscv64_efi.lds b/gnuefi/elf_riscv64_efi.lds new file mode 100644 index 0000000..bb64d81 --- /dev/null +++ b/gnuefi/elf_riscv64_efi.lds @@ -0,0 +1,77 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +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 : + ALIGN(4096) + { + _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) + *(COMMON) + . = ALIGN(16); + _bss_end = .; + } + +.rela.text : + { *(.rela.text) *(.rela.text*) } +.rela.dyn : + { *(.rela.dyn) } +.rela.plt : + { *(.rela.plt) } +.rela.got : + { *(.rela.got) } +.rela.data : + { *(.rela.data) *(.rela.data*) } + . = ALIGN(512); + _edata = .; + _data_size = . - _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/gnuefi/reloc_riscv64.c b/gnuefi/reloc_riscv64.c new file mode 100644 index 0000000..73e8d13 --- /dev/null +++ b/gnuefi/reloc_riscv64.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* reloc_riscv.c - position independent ELF shared object relocator + Copyright (C) 2018 Alexander Graf + Copyright (C) 2014 Linaro Ltd. + Copyright (C) 1999 Hewlett-Packard Co. + Contributed by David Mosberger . + + 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 + +#include + +#define Elf_Dyn Elf64_Dyn +#define Elf_Rela Elf64_Rela +#define ELF_R_TYPE ELF64_R_TYPE + +EFI_STATUS EFIAPI _relocate(long ldbase, Elf_Dyn *dyn) +{ + long relsz = 0, relent = 0; + Elf_Rela *rel = NULL; + 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; + 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 = (unsigned long *)(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; +} diff --git a/inc/efi.h b/inc/efi.h index bd99451..f87477b 100644 --- a/inc/efi.h +++ b/inc/efi.h @@ -50,6 +50,8 @@ Revision History #include "arm/efibind.h" #elif defined (_M_MIPS64) || defined(__mips64__) #include "mips64el/efibind.h" +#elif defined (__riscv) && __riscv_xlen == 64 +#include "riscv64/efibind.h" #else #error Usupported architecture #endif diff --git a/inc/efilib.h b/inc/efilib.h index f7db4b6..73f8cc8 100644 --- a/inc/efilib.h +++ b/inc/efilib.h @@ -33,6 +33,8 @@ Revision History #include "arm/efilibplat.h" #elif defined (_M_MIPS64) || defined(__mips64__) #include "mips64el/efilibplat.h" +#elif defined (__riscv) && __riscv_xlen == 64 +#include "riscv64/efilibplat.h" #endif #include "efilink.h" #include "efirtlib.h" diff --git a/inc/efirtlib.h b/inc/efirtlib.h index 5071493..8643061 100644 --- a/inc/efirtlib.h +++ b/inc/efirtlib.h @@ -32,6 +32,8 @@ Revision History #include "arm/efilibplat.h" #elif defined (_M_MIPS64) || defined(__mips64__) #include "mips64el/efilibplat.h" +#elif defined (__riscv) && __riscv_xlen == 64 +#include "riscv64/efilibplat.h" #endif diff --git a/inc/riscv64/efibind.h b/inc/riscv64/efibind.h new file mode 100644 index 0000000..40b9c20 --- /dev/null +++ b/inc/riscv64/efibind.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +#include + +#define EFIAPI +#define EFI_ERROR_MASK 0x8000000000000000 +#define EFIERR(a) (EFI_ERROR_MASK | a) +#define INTERFACE_DECL(x) struct x +#define MIN_ALIGNMENT_SIZE 8 +#define RUNTIMEFUNCTION +#define VOID void + +typedef uint8_t BOOLEAN; +typedef int64_t INTN; +typedef uint64_t UINTN; +typedef int8_t INT8; +typedef uint8_t UINT8; +typedef int16_t INT16; +typedef uint16_t UINT16; +typedef int32_t INT32; +typedef uint32_t UINT32; +typedef int64_t INT64; +typedef uint64_t UINT64; +typedef uint16_t WCHAR; + +#define BREAKPOINT() while(1); +#define uefi_call_wrapper(func, va_num, ...) func(__VA_ARGS__) + +#define EFI_SIGNATURE_16(A,B) ((A) | (B<<8)) +#define EFI_SIGNATURE_32(A,B,C,D) (EFI_SIGNATURE_16(A,B) | (EFI_SIGNATURE_16(C,D) << 16)) +#define EFI_SIGNATURE_64(A,B,C,D,E,F,G,H) (EFI_SIGNATURE_32(A,B,C,D) | ((UINT64)(EFI_SIGNATURE_32(E,F,G,H)) << 32)) diff --git a/inc/riscv64/efilibplat.h b/inc/riscv64/efilibplat.h new file mode 100644 index 0000000..0a61b24 --- /dev/null +++ b/inc/riscv64/efilibplat.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ + +VOID +InitializeLibPlatform ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); diff --git a/lib/Makefile b/lib/Makefile index d0902ca..cf4239d 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -64,7 +64,7 @@ endif OBJS = $(FILES:%=%.o) -SUBDIRS = ia32 x86_64 ia64 aarch64 arm mips64el runtime +SUBDIRS = ia32 x86_64 ia64 aarch64 arm mips64el riscv64 runtime LIBDIRINSTALL = $(INSTALLROOT)$(LIBDIR) diff --git a/lib/riscv64/initplat.c b/lib/riscv64/initplat.c new file mode 100644 index 0000000..ed42037 --- /dev/null +++ b/lib/riscv64/initplat.c @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include "lib.h" + +VOID +InitializeLibPlatform ( + IN EFI_HANDLE ImageHandle EFI_UNUSED, + IN EFI_SYSTEM_TABLE *SystemTable EFI_UNUSED + ) +{ +} diff --git a/lib/riscv64/math.c b/lib/riscv64/math.c new file mode 100644 index 0000000..3653e42 --- /dev/null +++ b/lib/riscv64/math.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * This code is based on EDK II MdePkg/Library/BaseLib/Math64.c + * Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved. + */ + +#include "lib.h" + +/** + * LShiftU64() - left shift + */ +UINT64 +LShiftU64 ( + IN UINT64 Operand, + IN UINTN Count +) +{ + return Operand << Count; +} + +/** + * RShiftU64() - right shift + */ +UINT64 +RShiftU64 ( + IN UINT64 Operand, + IN UINTN Count +) +{ + return Operand >> Count; +} + +/** + * MultU64x32() - multiply + */ +UINT64 +MultU64x32 ( + IN UINT64 Multiplicand, + IN UINTN Multiplier +) +{ + return Multiplicand * Multiplier; +} + +/** + * DivU64x32() - divide + */ +UINT64 +DivU64x32 ( + IN UINT64 Dividend, + IN UINTN Divisor, + OUT UINTN *Remainder OPTIONAL +) +{ + ASSERT(Divisor != 0); + + if (Remainder) { + *Remainder = Dividend % Divisor; + } + + return Dividend / Divisor; +} diff --git a/lib/riscv64/setjmp.S b/lib/riscv64/setjmp.S new file mode 100644 index 0000000..fa187d1 --- /dev/null +++ b/lib/riscv64/setjmp.S @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright Heinrich Schuchardt + */ + + .text + .p2align 3 + +#define GREG_LIST \ + REG_ONE(s0, 0); \ + REG_ONE(s1, 8); \ + REG_ONE(s2, 16); \ + REG_ONE(s3, 24); \ + REG_ONE(s4, 32); \ + REG_ONE(s5, 40); \ + REG_ONE(s6, 48); \ + REG_ONE(s7, 56); \ + REG_ONE(s8, 64); \ + REG_ONE(s9, 72); \ + REG_ONE(s10, 80); \ + REG_ONE(s11, 88); \ + REG_ONE(sp, 96); \ + REG_ONE(ra, 104); + +#define FREG_LIST \ + FREG_ONE(fs0, 112); \ + FREG_ONE(fs1, 120); \ + FREG_ONE(fs2, 128); \ + FREG_ONE(fs3, 136); \ + FREG_ONE(fs4, 144); \ + FREG_ONE(fs5, 152); \ + FREG_ONE(fs6, 160); \ + FREG_ONE(fs7, 168); \ + FREG_ONE(fs8, 176); \ + FREG_ONE(fs9, 184); \ + FREG_ONE(fs10, 192); \ + FREG_ONE(fs11, 200); + +#define REG_ONE(R, P) sd R, P(a0) +#define FREG_ONE(R, P) fsd R, P(a0) + + .globl setjmp + .type setjmp, @function + +setjmp: + GREG_LIST +#ifndef __riscv_float_abi_soft + FREG_LIST +#endif + li a0, 0 + ret + +#undef REG_ONE +#undef FREG_ONE + +#define REG_ONE(R, P) ld R, P(a0) +#define FREG_ONE(R, P) fld R, P(a0) + + .globl longjmp + .type longjmp, @function + +longjmp: + GREG_LIST +#ifndef __riscv_float_abi_soft + FREG_LIST +#endif + seqz a0, a1 + add a0, a0, a1 + ret