Initial support for RISCV64

Add the RISCV64 architecture

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
This commit is contained in:
Heinrich Schuchardt 2021-03-19 17:38:42 +01:00
parent dfdcd7eff3
commit b95f138fa1
13 changed files with 493 additions and 1 deletions

View File

@ -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)

136
gnuefi/crt0-efi-riscv64.S Normal file
View File

@ -0,0 +1,136 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
* Copright (C) 2018 Alexander Graf <agraf@suse.de>
*
* 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

View File

@ -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) }
}

91
gnuefi/reloc_riscv64.c Normal file
View File

@ -0,0 +1,91 @@
// SPDX-License-Identifier: GPL-2.0+
/* 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>
#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;
}

View File

@ -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

View File

@ -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"

View File

@ -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

31
inc/riscv64/efibind.h Normal file
View File

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#include <stdint.h>
#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))

7
inc/riscv64/efilibplat.h Normal file
View File

@ -0,0 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0+ */
VOID
InitializeLibPlatform (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);

View File

@ -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)

11
lib/riscv64/initplat.c Normal file
View File

@ -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
)
{
}

62
lib/riscv64/math.c Normal file
View File

@ -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;
}

69
lib/riscv64/setjmp.S Normal file
View File

@ -0,0 +1,69 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright Heinrich Schuchardt <xypron.glpk@gmx.de>
*/
.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