diff options
Diffstat (limited to 'src/arch/riscv/include')
29 files changed, 1577 insertions, 0 deletions
diff --git a/src/arch/riscv/include/bits/bigint.h b/src/arch/riscv/include/bits/bigint.h new file mode 100644 index 000000000..7f87d9748 --- /dev/null +++ b/src/arch/riscv/include/bits/bigint.h @@ -0,0 +1,381 @@ +#ifndef _BITS_BIGINT_H +#define _BITS_BIGINT_H + +/** @file + * + * Big integer support + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> +#include <string.h> +#include <strings.h> + +/** Element of a big integer */ +typedef unsigned long bigint_element_t; + +/** + * Initialise big integer + * + * @v value0 Element 0 of big integer to initialise + * @v size Number of elements + * @v data Raw data + * @v len Length of raw data + */ +static inline __attribute__ (( always_inline )) void +bigint_init_raw ( unsigned long *value0, unsigned int size, + const void *data, size_t len ) { + size_t pad_len = ( sizeof ( bigint_t ( size ) ) - len ); + uint8_t *value_byte = ( ( void * ) value0 ); + const uint8_t *data_byte = ( data + len ); + + /* Copy raw data in reverse order, padding with zeros */ + while ( len-- ) + *(value_byte++) = *(--data_byte); + while ( pad_len-- ) + *(value_byte++) = 0; +} + +/** + * Add big integers + * + * @v addend0 Element 0 of big integer to add + * @v value0 Element 0 of big integer to be added to + * @v size Number of elements + * @ret carry Carry out + */ +static inline __attribute__ (( always_inline )) int +bigint_add_raw ( const unsigned long *addend0, unsigned long *value0, + unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); + unsigned long *valueN = ( value0 + size ); + unsigned long *discard_addend; + unsigned long *discard_value; + unsigned long discard_addend_i; + unsigned long discard_value_i; + unsigned long discard_temp; + unsigned long carry; + + __asm__ __volatile__ ( "\n1:\n\t" + /* Load addend[i] and value[i] */ + LOADN " %2, (%0)\n\t" + LOADN " %3, (%1)\n\t" + /* Add carry flag and addend */ + "add %3, %3, %5\n\t" + "sltu %4, %3, %5\n\t" + "add %3, %3, %2\n\t" + "sltu %5, %3, %2\n\t" + "or %5, %4, %5\n\t" + /* Store value[i] */ + STOREN " %3, (%1)\n\t" + /* Loop */ + "addi %0, %0, %8\n\t" + "addi %1, %1, %8\n\t" + "bne %1, %7, 1b\n\t" + : "=&r" ( discard_addend ), + "=&r" ( discard_value ), + "=&r" ( discard_addend_i ), + "=&r" ( discard_value_i ), + "=&r" ( discard_temp ), + "=&r" ( carry ), + "+m" ( *value ) + : "r" ( valueN ), + "i" ( sizeof ( unsigned long ) ), + "0" ( addend0 ), "1" ( value0 ), "5" ( 0 ) ); + return carry; +} + +/** + * Subtract big integers + * + * @v subtrahend0 Element 0 of big integer to subtract + * @v value0 Element 0 of big integer to be subtracted from + * @v size Number of elements + * @ret borrow Borrow out + */ +static inline __attribute__ (( always_inline )) int +bigint_subtract_raw ( const unsigned long *subtrahend0, unsigned long *value0, + unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); + unsigned long *valueN = ( value0 + size ); + unsigned long *discard_subtrahend; + unsigned long *discard_value; + unsigned long discard_subtrahend_i; + unsigned long discard_value_i; + unsigned long discard_temp; + unsigned long borrow; + + __asm__ __volatile__ ( "\n1:\n\t" + /* Load subtrahend[i] and value[i] */ + LOADN " %2, (%0)\n\t" + LOADN " %3, (%1)\n\t" + /* Subtract carry flag and subtrahend */ + "sltu %4, %3, %5\n\t" + "sub %3, %3, %5\n\t" + "sltu %5, %3, %2\n\t" + "sub %3, %3, %2\n\t" + "or %5, %5, %4\n\t" + /* Store value[i] */ + STOREN " %3, (%1)\n\t" + /* Loop */ + "addi %0, %0, %8\n\t" + "addi %1, %1, %8\n\t" + "bne %1, %7, 1b\n\t" + : "=&r" ( discard_subtrahend ), + "=&r" ( discard_value ), + "=&r" ( discard_subtrahend_i ), + "=&r" ( discard_value_i ), + "=&r" ( discard_temp ), + "=&r" ( borrow ), + "+m" ( *value ) + : "r" ( valueN ), + "i" ( sizeof ( unsigned long ) ), + "0" ( subtrahend0 ), "1" ( value0 ), + "5" ( 0 ) ); + return borrow; +} + +/** + * Shift big integer left + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @ret out Bit shifted out + */ +static inline __attribute__ (( always_inline )) int +bigint_shl_raw ( unsigned long *value0, unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); + unsigned long *valueN = ( value0 + size ); + unsigned long *discard_value; + unsigned long discard_value_i; + unsigned long discard_temp; + unsigned long carry; + + __asm__ __volatile__ ( "\n1:\n\t" + /* Load value[i] */ + LOADN " %1, (%0)\n\t" + /* Shift left */ + "slli %2, %1, 1\n\t" + "or %2, %2, %3\n\t" + "srli %3, %1, %7\n\t" + /* Store value[i] */ + STOREN " %2, (%0)\n\t" + /* Loop */ + "addi %0, %0, %6\n\t" + "bne %0, %5, 1b\n\t" + : "=&r" ( discard_value ), + "=&r" ( discard_value_i ), + "=&r" ( discard_temp ), + "=&r" ( carry ), + "+m" ( *value ) + : "r" ( valueN ), + "i" ( sizeof ( unsigned long ) ), + "i" ( ( 8 * sizeof ( unsigned long ) - 1 ) ), + "0" ( value0 ), "3" ( 0 ) ); + return carry; +} + +/** + * Shift big integer right + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @ret out Bit shifted out + */ +static inline __attribute__ (( always_inline )) int +bigint_shr_raw ( unsigned long *value0, unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); + unsigned long *valueN = ( value0 + size ); + unsigned long *discard_value; + unsigned long discard_value_i; + unsigned long discard_temp; + unsigned long carry; + + __asm__ __volatile__ ( "\n1:\n\t" + /* Load value[i] */ + LOADN " %1, %6(%0)\n\t" + /* Shift right */ + "srli %2, %1, 1\n\t" + "or %2, %2, %3\n\t" + "slli %3, %1, %7\n\t" + /* Store value[i] */ + STOREN " %2, %6(%0)\n\t" + /* Loop */ + "addi %0, %0, %6\n\t" + "bne %0, %5, 1b\n\t" + : "=&r" ( discard_value ), + "=&r" ( discard_value_i ), + "=&r" ( discard_temp ), + "=&r" ( carry ), + "+m" ( *value ) + : "r" ( value0 ), + "i" ( -( sizeof ( unsigned long ) ) ), + "i" ( ( 8 * sizeof ( unsigned long ) - 1 ) ), + "0" ( valueN ), "3" ( 0 ) ); + return ( !! carry ); +} + +/** + * Test if big integer is equal to zero + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @ret is_zero Big integer is equal to zero + */ +static inline __attribute__ (( always_inline, pure )) int +bigint_is_zero_raw ( const unsigned long *value0, unsigned int size ) { + const unsigned long *value = value0; + unsigned long value_i; + + do { + value_i = *(value++); + if ( value_i ) + break; + } while ( --size ); + + return ( value_i == 0 ); +} + +/** + * Compare big integers + * + * @v value0 Element 0 of big integer + * @v reference0 Element 0 of reference big integer + * @v size Number of elements + * @ret geq Big integer is greater than or equal to the reference + */ +static inline __attribute__ (( always_inline, pure )) int +bigint_is_geq_raw ( const unsigned long *value0, + const unsigned long *reference0, unsigned int size ) { + const unsigned long *value = ( value0 + size ); + const unsigned long *reference = ( reference0 + size ); + unsigned long value_i; + unsigned long reference_i; + + do { + value_i = *(--value); + reference_i = *(--reference); + if ( value_i != reference_i ) + break; + } while ( --size ); + + return ( value_i >= reference_i ); +} + +/** + * Find highest bit set in big integer + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @ret max_bit Highest bit set + 1 (or 0 if no bits set) + */ +static inline __attribute__ (( always_inline )) int +bigint_max_set_bit_raw ( const unsigned long *value0, unsigned int size ) { + const unsigned long *value = ( value0 + size ); + int max_bit = ( 8 * sizeof ( bigint_t ( size ) ) ); + unsigned long value_i; + + do { + value_i = *(--value); + max_bit -= ( ( 8 * sizeof ( *value0 ) ) - fls ( value_i ) ); + if ( value_i ) + break; + } while ( --size ); + + return max_bit; +} + +/** + * Grow big integer + * + * @v source0 Element 0 of source big integer + * @v source_size Number of elements in source big integer + * @v dest0 Element 0 of destination big integer + * @v dest_size Number of elements in destination big integer + */ +static inline __attribute__ (( always_inline )) void +bigint_grow_raw ( const unsigned long *source0, unsigned int source_size, + unsigned long *dest0, unsigned int dest_size ) { + unsigned int pad_size = ( dest_size - source_size ); + + memcpy ( dest0, source0, sizeof ( bigint_t ( source_size ) ) ); + memset ( ( dest0 + source_size ), 0, sizeof ( bigint_t ( pad_size ) ) ); +} + +/** + * Shrink big integer + * + * @v source0 Element 0 of source big integer + * @v source_size Number of elements in source big integer + * @v dest0 Element 0 of destination big integer + * @v dest_size Number of elements in destination big integer + */ +static inline __attribute__ (( always_inline )) void +bigint_shrink_raw ( const unsigned long *source0, + unsigned int source_size __unused, + unsigned long *dest0, unsigned int dest_size ) { + + memcpy ( dest0, source0, sizeof ( bigint_t ( dest_size ) ) ); +} + +/** + * Finalise big integer + * + * @v value0 Element 0 of big integer to finalise + * @v size Number of elements + * @v out Output buffer + * @v len Length of output buffer + */ +static inline __attribute__ (( always_inline )) void +bigint_done_raw ( const unsigned long *value0, unsigned int size __unused, + void *out, size_t len ) { + const uint8_t *value_byte = ( ( const void * ) value0 ); + uint8_t *out_byte = ( out + len ); + + /* Copy raw data in reverse order */ + while ( len-- ) + *(--out_byte) = *(value_byte++); +} + +/** + * Multiply big integer elements + * + * @v multiplicand Multiplicand element + * @v multiplier Multiplier element + * @v result Result element + * @v carry Carry element + */ +static inline __attribute__ (( always_inline )) void +bigint_multiply_one ( const unsigned long multiplicand, + const unsigned long multiplier, + unsigned long *result, unsigned long *carry ) { + unsigned long discard_low; + unsigned long discard_high; + unsigned long discard_carry; + + __asm__ __volatile__ ( /* Perform multiplication */ + "mulhu %1, %5, %6\n\t" + "mul %0, %5, %6\n\t" + /* Accumulate low half */ + "add %3, %3, %0\n\t" + "sltu %2, %3, %0\n\t" + "add %1, %1, %2\n\t" + /* Accumulate carry (cannot overflow) */ + "add %3, %3, %4\n\t" + "sltu %2, %3, %4\n\t" + "add %4, %1, %2\n\t" + : "=r" ( discard_low ), + "=&r" ( discard_high ), + "=r" ( discard_carry ), + "+r" ( *result ), + "+r" ( *carry ) + : "r" ( multiplicand ), + "r" ( multiplier ) ); +} + +#endif /* _BITS_BIGINT_H */ diff --git a/src/arch/riscv/include/bits/bitops.h b/src/arch/riscv/include/bits/bitops.h new file mode 100644 index 000000000..2019db99a --- /dev/null +++ b/src/arch/riscv/include/bits/bitops.h @@ -0,0 +1,82 @@ +#ifndef _BITS_BITOPS_H +#define _BITS_BITOPS_H + +/** @file + * + * RISC-V bit operations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> + +/** + * Test and set bit atomically + * + * @v bit Bit to set + * @v bits Bit field + * @ret old Old value of bit (zero or non-zero) + */ +static inline __attribute__ (( always_inline )) int +test_and_set_bit ( unsigned int bit, volatile void *bits ) { + unsigned int index = ( bit / 32 ); + unsigned int offset = ( bit % 32 ); + volatile uint32_t *word = ( ( ( volatile uint32_t * ) bits ) + index ); + uint32_t mask = ( 1U << offset ); + uint32_t old; + + __asm__ __volatile__ ( "amoor.w %0, %2, %1" + : "=r" ( old ), "+A" ( *word ) + : "r" ( mask ) ); + + return ( !! ( old & mask ) ); +} + +/** + * Test and clear bit atomically + * + * @v bit Bit to set + * @v bits Bit field + * @ret old Old value of bit (zero or non-zero) + */ +static inline __attribute__ (( always_inline )) int +test_and_clear_bit ( unsigned int bit, volatile void *bits ) { + unsigned int index = ( bit / 32 ); + unsigned int offset = ( bit % 32 ); + volatile uint32_t *word = ( ( ( volatile uint32_t * ) bits ) + index ); + uint32_t mask = ( 1U << offset ); + uint32_t old; + + __asm__ __volatile__ ( "amoand.w %0, %2, %1" + : "=r" ( old ), "+A" ( *word ) + : "r" ( ~mask ) ); + + return ( !! ( old & mask ) ); +} + +/** + * Set bit atomically + * + * @v bit Bit to set + * @v bits Bit field + */ +static inline __attribute__ (( always_inline )) void +set_bit ( unsigned int bit, volatile void *bits ) { + + test_and_set_bit ( bit, bits ); +} + +/** + * Clear bit atomically + * + * @v bit Bit to set + * @v bits Bit field + */ +static inline __attribute__ (( always_inline )) void +clear_bit ( unsigned int bit, volatile void *bits ) { + + test_and_clear_bit ( bit, bits ); +} + +#endif /* _BITS_BITOPS_H */ diff --git a/src/arch/riscv/include/bits/byteswap.h b/src/arch/riscv/include/bits/byteswap.h new file mode 100644 index 000000000..56d03f64e --- /dev/null +++ b/src/arch/riscv/include/bits/byteswap.h @@ -0,0 +1,48 @@ +#ifndef _BITS_BYTESWAP_H +#define _BITS_BYTESWAP_H + +/** @file + * + * Byte-order swapping functions + * + */ + +#include <stdint.h> + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +extern __asmcall uint64_t riscv_swap_word ( uint64_t x ); +extern __asmcall unsigned long riscv_swap_half ( unsigned long x ); +extern __asmcall unsigned long riscv_swap_byte ( unsigned long x ); + +static inline __attribute__ (( always_inline, const )) uint16_t +__bswap_variable_16 ( uint16_t x ) { + return riscv_swap_byte ( x ); +} + +static inline __attribute__ (( always_inline )) void +__bswap_16s ( uint16_t *x ) { + *x = riscv_swap_byte ( *x ); +} + +static inline __attribute__ (( always_inline, const )) uint32_t +__bswap_variable_32 ( uint32_t x ) { + return riscv_swap_half ( x ); +} + +static inline __attribute__ (( always_inline )) void +__bswap_32s ( uint32_t *x ) { + *x = riscv_swap_half ( *x ); +} + +static inline __attribute__ (( always_inline, const )) uint64_t +__bswap_variable_64 ( uint64_t x ) { + return riscv_swap_word ( x ); +} + +static inline __attribute__ (( always_inline )) void +__bswap_64s ( uint64_t *x ) { + *x = riscv_swap_word ( *x ); +} + +#endif /* _BITS_BYTESWAP_H */ diff --git a/src/arch/riscv/include/bits/compiler.h b/src/arch/riscv/include/bits/compiler.h new file mode 100644 index 000000000..624a16108 --- /dev/null +++ b/src/arch/riscv/include/bits/compiler.h @@ -0,0 +1,40 @@ +#ifndef _BITS_COMPILER_H +#define _BITS_COMPILER_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** Dummy relocation type */ +#define RELOC_TYPE_NONE R_RISCV_NONE + +/* Determine load/store instructions for natural bit width */ +#if __riscv_xlen == 128 +#define NATURAL_SUFFIX q +#elif __riscv_xlen == 64 +#define NATURAL_SUFFIX d +#elif __riscv_xlen == 32 +#define NATURAL_SUFFIX w +#else +#error "Unsupported bit width" +#endif +#ifdef ASSEMBLY +#define LOADN _C2 ( L, NATURAL_SUFFIX ) +#define STOREN _C2 ( S, NATURAL_SUFFIX ) +#else +#define LOADN "L" _S2 ( NATURAL_SUFFIX ) +#define STOREN "S" _S2 ( NATURAL_SUFFIX ) +#endif + +#ifndef ASSEMBLY + +/** Unprefixed constant operand modifier */ +#define ASM_NO_PREFIX "" + +/** Declare a function with standard calling conventions */ +#define __asmcall + +/** Declare a function with libgcc implicit linkage */ +#define __libgcc + +#endif /* ASSEMBLY */ + +#endif /* _BITS_COMPILER_H */ diff --git a/src/arch/riscv/include/bits/dma.h b/src/arch/riscv/include/bits/dma.h new file mode 100644 index 000000000..f7decd14c --- /dev/null +++ b/src/arch/riscv/include/bits/dma.h @@ -0,0 +1,14 @@ +#ifndef _BITS_DMA_H +#define _BITS_DMA_H + +/** @file + * + * RISCV-specific DMA API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/riscv_dma.h> + +#endif /* _BITS_DMA_H */ diff --git a/src/arch/riscv/include/bits/endian.h b/src/arch/riscv/include/bits/endian.h new file mode 100644 index 000000000..85718cfdd --- /dev/null +++ b/src/arch/riscv/include/bits/endian.h @@ -0,0 +1,8 @@ +#ifndef _BITS_ENDIAN_H +#define _BITS_ENDIAN_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#define __BYTE_ORDER __LITTLE_ENDIAN + +#endif /* _BITS_ENDIAN_H */ diff --git a/src/arch/riscv/include/bits/errfile.h b/src/arch/riscv/include/bits/errfile.h new file mode 100644 index 000000000..bdd2927a4 --- /dev/null +++ b/src/arch/riscv/include/bits/errfile.h @@ -0,0 +1,24 @@ +#ifndef _BITS_ERRFILE_H +#define _BITS_ERRFILE_H + +/** @file + * + * RISC-V error file identifiers + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @addtogroup errfile Error file identifiers + * @{ + */ + +#define ERRFILE_sbi_reboot ( ERRFILE_ARCH | ERRFILE_CORE | 0x00000000 ) +#define ERRFILE_hart ( ERRFILE_ARCH | ERRFILE_CORE | 0x00010000 ) +#define ERRFILE_zicntr ( ERRFILE_ARCH | ERRFILE_CORE | 0x00020000 ) +#define ERRFILE_zkr ( ERRFILE_ARCH | ERRFILE_CORE | 0x00030000 ) + +/** @} */ + +#endif /* _BITS_ERRFILE_H */ diff --git a/src/arch/riscv/include/bits/io.h b/src/arch/riscv/include/bits/io.h new file mode 100644 index 000000000..4296e318a --- /dev/null +++ b/src/arch/riscv/include/bits/io.h @@ -0,0 +1,17 @@ +#ifndef _BITS_IO_H +#define _BITS_IO_H + +/** @file + * + * RISCV-specific I/O API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** Page shift */ +#define PAGE_SHIFT 12 + +#include <ipxe/riscv_io.h> + +#endif /* _BITS_IO_H */ diff --git a/src/arch/riscv/include/bits/iomap.h b/src/arch/riscv/include/bits/iomap.h new file mode 100644 index 000000000..fd8e37825 --- /dev/null +++ b/src/arch/riscv/include/bits/iomap.h @@ -0,0 +1,14 @@ +#ifndef _BITS_IOMAP_H +#define _BITS_IOMAP_H + +/** @file + * + * RISCV-specific I/O mapping API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/svpage.h> + +#endif /* _BITS_IOMAP_H */ diff --git a/src/arch/riscv/include/bits/lkrn.h b/src/arch/riscv/include/bits/lkrn.h new file mode 100644 index 000000000..d26108647 --- /dev/null +++ b/src/arch/riscv/include/bits/lkrn.h @@ -0,0 +1,34 @@ +#ifndef _BITS_LKRN_H +#define _BITS_LKRN_H + +/** @file + * + * Linux kernel image invocation + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/hart.h> + +/** Header magic value */ +#define LKRN_MAGIC_ARCH LKRN_MAGIC_RISCV + +/** + * Jump to kernel entry point + * + * @v entry Kernel entry point + * @v fdt Device tree + */ +static inline __attribute__ (( noreturn )) void +lkrn_jump ( physaddr_t entry, physaddr_t fdt ) { + register unsigned long a0 asm ( "a0" ) = boot_hart; + register unsigned long a1 asm ( "a1" ) = fdt; + + __asm__ __volatile__ ( "call disable_paging\n\t" + "jr %2\n\t" + : : "r" ( a0 ), "r" ( a1 ), "r" ( entry ) ); + __builtin_unreachable(); +} + +#endif /* _BITS_LKRN_H */ diff --git a/src/arch/riscv/include/bits/nap.h b/src/arch/riscv/include/bits/nap.h new file mode 100644 index 000000000..331399f46 --- /dev/null +++ b/src/arch/riscv/include/bits/nap.h @@ -0,0 +1,20 @@ +#ifndef _BITS_NAP_H +#define _BITS_NAP_H + +/** @file + * + * RISCV-specific CPU sleeping API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * Sleep until next CPU interrupt + * + */ +static inline __attribute__ (( always_inline )) void cpu_halt ( void ) { + __asm__ __volatile__ ( "wfi" ); +} + +#endif /* _BITS_NAP_H */ diff --git a/src/arch/riscv/include/bits/profile.h b/src/arch/riscv/include/bits/profile.h new file mode 100644 index 000000000..e9e003dab --- /dev/null +++ b/src/arch/riscv/include/bits/profile.h @@ -0,0 +1,28 @@ +#ifndef _BITS_PROFILE_H +#define _BITS_PROFILE_H + +/** @file + * + * Profiling + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <stdint.h> + +/** + * Get profiling timestamp + * + * @ret timestamp Timestamp + */ +static inline __attribute__ (( always_inline )) unsigned long +profile_timestamp ( void ) { + unsigned long cycles; + + /* Read timestamp counter */ + __asm__ __volatile__ ( "rdcycle %0" : "=r" ( cycles ) ); + return cycles; +} + +#endif /* _BITS_PROFILE_H */ diff --git a/src/arch/riscv/include/bits/reboot.h b/src/arch/riscv/include/bits/reboot.h new file mode 100644 index 000000000..01272483b --- /dev/null +++ b/src/arch/riscv/include/bits/reboot.h @@ -0,0 +1,14 @@ +#ifndef _BITS_REBOOT_H +#define _BITS_REBOOT_H + +/** @file + * + * RISCV-specific reboot API implementations + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include <ipxe/sbi_reboot.h> + +#endif /* _BITS_REBOOT_H */ diff --git a/src/arch/riscv/include/bits/setjmp.h b/src/arch/riscv/include/bits/setjmp.h new file mode 100644 index 000000000..5186fadaf --- /dev/null +++ b/src/arch/riscv/include/bits/setjmp.h @@ -0,0 +1,16 @@ +#ifndef _BITS_SETJMP_H +#define _BITS_SETJMP_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** A jump buffer */ +typedef struct { + /** Return address (ra) */ + unsigned long ra; + /** Stack pointer (sp) */ + unsigned long sp; + /** Callee-saved registers (s0-s11) */ + unsigned long s[12]; +} jmp_buf[1]; + +#endif /* _BITS_SETJMP_H */ diff --git a/src/arch/riscv/include/bits/stdint.h b/src/arch/riscv/include/bits/stdint.h new file mode 100644 index 000000000..fe1f9946a --- /dev/null +++ b/src/arch/riscv/include/bits/stdint.h @@ -0,0 +1,23 @@ +#ifndef _BITS_STDINT_H +#define _BITS_STDINT_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +typedef __SIZE_TYPE__ size_t; +typedef signed long ssize_t; +typedef signed long off_t; + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef signed long long int64_t; + +typedef unsigned long physaddr_t; +typedef unsigned long intptr_t; + +#endif /* _BITS_STDINT_H */ diff --git a/src/arch/riscv/include/bits/string.h b/src/arch/riscv/include/bits/string.h new file mode 100644 index 000000000..87834d91a --- /dev/null +++ b/src/arch/riscv/include/bits/string.h @@ -0,0 +1,82 @@ +#ifndef _BITS_STRING_H +#define _BITS_STRING_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** @file + * + * String functions + * + */ + +extern void riscv_bzero ( void *dest, size_t len ); +extern void riscv_memset ( void *dest, size_t len, int character ); +extern void riscv_memcpy ( void *dest, const void *src, size_t len ); +extern void riscv_memmove ( void *dest, const void *src, size_t len ); + +/** + * Fill memory region + * + * @v dest Destination region + * @v character Fill character + * @v len Length + * @ret dest Destination region + */ +static inline __attribute__ (( always_inline )) void * +memset ( void *dest, int character, size_t len ) { + + /* For zeroing larger or non-constant lengths, use the + * optimised variable-length zeroing code. + */ + if ( __builtin_constant_p ( character ) && ( character == 0 ) ) { + riscv_bzero ( dest, len ); + return dest; + } + + /* Not necessarily zeroing: use basic variable-length code */ + riscv_memset ( dest, len, character ); + return dest; +} + +/** + * Copy memory region + * + * @v dest Destination region + * @v src Source region + * @v len Length + * @ret dest Destination region + */ +static inline __attribute__ (( always_inline )) void * +memcpy ( void *dest, const void *src, size_t len ) { + + /* Otherwise, use variable-length code */ + riscv_memcpy ( dest, src, len ); + return dest; +} + +/** + * Copy (possibly overlapping) memory region + * + * @v dest Destination region + * @v src Source region + * @v len Length + * @ret dest Destination region + */ +static inline __attribute__ (( always_inline )) void * +memmove ( void *dest, const void *src, size_t len ) { + ssize_t offset = ( dest - src ); + + /* If direction of copy is known to be forwards at build time, + * then use variable-length memcpy(). + */ + if ( __builtin_constant_p ( offset ) && ( offset <= 0 ) ) { + riscv_memcpy ( dest, src, len ); + return dest; + } + + /* Otherwise, use ambidirectional copy */ + riscv_memmove ( dest, src, len ); + return dest; +} + +#endif /* _BITS_STRING_H */ diff --git a/src/arch/riscv/include/bits/strings.h b/src/arch/riscv/include/bits/strings.h new file mode 100644 index 000000000..dd6d458b2 --- /dev/null +++ b/src/arch/riscv/include/bits/strings.h @@ -0,0 +1,91 @@ +#ifndef _BITS_STRINGS_H +#define _BITS_STRINGS_H + +/** @file + * + * String functions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +extern __asmcall unsigned long riscv_ffs ( unsigned long value ); +extern __asmcall unsigned long riscv_fls ( unsigned long value ); + +/** + * Find first (i.e. least significant) set bit + * + * @v value Value + * @ret lsb Least significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __ffsl ( long value ) { + + return riscv_ffs ( value ); +} + +/** + * Find first (i.e. least significant) set bit + * + * @v value Value + * @ret lsb Least significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __ffsll ( long long value ){ + unsigned long low = value; + unsigned long high; + + /* Check machine word size */ + if ( sizeof ( value ) > sizeof ( low ) ) { + /* 32-bit */ + high = ( value >> 32 ); + if ( low ) { + return ( __ffsl ( low ) ); + } else if ( high ) { + return ( 32 + __ffsl ( high ) ); + } else { + return 0; + } + } else { + /* 64-bit */ + return ( __ffsl ( low ) ); + } +} + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsl ( long value ) { + + return riscv_fls ( value ); +} + +/** + * Find last (i.e. most significant) set bit + * + * @v value Value + * @ret msb Most significant bit set in value (LSB=1), or zero + */ +static inline __attribute__ (( always_inline )) int __flsll ( long long value ){ + unsigned long low = value; + unsigned long high; + + /* Check machine word size */ + if ( sizeof ( value ) > sizeof ( low ) ) { + /* 32-bit */ + high = ( value >> 32 ); + if ( high ) { + return ( 32 + __flsl ( high ) ); + } else if ( low ) { + return ( __flsl ( low ) ); + } else { + return 0; + } + } else { + /* 64-bit */ + return ( __flsl ( low ) ); + } +} + +#endif /* _BITS_STRINGS_H */ diff --git a/src/arch/riscv/include/bits/tcpip.h b/src/arch/riscv/include/bits/tcpip.h new file mode 100644 index 000000000..0ac55b1a0 --- /dev/null +++ b/src/arch/riscv/include/bits/tcpip.h @@ -0,0 +1,15 @@ +#ifndef _BITS_TCPIP_H +#define _BITS_TCPIP_H + +/** @file + * + * Transport-network layer interface + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +extern uint16_t tcpip_continue_chksum ( uint16_t partial, const void *data, + size_t len ); + +#endif /* _BITS_TCPIP_H */ diff --git a/src/arch/riscv/include/bits/virt_offset.h b/src/arch/riscv/include/bits/virt_offset.h new file mode 100644 index 000000000..83ac17551 --- /dev/null +++ b/src/arch/riscv/include/bits/virt_offset.h @@ -0,0 +1,33 @@ +#ifndef _BITS_VIRT_OFFSET_H +#define _BITS_VIRT_OFFSET_H + +/** @file + * + * RISCV-specific virtual address offset + * + * We use the thread pointer register (tp) to hold the virtual address + * offset, so that virtual-to-physical address translations work as + * expected even while we are executing directly from read-only memory + * (and so cannot store a value in a global virt_offset variable). + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * Read virtual address offset held in thread pointer register + * + * @ret virt_offset Virtual address offset + */ +static inline __attribute__ (( const, always_inline )) unsigned long +tp_virt_offset ( void ) { + register unsigned long tp asm ( "tp" ); + + __asm__ ( "" : "=r" ( tp ) ); + return tp; +} + +/** Always read thread pointer register to get virtual address offset */ +#define virt_offset tp_virt_offset() + +#endif /* _BITS_VIRT_OFFSET_H */ 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 */ |
