summaryrefslogtreecommitdiffstats
path: root/src/arch/riscv/include/ipxe
diff options
context:
space:
mode:
Diffstat (limited to 'src/arch/riscv/include/ipxe')
-rw-r--r--src/arch/riscv/include/ipxe/csr.h75
-rw-r--r--src/arch/riscv/include/ipxe/errno/sbi.h19
-rw-r--r--src/arch/riscv/include/ipxe/hart.h16
-rw-r--r--src/arch/riscv/include/ipxe/riscv_dma.h45
-rw-r--r--src/arch/riscv/include/ipxe/riscv_io.h141
-rw-r--r--src/arch/riscv/include/ipxe/sbi.h213
-rw-r--r--src/arch/riscv/include/ipxe/sbi_reboot.h18
-rw-r--r--src/arch/riscv/include/ipxe/svpage.h28
-rw-r--r--src/arch/riscv/include/ipxe/xthead.h21
-rw-r--r--src/arch/riscv/include/ipxe/zicbom.h17
10 files changed, 593 insertions, 0 deletions
diff --git a/src/arch/riscv/include/ipxe/csr.h b/src/arch/riscv/include/ipxe/csr.h
new file mode 100644
index 000000000..c14974472
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/csr.h
@@ -0,0 +1,75 @@
+#ifndef _IPXE_CSR_H
+#define _IPXE_CSR_H
+
+/** @file
+ *
+ * Control and status registers (CSRs)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * Check if CSR can be read
+ *
+ * @v name CSR name
+ * @v allowed CSR can be read
+ */
+#define csr_can_read( name ) ( { \
+ unsigned long stvec_orig; \
+ unsigned long stvec_temp; \
+ unsigned long csr; \
+ int allowed = 0; \
+ \
+ __asm__ __volatile__ ( /* Set temporary trap vector */ \
+ "la %3, 1f\n\t" \
+ "csrrw %2, stvec, %3\n\t" \
+ /* Try reading CSR */ \
+ "csrr %1, " name "\n\t" \
+ /* Mark as allowed if not trapped */ \
+ "addi %0, %0, 1\n\t" \
+ /* Temporary trap vector */ \
+ ".balign 4\n\t" \
+ "\n1:\n\t" \
+ /* Restore original trap vector */ \
+ "csrw stvec, %2\n\t" \
+ : "+r" ( allowed ), \
+ "=r" ( csr ), \
+ "=r" ( stvec_orig ), \
+ "=r" ( stvec_temp ) ); \
+ allowed; \
+ } )
+
+/**
+ * Check if CSR can be written
+ *
+ * @v name CSR name
+ * @v value Value to write
+ * @v allowed CSR can be written
+ */
+#define csr_can_write( name, value ) ( { \
+ unsigned long stvec_orig; \
+ unsigned long stvec_temp; \
+ unsigned long csr = (value); \
+ int allowed = 0; \
+ \
+ __asm__ __volatile__ ( /* Set temporary trap vector */ \
+ "la %3, 1f\n\t" \
+ "csrrw %2, stvec, %3\n\t" \
+ /* Try writing CSR */ \
+ "csrrw %1, " name ", %1\n\t" \
+ /* Mark as allowed if not trapped */ \
+ "addi %0, %0, 1\n\t" \
+ /* Temporary trap vector */ \
+ ".balign 4\n\t" \
+ "\n1:\n\t" \
+ /* Restore original trap vector */ \
+ "csrw stvec, %2\n\t" \
+ : "+r" ( allowed ), \
+ "+r" ( csr ), \
+ "=r" ( stvec_orig ), \
+ "=r" ( stvec_temp ) ); \
+ allowed; \
+ } )
+
+#endif /* _IPXE_CSR_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 <ipxe/errno/linux.h>
+
+#endif /* _IPXE_ERRNO_SBI_H */
diff --git a/src/arch/riscv/include/ipxe/hart.h b/src/arch/riscv/include/ipxe/hart.h
new file mode 100644
index 000000000..c201b6c77
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/hart.h
@@ -0,0 +1,16 @@
+#ifndef _IPXE_HART_H
+#define _IPXE_HART_H
+
+/** @file
+ *
+ * Hardware threads (harts)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+extern unsigned long boot_hart;
+
+extern int hart_supported ( const char *ext );
+
+#endif /* _IPXE_HART_H */
diff --git a/src/arch/riscv/include/ipxe/riscv_dma.h b/src/arch/riscv/include/ipxe/riscv_dma.h
new file mode 100644
index 000000000..d35904d88
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/riscv_dma.h
@@ -0,0 +1,45 @@
+#ifndef _IPXE_RISCV_DMA_H
+#define _IPXE_RISCV_DMA_H
+
+/** @file
+ *
+ * iPXE DMA API for RISC-V
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#ifdef DMAAPI_RISCV
+#define DMAAPI_PREFIX_riscv
+#else
+#define DMAAPI_PREFIX_riscv __riscv_
+#endif
+
+/**
+ * Set addressable space mask
+ *
+ * @v dma DMA device
+ * @v mask Addressable space mask
+ */
+static inline __always_inline void
+DMAAPI_INLINE ( riscv, dma_set_mask ) ( struct dma_device *dma __unused,
+ physaddr_t mask __unused ) {
+
+ /* Nothing to do */
+}
+
+/**
+ * Get DMA address from virtual address
+ *
+ * @v map DMA mapping
+ * @v addr Address within the mapped region
+ * @ret addr Device-side DMA address
+ */
+static inline __always_inline physaddr_t
+DMAAPI_INLINE ( riscv, dma ) ( struct dma_mapping *map __unused, void *addr ) {
+
+ /* Use physical address as device address */
+ return virt_to_phys ( addr );
+}
+
+#endif /* _IPXE_RISCV_DMA_H */
diff --git a/src/arch/riscv/include/ipxe/riscv_io.h b/src/arch/riscv/include/ipxe/riscv_io.h
new file mode 100644
index 000000000..539dbd7ed
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/riscv_io.h
@@ -0,0 +1,141 @@
+#ifndef _IPXE_RISCV_IO_H
+#define _IPXE_RISCV_IO_H
+
+/** @file
+ *
+ * iPXE I/O API for RISC-V
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#ifdef IOAPI_RISCV
+#define IOAPI_PREFIX_riscv
+#else
+#define IOAPI_PREFIX_riscv __riscv_
+#endif
+
+#include <ipxe/dummy_pio.h>
+
+/*
+ * Memory space mappings
+ *
+ */
+
+/*
+ * Physical<->Bus address mappings
+ *
+ */
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( riscv, phys_to_bus ) ( unsigned long phys_addr ) {
+ return phys_addr;
+}
+
+static inline __always_inline unsigned long
+IOAPI_INLINE ( riscv, bus_to_phys ) ( unsigned long bus_addr ) {
+ return bus_addr;
+}
+
+/*
+ * MMIO reads and writes
+ *
+ */
+
+/* Single-register read */
+#define RISCV_READX( _suffix, _type, _insn_suffix ) \
+static inline __always_inline _type \
+IOAPI_INLINE ( riscv, read ## _suffix ) ( volatile _type *io_addr ) { \
+ unsigned long data; \
+ __asm__ __volatile__ ( "fence io, io\n\t" \
+ "l" _insn_suffix " %0, %1\n\t" \
+ : "=r" ( data ) : "m" ( *io_addr ) ); \
+ return data; \
+}
+
+/* Single-register write */
+#define RISCV_WRITEX( _suffix, _type, _insn_suffix) \
+static inline __always_inline void \
+IOAPI_INLINE ( riscv, write ## _suffix ) ( _type data, \
+ volatile _type *io_addr ) { \
+ __asm__ __volatile__ ( "fence io, io\n\t" \
+ "s" _insn_suffix " %0, %1\n\t" \
+ : : "r" ( data ), "m" ( *io_addr ) ); \
+}
+
+/* Double-register hopefully-fused read */
+#define RISCV_READX_FUSED( _suffix, _type, _insn_suffix ) \
+static inline __always_inline _type \
+IOAPI_INLINE ( riscv, read ## _suffix ) ( volatile _type *io_addr ) { \
+ union { \
+ unsigned long half[2]; \
+ _type data; \
+ } u; \
+ __asm__ __volatile__ ( "fence io, io\n\t" \
+ "l" _insn_suffix " %0, 0(%2)\n\t" \
+ "l" _insn_suffix " %1, %3(%2)\n\t" \
+ : "=&r" ( u.half[0] ), \
+ "=&r" ( u.half[1] ) \
+ : "r" ( io_addr ), \
+ "i" ( sizeof ( u.half[0] ) ) ); \
+ return u.data; \
+}
+
+/* Double-register hopefully-fused write */
+#define RISCV_WRITEX_FUSED( _suffix, _type, _insn_suffix ) \
+static inline __always_inline void \
+IOAPI_INLINE ( riscv, write ## _suffix ) ( _type data, \
+ volatile _type *io_addr ) { \
+ union { \
+ unsigned long half[2]; \
+ _type data; \
+ } u = { .data = data }; \
+ __asm__ __volatile__ ( "fence io, io\n\t" \
+ "s" _insn_suffix " %0, 0(%2)\n\t" \
+ "s" _insn_suffix " %1, %3(%2)\n\t" : \
+ : "r" ( u.half[0] ), \
+ "r" ( u.half[1] ), \
+ "r" ( io_addr ), \
+ "i" ( sizeof ( u.half[0] ) ) ); \
+}
+
+RISCV_READX ( b, uint8_t, "bu" );
+RISCV_WRITEX ( b, uint8_t, "b" );
+
+RISCV_READX ( w, uint16_t, "hu" );
+RISCV_WRITEX ( w, uint16_t, "h" );
+
+#if __riscv_xlen > 32
+ RISCV_READX ( l, uint32_t, "wu" );
+ RISCV_WRITEX ( l, uint32_t, "w" );
+#else
+ RISCV_READX ( l, uint32_t, "w" );
+ RISCV_WRITEX ( l, uint32_t, "w" );
+#endif
+
+#if __riscv_xlen >= 64
+ #if __riscv_xlen > 64
+ RISCV_READX ( q, uint64_t, "du" );
+ RISCV_WRITEX ( q, uint64_t, "d" );
+ #else
+ RISCV_READX ( q, uint64_t, "d" );
+ RISCV_WRITEX ( q, uint64_t, "d" );
+ #endif
+#else
+ RISCV_READX_FUSED ( q, uint64_t, "w" );
+ RISCV_WRITEX_FUSED ( q, uint64_t, "w" );
+#endif
+
+/*
+ * Memory barrier
+ *
+ */
+static inline __always_inline void
+IOAPI_INLINE ( riscv, mb ) ( void ) {
+ __asm__ __volatile__ ( "fence" : : : "memory" );
+}
+
+/* Dummy PIO */
+DUMMY_PIO ( riscv );
+
+#endif /* _IPXE_RISCV_IO_H */
diff --git a/src/arch/riscv/include/ipxe/sbi.h b/src/arch/riscv/include/ipxe/sbi.h
new file mode 100644
index 000000000..4364098b9
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/sbi.h
@@ -0,0 +1,213 @@
+#ifndef _IPXE_SBI_H
+#define _IPXE_SBI_H
+
+/** @file
+ *
+ * Supervisor Binary Interface (SBI)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+/** An SBI function return value */
+struct sbi_return {
+ /** Error status (returned in a0) */
+ long error;
+ /** Data value (returned in a1) */
+ long value;
+};
+
+/**
+ * @defgroup sbierrors SBI errors
+ *
+ * *{
+ */
+#define SBI_SUCCESS 0 /**< Completed successfully */
+#define SBI_ERR_FAILED -1 /**< Failed */
+#define SBI_ERR_NOT_SUPPORTED -2 /**< Not supported */
+#define SBI_ERR_INVALID_PARAM -3 /**< Invalid parameter(s) */
+#define SBI_ERR_DENIED -4 /**< Denied or not allowed */
+#define SBI_ERR_INVALID_ADDRESS -5 /**< Invalid address(es) */
+#define SBI_ERR_ALREADY_AVAILABLE -6 /**< Already available */
+#define SBI_ERR_ALREADY_STARTED -7 /**< Already started */
+#define SBI_ERR_ALREADY_STOPPED -8 /**< Already stopped */
+#define SBI_ERR_NO_SHMEM -9 /**< Shared memory not available */
+#define SBI_ERR_INVALID_STATE -10 /**< Invalid state */
+#define SBI_ERR_BAD_RANGE -11 /**< Bad (or invalid) range */
+#define SBI_ERR_TIMEOUT -12 /**< Failed due to timeout */
+#define SBI_ERR_IO -13 /**< Input/output error */
+/** @} */
+
+/** Construct SBI extension ID */
+#define SBI_EID( c1, c2, c3, c4 ) \
+ ( (int) ( ( (c1) << 24 ) | ( (c2) << 16 ) | ( (c3) << 8 ) | (c4) ) )
+
+/**
+ * Call supervisor with no parameters
+ *
+ * @v eid Extension ID
+ * @v fid Function ID
+ * @ret ret Return value
+ */
+static inline __attribute__ (( always_inline )) struct sbi_return
+sbi_ecall_0 ( int eid, int fid ) {
+ register unsigned long a7 asm ( "a7" ) = ( ( long ) eid );
+ register unsigned long a6 asm ( "a6" ) = ( ( long ) fid );
+ register unsigned long a0 asm ( "a0" );
+ register unsigned long a1 asm ( "a1" );
+ struct sbi_return ret;
+
+ __asm__ __volatile__ ( "ecall"
+ : "=r" ( a0 ), "=r" ( a1 )
+ : "r" ( a6 ), "r" ( a7 )
+ : "memory" );
+ ret.error = a0;
+ ret.value = a1;
+ return ret;
+}
+
+/**
+ * Call supervisor with one parameter
+ *
+ * @v eid Extension ID
+ * @v fid Function ID
+ * @v p0 Parameter 0
+ * @ret ret Return value
+ */
+static inline __attribute__ (( always_inline )) struct sbi_return
+sbi_ecall_1 ( int eid, int fid, unsigned long p0 ) {
+ register unsigned long a7 asm ( "a7" ) = ( ( long ) eid );
+ register unsigned long a6 asm ( "a6" ) = ( ( long ) fid );
+ register unsigned long a0 asm ( "a0" ) = p0;
+ register unsigned long a1 asm ( "a1" );
+ struct sbi_return ret;
+
+ __asm__ __volatile__ ( "ecall"
+ : "+r" ( a0 ), "=r" ( a1 )
+ : "r" ( a6 ), "r" ( a7 )
+ : "memory" );
+ ret.error = a0;
+ ret.value = a1;
+ return ret;
+}
+
+/**
+ * Call supervisor with two parameters
+ *
+ * @v eid Extension ID
+ * @v fid Function ID
+ * @v p0 Parameter 0
+ * @v p1 Parameter 1
+ * @ret ret Return value
+ */
+static inline __attribute__ (( always_inline )) struct sbi_return
+sbi_ecall_2 ( int eid, int fid, unsigned long p0, unsigned long p1 ) {
+ register unsigned long a7 asm ( "a7" ) = ( ( long ) eid );
+ register unsigned long a6 asm ( "a6" ) = ( ( long ) fid );
+ register unsigned long a0 asm ( "a0" ) = p0;
+ register unsigned long a1 asm ( "a1" ) = p1;
+ struct sbi_return ret;
+
+ __asm__ __volatile__ ( "ecall"
+ : "+r" ( a0 ), "+r" ( a1 )
+ : "r" ( a6 ), "r" ( a7 )
+ : "memory" );
+ ret.error = a0;
+ ret.value = a1;
+ return ret;
+}
+
+/**
+ * Call supervisor with three parameters
+ *
+ * @v eid Extension ID
+ * @v fid Function ID
+ * @v p0 Parameter 0
+ * @v p1 Parameter 1
+ * @v p2 Parameter 2
+ * @ret ret Return value
+ */
+static inline __attribute__ (( always_inline )) struct sbi_return
+sbi_ecall_3 ( int eid, int fid, unsigned long p0, unsigned long p1,
+ unsigned long p2 ) {
+ register unsigned long a7 asm ( "a7" ) = ( ( long ) eid );
+ register unsigned long a6 asm ( "a6" ) = ( ( long ) fid );
+ register unsigned long a0 asm ( "a0" ) = p0;
+ register unsigned long a1 asm ( "a1" ) = p1;
+ register unsigned long a2 asm ( "a2" ) = p2;
+ struct sbi_return ret;
+
+ __asm__ __volatile__ ( "ecall"
+ : "+r" ( a0 ), "+r" ( a1 )
+ : "r" ( a2 ), "r" ( a6 ), "r" ( a7 )
+ : "memory" );
+ ret.error = a0;
+ ret.value = a1;
+ return ret;
+}
+
+/**
+ * Call supervisor with no parameters
+ *
+ * @v fid Legacy function ID
+ * @ret ret Return value
+ */
+static inline __attribute__ (( always_inline )) long
+sbi_legacy_ecall_0 ( int fid ) {
+ register unsigned long a7 asm ( "a7" ) = ( ( long ) fid );
+ register unsigned long a0 asm ( "a0" );
+
+ __asm__ __volatile__ ( "ecall"
+ : "=r" ( a0 )
+ : "r" ( a7 )
+ : "memory" );
+ return a0;
+}
+
+/**
+ * Call supervisor with one parameter
+ *
+ * @v fid Legacy function ID
+ * @v p0 Parameter 0
+ * @ret ret Return value
+ */
+static inline __attribute__ (( always_inline )) long
+sbi_legacy_ecall_1 ( int fid, unsigned long p0 ) {
+ register unsigned long a7 asm ( "a7" ) = ( ( long ) fid );
+ register unsigned long a0 asm ( "a0" ) = p0;
+
+ __asm__ __volatile__ ( "ecall"
+ : "+r" ( a0 )
+ : "r" ( a7 )
+ : "memory" );
+ return a0;
+}
+
+/** Convert an SBI error code to an iPXE status code */
+#define ESBI( error ) EPLATFORM ( EINFO_EPLATFORM, error )
+
+/** Legacy extensions */
+#define SBI_LEGACY_PUTCHAR 0x01 /**< Console Put Character */
+#define SBI_LEGACY_GETCHAR 0x02 /**< Console Get Character */
+#define SBI_LEGACY_SHUTDOWN 0x08 /**< System Shutdown */
+
+/** Base extension */
+#define SBI_BASE 0x10
+#define SBI_BASE_MVENDORID 0x04 /**< Get machine vendor ID */
+
+/** System reset extension */
+#define SBI_SRST SBI_EID ( 'S', 'R', 'S', 'T' )
+#define SBI_SRST_SYSTEM_RESET 0x00 /**< Reset system */
+#define SBI_RESET_SHUTDOWN 0x00000000 /**< Shutdown */
+#define SBI_RESET_COLD 0x00000001 /**< Cold reboot */
+#define SBI_RESET_WARM 0x00000002 /**< Warm reboot */
+
+/** Debug console extension */
+#define SBI_DBCN SBI_EID ( 'D', 'B', 'C', 'N' )
+#define SBI_DBCN_WRITE 0x00 /**< Console Write */
+#define SBI_DBCN_READ 0x01 /**< Console Read */
+#define SBI_DBCN_WRITE_BYTE 0x02 /**< Console Write Byte */
+
+#endif /* _IPXE_SBI_H */
diff --git a/src/arch/riscv/include/ipxe/sbi_reboot.h b/src/arch/riscv/include/ipxe/sbi_reboot.h
new file mode 100644
index 000000000..e8d6e82bf
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/sbi_reboot.h
@@ -0,0 +1,18 @@
+#ifndef _IPXE_BIOS_REBOOT_H
+#define _IPXE_BIOS_REBOOT_H
+
+/** @file
+ *
+ * Supervisor Binary Interface (SBI) reboot mechanism
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#ifdef REBOOT_SBI
+#define REBOOT_PREFIX_sbi
+#else
+#define REBOOT_PREFIX_sbi __sbi_
+#endif
+
+#endif /* _IPXE_BIOS_REBOOT_H */
diff --git a/src/arch/riscv/include/ipxe/svpage.h b/src/arch/riscv/include/ipxe/svpage.h
new file mode 100644
index 000000000..897a3379a
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/svpage.h
@@ -0,0 +1,28 @@
+#ifndef _IPXE_SVPAGE_H
+#define _IPXE_SVPAGE_H
+
+/** @file
+ *
+ * Supervisor page table management
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+#ifdef IOMAP_SVPAGE
+#define IOMAP_PREFIX_svpage
+#else
+#define IOMAP_PREFIX_svpage __svpage_
+#endif
+
+static inline __always_inline unsigned long
+IOMAP_INLINE ( svpage, io_to_bus ) ( volatile const void *io_addr ) {
+ /* Not easy to do; just return the CPU address for debugging purposes */
+ return ( ( intptr_t ) io_addr );
+}
+
+extern void * svpage_dma32 ( void );
+
+#endif /* _IPXE_SVPAGE_H */
diff --git a/src/arch/riscv/include/ipxe/xthead.h b/src/arch/riscv/include/ipxe/xthead.h
new file mode 100644
index 000000000..d0c9449ef
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/xthead.h
@@ -0,0 +1,21 @@
+#ifndef _IPXE_XTHEAD_H
+#define _IPXE_XTHEAD_H
+
+/** @file
+ *
+ * T-Head vendor extensions
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/** T-Head machine vendor ID */
+#define THEAD_MVENDORID 0x5b7
+
+/** T-Head SXSTATUS CSR */
+#define THEAD_SXSTATUS 0x5c0
+#define THEAD_SXSTATUS_THEADISAEE 0x00400000 /**< General ISA extensions */
+
+extern int xthead_supported ( unsigned long feature );
+
+#endif /* _IPXE_XTHEAD_H */
diff --git a/src/arch/riscv/include/ipxe/zicbom.h b/src/arch/riscv/include/ipxe/zicbom.h
new file mode 100644
index 000000000..4ba165f3c
--- /dev/null
+++ b/src/arch/riscv/include/ipxe/zicbom.h
@@ -0,0 +1,17 @@
+#ifndef _IPXE_ZICBOM_H
+#define _IPXE_ZICBOM_H
+
+/** @file
+ *
+ * Cache-block management operations (Zicbom)
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <stdint.h>
+
+extern void cache_clean ( const void *start, size_t len );
+extern void cache_invalidate ( void *start, size_t len );
+
+#endif /* _IPXE_ZICBOM_H */