]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Add support for the SBI debug console
authorMichael Brown <mcb30@ipxe.org>
Tue, 22 Oct 2024 11:51:48 +0000 (12:51 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 22 Oct 2024 11:51:48 +0000 (12:51 +0100)
Add the ability to issue Supervisor Binary Interface (SBI) calls via
the ECALL instruction, and use the SBI DBCN extension to implement a
debug console.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/riscv/Makefile
src/arch/riscv/include/ipxe/sbi.h [new file with mode: 0644]
src/arch/riscv/interface/sbi/sbi_console.c [new file with mode: 0644]
src/config/config.c
src/config/console.h

index 668d7db3920d5b4e3d1f88862635995a6ae847e4..d3ae4e84c1fa5465d2b06d6f3bf9152328c10f60 100644 (file)
@@ -10,6 +10,7 @@ INCDIRS               := arch/$(ARCH)/include arch/riscv/include $(INCDIRS)
 # RISCV-specific directories containing source files
 #
 SRCDIRS                += arch/riscv/core
+SRCDIRS                += arch/riscv/interface/sbi
 
 # RISCV-specific flags
 #
diff --git a/src/arch/riscv/include/ipxe/sbi.h b/src/arch/riscv/include/ipxe/sbi.h
new file mode 100644 (file)
index 0000000..529f1d0
--- /dev/null
@@ -0,0 +1,157 @@
+#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 param0           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 param0           Parameter 0
+ * @v param1           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 param0           Parameter 0
+ * @v param1           Parameter 1
+ * @v param2           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;
+}
+
+/** 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/interface/sbi/sbi_console.c b/src/arch/riscv/interface/sbi/sbi_console.c
new file mode 100644 (file)
index 0000000..8352555
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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
+ *
+ * SBI debug console
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+#include <ipxe/sbi.h>
+#include <ipxe/io.h>
+#include <ipxe/console.h>
+#include <config/console.h>
+
+/* Set default console usage if applicable */
+#if ! ( defined ( CONSOLE_SBI ) && CONSOLE_EXPLICIT ( CONSOLE_SBI ) )
+#undef CONSOLE_SBI
+#define CONSOLE_SBI ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG )
+#endif
+
+/** Buffered input character (if any) */
+static unsigned char sbi_console_input;
+
+/**
+ * Print a character to SBI console
+ *
+ * @v character                Character to be printed
+ */
+static void sbi_putchar ( int character ) {
+
+       /* Write byte to console */
+       sbi_ecall_1 ( SBI_DBCN, SBI_DBCN_WRITE_BYTE, character );
+}
+
+/**
+ * Get character from SBI console
+ *
+ * @ret character      Character read from console, if any
+ */
+static int sbi_getchar ( void ) {
+       int character;
+
+       /* Consume and return buffered character, if any */
+       character = sbi_console_input;
+       sbi_console_input = 0;
+       return character;
+}
+
+/**
+ * Check for character ready to read from SBI console
+ *
+ * @ret True           Character available to read
+ * @ret False          No character available to read
+ */
+static int sbi_iskey ( void ) {
+       struct sbi_return ret;
+
+       /* Do nothing if we already have a buffered character */
+       if ( sbi_console_input )
+               return sbi_console_input;
+
+       /* Read and buffer byte from console, if any */
+       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;
+}
+
+/** SBI console */
+struct console_driver sbi_console_driver __console_driver = {
+       .putchar = sbi_putchar,
+       .getchar = sbi_getchar,
+       .iskey = sbi_iskey,
+       .usage = CONSOLE_SBI,
+};
index 0f950eb9dcc551518fe6dc7487d3a58a0e4cbc6a..4cfa5dd418743269256841bb79c02e997351e78f 100644 (file)
@@ -78,6 +78,9 @@ REQUIRE_OBJECT ( vmconsole );
 #ifdef CONSOLE_DEBUGCON
 REQUIRE_OBJECT ( debugcon );
 #endif
+#ifdef CONSOLE_SBI
+REQUIRE_OBJECT ( sbi_console );
+#endif
 
 /*
  * Drag in all requested network protocols
index 9f770d0943a519ea79247aa6281b345432ae5d44..0ff328b7c34fcadcda447c550810679e14639be6 100644 (file)
@@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 //#define      CONSOLE_VMWARE          /* VMware logfile console */
 //#define      CONSOLE_DEBUGCON        /* Bochs/QEMU/KVM debug port console */
 //#define      CONSOLE_INT13           /* INT13 disk log console */
+//#define      CONSOLE_SBI             /* RISC-V SBI debug console */
 
 /*
  * Very obscure console types