diff --git a/src/Makefile.housekeeping b/src/Makefile.housekeeping index ba61e2166..2b4356de1 100644 --- a/src/Makefile.housekeeping +++ b/src/Makefile.housekeeping @@ -352,6 +352,8 @@ arch : # Determine build platform DEFAULT_PLATFORM_i386 := pcbios DEFAULT_PLATFORM_x86_64 := pcbios +DEFAULT_PLATFORM_riscv32 := sbi +DEFAULT_PLATFORM_riscv64 := sbi DEFAULT_PLATFORM := $(DEFAULT_PLATFORM_$(ARCH)) PLATFORM := $(firstword $(BIN_PLATFORM) $(DEFAULT_PLATFORM) none) CFLAGS += -DPLATFORM=$(PLATFORM) -DPLATFORM_$(PLATFORM) diff --git a/src/arch/riscv/Makefile b/src/arch/riscv/Makefile index d3ae4e84c..324e1403e 100644 --- a/src/arch/riscv/Makefile +++ b/src/arch/riscv/Makefile @@ -11,6 +11,7 @@ INCDIRS := arch/$(ARCH)/include arch/riscv/include $(INCDIRS) # SRCDIRS += arch/riscv/core SRCDIRS += arch/riscv/interface/sbi +SRCDIRS += arch/riscv/prefix # RISCV-specific flags # diff --git a/src/arch/riscv/Makefile.sbi b/src/arch/riscv/Makefile.sbi new file mode 100644 index 000000000..dee1b6e5d --- /dev/null +++ b/src/arch/riscv/Makefile.sbi @@ -0,0 +1,16 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Build a position-independent executable, with relocations required +# only for data values. Runtime relocations are applied by the +# prefix code. +# +CFLAGS += -mcmodel=medany -fpie +LDFLAGS += -pie --no-dynamic-linker + +# Linker script +# +LDSCRIPT = arch/riscv/scripts/sbi.lds + +# Media types +# +MEDIA += sbi diff --git a/src/arch/riscv/core/stack.S b/src/arch/riscv/core/stack.S new file mode 100644 index 000000000..1cd1da7c5 --- /dev/null +++ b/src/arch/riscv/core/stack.S @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + + FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + +/** @file + * + * Internal stack + * + */ + + .section ".note.GNU-stack", "", @progbits + .text + +#define STACK_ALIGN 16 + +#define STACK_SIZE 8192 + + .section ".stack", "aw", @nobits + .balign STACK_ALIGN + .globl _stack +_stack: + .space STACK_SIZE + .globl _estack +_estack: diff --git a/src/arch/riscv/include/bits/umalloc.h b/src/arch/riscv/include/bits/umalloc.h new file mode 100644 index 000000000..a7171ca2c --- /dev/null +++ b/src/arch/riscv/include/bits/umalloc.h @@ -0,0 +1,14 @@ +#ifndef _BITS_UMALLOC_H +#define _BITS_UMALLOC_H + +/** @file + * + * RISCV-specific user memory allocation API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +#endif /* _BITS_UMALLOC_H */ diff --git a/src/arch/riscv/include/ipxe/errno/sbi.h b/src/arch/riscv/include/ipxe/errno/sbi.h new file mode 100644 index 000000000..2428183d4 --- /dev/null +++ b/src/arch/riscv/include/ipxe/errno/sbi.h @@ -0,0 +1,19 @@ +#ifndef _IPXE_ERRNO_SBI_H +#define _IPXE_ERRNO_SBI_H + +/** + * @file + * + * RISC-V SBI platform error codes + * + * We never need to return SBI error codes ourselves, so we + * arbitrarily choose to use the Linux error codes as platform error + * codes. + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +#endif /* _IPXE_ERRNO_SBI_H */ diff --git a/src/arch/riscv/include/ipxe/sbi_umalloc.h b/src/arch/riscv/include/ipxe/sbi_umalloc.h new file mode 100644 index 000000000..5763239fb --- /dev/null +++ b/src/arch/riscv/include/ipxe/sbi_umalloc.h @@ -0,0 +1,18 @@ +#ifndef _IPXE_SBI_UMALLOC_H +#define _IPXE_SBI_UMALLOC_H + +/** @file + * + * External memory allocation + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#ifdef UMALLOC_SBI +#define UMALLOC_PREFIX_sbi +#else +#define UMALLOC_PREFIX_sbi __sbi_ +#endif + +#endif /* _IPXE_SBI_UMALLOC_H */ diff --git a/src/arch/riscv/interface/sbi/sbi_umalloc.c b/src/arch/riscv/interface/sbi/sbi_umalloc.c new file mode 100644 index 000000000..2f9935adb --- /dev/null +++ b/src/arch/riscv/interface/sbi/sbi_umalloc.c @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +/** @file + * + * iPXE user memory allocation API for SBI + * + */ + +/** Equivalent of NOWHERE for user pointers */ +#define UNOWHERE ( ~UNULL ) + +/** + * Reallocate external memory + * + * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v new_size Requested size + * @ret new_ptr Allocated memory, or UNULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ +static userptr_t sbi_urealloc ( userptr_t old_ptr, size_t new_size ) { + + /* External allocation not yet implemented: allocate from heap */ + return ( ( userptr_t ) realloc ( ( ( void * ) old_ptr ), new_size ) ); +} + +PROVIDE_UMALLOC ( sbi, urealloc, sbi_urealloc ); diff --git a/src/arch/riscv/prefix/sbiprefix.S b/src/arch/riscv/prefix/sbiprefix.S new file mode 100644 index 000000000..0de001951 --- /dev/null +++ b/src/arch/riscv/prefix/sbiprefix.S @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + + FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ) + +/** @file + * + * SBI position-independent executable prefix + * + */ + + .section ".note.GNU-stack", "", @progbits + .text + +/* SBI debug console extension */ +#define SBI_DBCN ( ( 'D' << 24 ) | ( 'B' << 16 ) | ( 'C' << 8 ) | 'N' ) +#define SBI_DBCN_WRITE 0x00 + +/* SBI system reset extension */ +#define SBI_SRST ( ( 'S' << 24 ) | ( 'R' << 16 ) | ( 'S' << 8 ) | 'T' ) +#define SBI_SRST_SYSTEM_RESET 0x00 +#define SBI_RESET_COLD 0x00000001 + +/* Relative relocation type */ +#define R_RISCV_RELATIVE 3 + + /* Layout of a relocation record */ + .struct 0 +rela_offset: .space ( __riscv_xlen / 8 ) +rela_type: .space ( __riscv_xlen / 8 ) +rela_addend: .space ( __riscv_xlen / 8 ) +rela_len: + .previous + + /* + * Display progress message via debug console + */ + .macro progress message +#ifndef NDEBUG + .section ".prefix.data", "aw", @progbits +progress_\@: + .ascii "\message" + .equ progress_\@_len, . - progress_\@ + .size progress_\@, . - progress_\@ + .previous + li a7, SBI_DBCN + li a6, SBI_DBCN_WRITE + li a0, progress_\@_len + la a1, progress_\@ + mv a2, zero + ecall +#endif + .endm + + /* + * SBI entry point + */ + .section ".prefix", "ax", @progbits + .org 0 + .globl _sbi_start +_sbi_start: + /* Preserve arguments */ + mv s0, a0 + mv s1, a1 + progress "\nSBI->iPXE" + + /* Apply dynamic relocations */ + la t0, _reloc + la t1, _ereloc + la t2, _sbi_start +1: /* Read relocation record */ + LOADN t3, rela_offset(t0) + LOADN t4, rela_type(t0) + LOADN t5, rela_addend(t0) + /* Check relocation type */ + addi t4, t4, -R_RISCV_RELATIVE + bnez t4, 2f + /* Apply relocation */ + add t3, t3, t2 + add t5, t5, t2 + STOREN t5, (t3) +2: /* Loop */ + addi t0, t0, rela_len + blt t0, t1, 1b + progress " .reloc" + + /* Zero the bss */ + la t0, _bss + la t1, _ebss +1: STOREN zero, (t0) + addi t0, t0, ( __riscv_xlen / 8 ) + blt t0, t1, 1b + progress " .bss" + + /* Set up stack */ + la sp, _estack + progress " .stack" + + /* Store boot hart */ + la t0, boot_hart + STOREN s0, (t0) + + /* Register device tree */ + mv a0, s1 + call register_fdt + + /* Call main program */ + progress "\n\n" + call main + + /* We have no return path, since the M-mode SBI implementation + * will have jumped to us by setting our start address in MEPC + * and issuing an MRET instruction. + * + * Attempt a system reset, since there is nothing else we can + * viably do at this point. + */ + progress "\niPXE->SBI reset\n" + li a7, SBI_SRST + li a6, SBI_SRST_SYSTEM_RESET + li a0, SBI_RESET_COLD + mv a1, zero + ecall + + /* If reset failed, lock the system */ + progress "(reset failed)\n" +1: wfi + j 1b + .size _sbi_start, . - _sbi_start + + /* File split information for the compressor */ + .section ".zinfo", "a", @progbits + .ascii "COPY" + .word 0 + .word _sbi_filesz + .word 1 diff --git a/src/arch/riscv/scripts/sbi.lds b/src/arch/riscv/scripts/sbi.lds new file mode 100644 index 000000000..a65b27181 --- /dev/null +++ b/src/arch/riscv/scripts/sbi.lds @@ -0,0 +1,119 @@ +/* + * Linker script for RISC-V SBI images + * + */ + +SECTIONS { + + /* Start at virtual address zero */ + . = 0; + + /* Weak symbols that need zero values if not otherwise defined */ + .weak 0x0 : { + _weak = .; + *(.weak) + *(.weak.*) + _eweak = .; + } + _assert = ASSERT ( ( _weak == _eweak ), ".weak is non-zero length" ); + + /* Prefix code */ + .prefix : { + _prefix = .; + *(.prefix) + *(.prefix.*) + _eprefix = .; + } + + /* Program code */ + .text : { + _text = .; + *(.text) + *(.text.*) + _etext = .; + } + + /* Align to page size to allow linker to generate W^X segments */ + . = ALIGN ( 4096 ); + + /* Read-only data */ + .rodata : { + _rodata = .; + *(.rodata) + *(.rodata.*) + _erodata = .; + } + + /* Writable data */ + .data : { + _data = .; + *(.data) + *(.data.*) + KEEP(*(SORT(.tbl.*))) /* Various tables. See include/tables.h */ + KEEP(*(.provided)) + KEEP(*(.provided.*)) + _edata = .; + } + + /* Uninitialised and discardable data */ + OVERLAY : { + + /* Runtime relocations (discarded after use) */ + .rela.dyn { + _reloc = .; + *(.rela) + *(.rela.dyn) + } + + /* Compressor information block */ + .zinfo { + _zinfo = .; + KEEP(*(.zinfo)) + KEEP(*(.zinfo.*)) + _ezinfo = .; + } + + /* Uninitialised data */ + .bss { + _bss = .; + *(.bss) + *(.bss.*) + *(COMMON) + *(.stack) + *(.stack.*) + /* Align to allow for easy zeroing by prefix code */ + . = ALIGN ( 16 ); + _ebss = .; + } + } + + /* Calculate end of relocations + * + * This cannot be done by placing "_ereloc = .;" inside the + * .rela.dyn section, since the dynamic relocations are not + * present in the input sections but are instead generated during + * linking. + */ + _ereloc = ( _reloc + __load_stop_reladyn - __load_start_reladyn ); + + /* Length of initialised data */ + _sbi_filesz = ABSOLUTE ( _ereloc ); + + /* Unwanted sections */ + /DISCARD/ : { + *(.comment) + *(.comment.*) + *(.note) + *(.note.*) + *(.eh_frame) + *(.eh_frame.*) + *(.dynamic) + *(.dynsym) + *(.dynstr) + *(.einfo) + *(.einfo.*) + *(.discard) + *(.discard.*) + *(.pci_devlist.*) + } +} diff --git a/src/arch/riscv32/Makefile.sbi b/src/arch/riscv32/Makefile.sbi new file mode 100644 index 000000000..d62287770 --- /dev/null +++ b/src/arch/riscv32/Makefile.sbi @@ -0,0 +1,6 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Include generic SBI Makefile +# +MAKEDEPS += arch/riscv/Makefile.sbi +include arch/riscv/Makefile.sbi diff --git a/src/arch/riscv32/include/ipxe/sbi/dhcparch.h b/src/arch/riscv32/include/ipxe/sbi/dhcparch.h new file mode 100644 index 000000000..713d4cf5d --- /dev/null +++ b/src/arch/riscv32/include/ipxe/sbi/dhcparch.h @@ -0,0 +1,20 @@ +#ifndef _IPXE_SBI_DHCPARCH_H +#define _IPXE_SBI_DHCPARCH_H + +/** @file + * + * DHCP client architecture definitions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** DHCP client architecture */ +#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_RISCV32 + +/** DHCP client network device interface */ +#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */ + +#endif /* _IPXE_SBI_DHCPARCH_H */ diff --git a/src/arch/riscv64/Makefile.sbi b/src/arch/riscv64/Makefile.sbi new file mode 100644 index 000000000..d62287770 --- /dev/null +++ b/src/arch/riscv64/Makefile.sbi @@ -0,0 +1,6 @@ +# -*- makefile -*- : Force emacs to use Makefile mode + +# Include generic SBI Makefile +# +MAKEDEPS += arch/riscv/Makefile.sbi +include arch/riscv/Makefile.sbi diff --git a/src/arch/riscv64/include/ipxe/sbi/dhcparch.h b/src/arch/riscv64/include/ipxe/sbi/dhcparch.h new file mode 100644 index 000000000..e172f064f --- /dev/null +++ b/src/arch/riscv64/include/ipxe/sbi/dhcparch.h @@ -0,0 +1,20 @@ +#ifndef _IPXE_SBI_DHCPARCH_H +#define _IPXE_SBI_DHCPARCH_H + +/** @file + * + * DHCP client architecture definitions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** DHCP client architecture */ +#define DHCP_ARCH_CLIENT_ARCHITECTURE DHCP_CLIENT_ARCHITECTURE_RISCV64 + +/** DHCP client network device interface */ +#define DHCP_ARCH_CLIENT_NDI 1 /* UNDI */ , 3, 10 /* v3.10 */ + +#endif /* _IPXE_SBI_DHCPARCH_H */ diff --git a/src/config/config_sbi.c b/src/config/config_sbi.c new file mode 100644 index 000000000..e69de29bb diff --git a/src/config/defaults/sbi.h b/src/config/defaults/sbi.h new file mode 100644 index 000000000..42fb515f0 --- /dev/null +++ b/src/config/defaults/sbi.h @@ -0,0 +1,36 @@ +#ifndef CONFIG_DEFAULTS_SBI_H +#define CONFIG_DEFAULTS_SBI_H + +/** @file + * + * Configuration defaults for RISC-V SBI + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#define IOAPI_RISCV +#define IOMAP_VIRT +#define DMAAPI_FLAT +#define UACCESS_FLAT +#define TIMER_ZICNTR +#define ENTROPY_ZKR + +#define CONSOLE_SBI +#define REBOOT_SBI +#define UMALLOC_SBI + +#define ACPI_NULL +#define MPAPI_NULL +#define NAP_NULL +#define PCIAPI_NULL +#define SANBOOT_NULL +#define SMBIOS_NULL +#define TIME_NULL + +#define IMAGE_SCRIPT + +#define REBOOT_CMD +#define POWEROFF_CMD + +#endif /* CONFIG_DEFAULTS_SBI_H */