mirror of
https://github.com/ipxe/ipxe
synced 2025-12-08 18:30:28 +03:00
[riscv] Add support for the SBI debug console
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>
This commit is contained in:
@@ -10,6 +10,7 @@ INCDIRS := arch/$(ARCH)/include arch/riscv/include $(INCDIRS)
|
|||||||
# RISCV-specific directories containing source files
|
# RISCV-specific directories containing source files
|
||||||
#
|
#
|
||||||
SRCDIRS += arch/riscv/core
|
SRCDIRS += arch/riscv/core
|
||||||
|
SRCDIRS += arch/riscv/interface/sbi
|
||||||
|
|
||||||
# RISCV-specific flags
|
# RISCV-specific flags
|
||||||
#
|
#
|
||||||
|
|||||||
157
src/arch/riscv/include/ipxe/sbi.h
Normal file
157
src/arch/riscv/include/ipxe/sbi.h
Normal file
@@ -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 */
|
||||||
101
src/arch/riscv/interface/sbi/sbi_console.c
Normal file
101
src/arch/riscv/interface/sbi/sbi_console.c
Normal file
@@ -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,
|
||||||
|
};
|
||||||
@@ -78,6 +78,9 @@ REQUIRE_OBJECT ( vmconsole );
|
|||||||
#ifdef CONSOLE_DEBUGCON
|
#ifdef CONSOLE_DEBUGCON
|
||||||
REQUIRE_OBJECT ( debugcon );
|
REQUIRE_OBJECT ( debugcon );
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CONSOLE_SBI
|
||||||
|
REQUIRE_OBJECT ( sbi_console );
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drag in all requested network protocols
|
* Drag in all requested network protocols
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
//#define CONSOLE_VMWARE /* VMware logfile console */
|
//#define CONSOLE_VMWARE /* VMware logfile console */
|
||||||
//#define CONSOLE_DEBUGCON /* Bochs/QEMU/KVM debug port console */
|
//#define CONSOLE_DEBUGCON /* Bochs/QEMU/KVM debug port console */
|
||||||
//#define CONSOLE_INT13 /* INT13 disk log console */
|
//#define CONSOLE_INT13 /* INT13 disk log console */
|
||||||
|
//#define CONSOLE_SBI /* RISC-V SBI debug console */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Very obscure console types
|
* Very obscure console types
|
||||||
|
|||||||
Reference in New Issue
Block a user