From: Michael Brown Date: Sun, 25 May 2025 08:28:11 +0000 (+0100) Subject: [riscv] Support older SBI implementations X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8d88870da59e93202d1cff4504f2fd2d2fa139cd;p=thirdparty%2Fipxe.git [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 --- 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