]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[sbi] Add support for running as a RISC-V SBI payload
authorMichael Brown <mcb30@ipxe.org>
Mon, 28 Oct 2024 14:40:35 +0000 (14:40 +0000)
committerMichael Brown <mcb30@ipxe.org>
Mon, 28 Oct 2024 19:20:50 +0000 (19:20 +0000)
Add basic support for running directly on top of SBI, with no UEFI
firmware present.  Build as e.g.:

  make CROSS=riscv64-linux-gnu- bin-riscv64/ipxe.sbi

The resulting binary can be tested in QEMU using e.g.:

  qemu-system-riscv64 -M virt -cpu max -serial stdio \
                      -kernel bin-riscv64/ipxe.sbi

No drivers or executable binary formats are supported yet, but the
unit test suite may be run successfully.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
16 files changed:
src/Makefile.housekeeping
src/arch/riscv/Makefile
src/arch/riscv/Makefile.sbi [new file with mode: 0644]
src/arch/riscv/core/stack.S [new file with mode: 0644]
src/arch/riscv/include/bits/umalloc.h [new file with mode: 0644]
src/arch/riscv/include/ipxe/errno/sbi.h [new file with mode: 0644]
src/arch/riscv/include/ipxe/sbi_umalloc.h [new file with mode: 0644]
src/arch/riscv/interface/sbi/sbi_umalloc.c [new file with mode: 0644]
src/arch/riscv/prefix/sbiprefix.S [new file with mode: 0644]
src/arch/riscv/scripts/sbi.lds [new file with mode: 0644]
src/arch/riscv32/Makefile.sbi [new file with mode: 0644]
src/arch/riscv32/include/ipxe/sbi/dhcparch.h [new file with mode: 0644]
src/arch/riscv64/Makefile.sbi [new file with mode: 0644]
src/arch/riscv64/include/ipxe/sbi/dhcparch.h [new file with mode: 0644]
src/config/config_sbi.c [new file with mode: 0644]
src/config/defaults/sbi.h [new file with mode: 0644]

index ba61e216694b61c66543ea4d5b5fd83654b606ac..2b4356de1e21dc0438ed1e7747f87f563f83a10a 100644 (file)
@@ -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)
index d3ae4e84c1fa5465d2b06d6f3bf9152328c10f60..324e1403e89033298ebf5336640312c24bf35bd0 100644 (file)
@@ -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 (file)
index 0000000..dee1b6e
--- /dev/null
@@ -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 (file)
index 0000000..1cd1da7
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 (file)
index 0000000..a7171ca
--- /dev/null
@@ -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 <ipxe/sbi_umalloc.h>
+
+#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 (file)
index 0000000..2428183
--- /dev/null
@@ -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 <ipxe/errno/linux.h>
+
+#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 (file)
index 0000000..5763239
--- /dev/null
@@ -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 (file)
index 0000000..2f9935a
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 <stdlib.h>
+#include <ipxe/umalloc.h>
+
+/** @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 (file)
index 0000000..0de0019
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * 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 (file)
index 0000000..a65b271
--- /dev/null
@@ -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 (file)
index 0000000..d622877
--- /dev/null
@@ -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 (file)
index 0000000..713d4cf
--- /dev/null
@@ -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 <ipxe/dhcp.h>
+
+/** 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 (file)
index 0000000..d622877
--- /dev/null
@@ -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 (file)
index 0000000..e172f06
--- /dev/null
@@ -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 <ipxe/dhcp.h>
+
+/** 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 (file)
index 0000000..e69de29
diff --git a/src/config/defaults/sbi.h b/src/config/defaults/sbi.h
new file mode 100644 (file)
index 0000000..42fb515
--- /dev/null
@@ -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 */