summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown2025-05-25 10:28:11 +0200
committerMichael Brown2025-05-25 11:43:39 +0200
commit8d88870da59e93202d1cff4504f2fd2d2fa139cd (patch)
treef74931b3fbc35e6766c5feb827831dbae6a8868b /src
parent[memmap] Rename addr/last fields to min/max for clarity (diff)
downloadipxe-8d88870da59e93202d1cff4504f2fd2d2fa139cd.tar.gz
ipxe-8d88870da59e93202d1cff4504f2fd2d2fa139cd.tar.xz
ipxe-8d88870da59e93202d1cff4504f2fd2d2fa139cd.zip
[riscv] Support older SBI implementations
Fall back to attempting the legacy SBI console and shutdown calls if the standard calls fail. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src')
-rw-r--r--src/arch/riscv/include/ipxe/sbi.h54
-rw-r--r--src/arch/riscv/interface/sbi/sbi_console.c26
-rw-r--r--src/arch/riscv/interface/sbi/sbi_reboot.c9
-rw-r--r--src/arch/riscv/prefix/libprefix.S40
4 files changed, 111 insertions, 18 deletions
diff --git a/src/arch/riscv/include/ipxe/sbi.h b/src/arch/riscv/include/ipxe/sbi.h
index 44685cc87..aaab3a355 100644
--- a/src/arch/riscv/include/ipxe/sbi.h
+++ b/src/arch/riscv/include/ipxe/sbi.h
@@ -73,7 +73,7 @@ sbi_ecall_0 ( int eid, int fid ) {
*
* @v eid Extension ID
* @v fid Function ID
- * @v param0 Parameter 0
+ * @v p0 Parameter 0
* @ret ret Return value
*/
static inline __attribute__ (( always_inline )) struct sbi_return
@@ -98,8 +98,8 @@ sbi_ecall_1 ( int eid, int fid, unsigned long p0 ) {
*
* @v eid Extension ID
* @v fid Function ID
- * @v param0 Parameter 0
- * @v param1 Parameter 1
+ * @v p0 Parameter 0
+ * @v p1 Parameter 1
* @ret ret Return value
*/
static inline __attribute__ (( always_inline )) struct sbi_return
@@ -124,9 +124,9 @@ sbi_ecall_2 ( int eid, int fid, unsigned long p0, unsigned long p1 ) {
*
* @v eid Extension ID
* @v fid Function ID
- * @v param0 Parameter 0
- * @v param1 Parameter 1
- * @v param2 Parameter 2
+ * @v p0 Parameter 0
+ * @v p1 Parameter 1
+ * @v p2 Parameter 2
* @ret ret Return value
*/
static inline __attribute__ (( always_inline )) struct sbi_return
@@ -148,9 +148,51 @@ sbi_ecall_3 ( int eid, int fid, unsigned long p0, unsigned long p1,
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 */
+
/** System reset extension */
#define SBI_SRST SBI_EID ( 'S', 'R', 'S', 'T' )
#define SBI_SRST_SYSTEM_RESET 0x00 /**< Reset system */
diff --git a/src/arch/riscv/interface/sbi/sbi_console.c b/src/arch/riscv/interface/sbi/sbi_console.c
index 93cdf0798..c993ebc0a 100644
--- a/src/arch/riscv/interface/sbi/sbi_console.c
+++ b/src/arch/riscv/interface/sbi/sbi_console.c
@@ -50,9 +50,15 @@ static unsigned char sbi_console_input;
* @v character Character to be printed
*/
static void sbi_putchar ( int character ) {
+ struct sbi_return ret;
/* Write byte to console */
- sbi_ecall_1 ( SBI_DBCN, SBI_DBCN_WRITE_BYTE, character );
+ ret = sbi_ecall_1 ( SBI_DBCN, SBI_DBCN_WRITE_BYTE, character );
+ if ( ! ret.error )
+ return;
+
+ /* Debug extension not supported: try legacy method */
+ sbi_legacy_ecall_1 ( SBI_LEGACY_PUTCHAR, character );
}
/**
@@ -82,6 +88,7 @@ static int sbi_getchar ( void ) {
*/
static int sbi_iskey ( void ) {
struct sbi_return ret;
+ long key;
/* Do nothing if we already have a buffered character */
if ( sbi_console_input )
@@ -91,11 +98,18 @@ static int sbi_iskey ( void ) {
ret = sbi_ecall_3 ( SBI_DBCN, SBI_DBCN_READ,
sizeof ( sbi_console_input ),
virt_to_phys ( &sbi_console_input ), 0 );
- if ( ret.error )
- return 0;
-
- /* Return number of characters read and buffered */
- return ret.value;
+ if ( ! ret.error )
+ return ret.value;
+
+ /* Debug extension not supported: try legacy method */
+ key = sbi_legacy_ecall_0 ( SBI_LEGACY_GETCHAR );
+ if ( key > 0 ) {
+ sbi_console_input = key;
+ return key;
+ }
+
+ /* No character available */
+ return 0;
}
/** SBI console */
diff --git a/src/arch/riscv/interface/sbi/sbi_reboot.c b/src/arch/riscv/interface/sbi/sbi_reboot.c
index 3529c9d38..b1c742ec7 100644
--- a/src/arch/riscv/interface/sbi/sbi_reboot.c
+++ b/src/arch/riscv/interface/sbi/sbi_reboot.c
@@ -53,6 +53,10 @@ static void sbi_reboot ( int flags ) {
rc = -ESBI ( ret.error );
DBGC ( SBI_SRST, "SBI %s reset failed: %s\n",
( warm ? "warm" : "cold" ), strerror ( rc ) );
+
+ /* Try a legacy shutdown */
+ sbi_legacy_ecall_0 ( SBI_LEGACY_SHUTDOWN );
+ DBGC ( SBI_SRST, "SBI legacy shutdown failed\n" );
}
/**
@@ -71,6 +75,11 @@ static int sbi_poweroff ( void ) {
/* Any return is an error */
rc = -ESBI ( ret.error );
DBGC ( SBI_SRST, "SBI shutdown failed: %s\n", strerror ( rc ) );
+
+ /* Try a legacy shutdown */
+ sbi_legacy_ecall_0 ( SBI_LEGACY_SHUTDOWN );
+ DBGC ( SBI_SRST, "SBI legacy shutdown failed\n" );
+
return rc;
}
diff --git a/src/arch/riscv/prefix/libprefix.S b/src/arch/riscv/prefix/libprefix.S
index a101ba1cd..5bfc6b3be 100644
--- a/src/arch/riscv/prefix/libprefix.S
+++ b/src/arch/riscv/prefix/libprefix.S
@@ -80,6 +80,9 @@ prefix_virt:
#define SBI_DBCN ( ( 'D' << 24 ) | ( 'B' << 16 ) | ( 'C' << 8 ) | 'N' )
#define SBI_DBCN_WRITE_BYTE 0x02
+/* SBI legacy console putchar */
+#define SBI_LEGACY_PUTCHAR 0x01
+
.section ".prefix.print_message", "ax", @progbits
.globl print_message
print_message:
@@ -108,6 +111,10 @@ print_message_alt:
li a7, SBI_DBCN
li a6, SBI_DBCN_WRITE_BYTE
ecall
+ beqz a0, 1b
+ lbu a0, -1(t1)
+ li a7, SBI_LEGACY_PUTCHAR
+ ecall
j 1b
2:
/* Restore registers and return (via alternate link register) */
@@ -154,6 +161,17 @@ progress_\@:
* Returns: none
*
*/
+
+ /*
+ * Convert a single nibble to an ASCII character
+ */
+ .macro nibble_to_ascii reg
+ addi \reg, \reg, -10
+ bltz \reg, dec_\@
+ addi \reg, \reg, ( 'a' - ( '0' + 10 ) )
+dec_\@: addi \reg, \reg, ( '0' + 10 )
+ .endm
+
.section ".prefix.print_hex_value", "ax", @progbits
.globl print_hex_value
print_hex_value:
@@ -183,14 +201,16 @@ print_hex_value_alt:
1: /* Print each digit in turn */
srli a0, t1, ( __riscv_xlen - 4 )
- addi a0, a0, -10
- bltz a0, 2f
- addi a0, a0, ( 'a' - ( '0' + 10 ) )
-2: addi a0, a0, ( '0' + 10 )
+ nibble_to_ascii a0
li a7, SBI_DBCN
li a6, SBI_DBCN_WRITE_BYTE
ecall
- slli t1, t1, 4
+ beqz a0, 2f
+ srli a0, t1, ( __riscv_xlen - 4 )
+ nibble_to_ascii a0
+ li a7, SBI_LEGACY_PUTCHAR
+ ecall
+2: slli t1, t1, 4
addi t2, t2, -4
bgtz t2, 1b
@@ -1121,6 +1141,9 @@ install:
#define SBI_SRST_SYSTEM_RESET 0x00
#define SBI_RESET_COLD 0x00000001
+/* SBI legacy shutdown */
+#define SBI_LEGACY_SHUTDOWN 0x08
+
.section ".prefix.reset_system", "ax", @progbits
.globl reset_system
reset_system:
@@ -1133,9 +1156,14 @@ reset_system:
li a0, SBI_RESET_COLD
mv a1, zero
ecall
+ progress "(reset failed)\n"
+
+ /* Attempt legacy shutdown */
+ li a7, SBI_LEGACY_SHUTDOWN
+ ecall
+ progress "(legacy shutdown failed)\n"
/* If reset failed, lock the system */
- progress "(reset failed)\n"
1: wfi
j 1b
.size reset_system, . - reset_system