From: Michael Brown Date: Tue, 27 May 2025 13:49:06 +0000 (+0100) Subject: [riscv] Add support for writing prefix debug messages direct to a UART X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=98fdfdd25512d8a6fd53d37775e6ea43283ac49f;p=thirdparty%2Fipxe.git [riscv] Add support for writing prefix debug messages direct to a UART Some platforms (such as the Sipeed Lichee Pi 4A) do not provide a functional SBI debug console. We can obtain early debug messages on these systems by writing directly to the UART used by the vendor firmware. There is no viable way to parse the UART address from the device tree, since the prefix debug messages occur extremely early, before the C runtime environment is available and therefore before any information has been parsed from the device tree. The early UART model and register addresses must be configured by editing config/serial.h if needed. (This is an acceptable limitation, since prefix debugging is an extremely specialised use case.) Signed-off-by: Michael Brown --- diff --git a/src/arch/riscv/prefix/libprefix.S b/src/arch/riscv/prefix/libprefix.S index d3278f07d..41d03769e 100644 --- a/src/arch/riscv/prefix/libprefix.S +++ b/src/arch/riscv/prefix/libprefix.S @@ -29,6 +29,8 @@ * */ +#include + .section ".note.GNU-stack", "", @progbits .text @@ -110,6 +112,81 @@ prefix_virt: ecall .endm +/***************************************************************************** + * + * Print character via early UART + * + ***************************************************************************** + * + * Print a single character via a UART. + * + * For devices without a functional SBI console, a UART at a hardcoded + * address can be used as a last resort mechanism for obtaining debug + * output from the prefix. + * + * Parameters: + * + * a0 - Character to print + * + * Returns: + * + * a0 - Preserved + * a1 - May be overwritten + * a6 - May be overwritten + * a7 - May be overwritten + * + */ + +/* Default to no UART, if not specified */ +#ifndef EARLY_UART_MODEL +#define EARLY_UART_MODEL none +#endif + +/* Default to a register shift of zero, if not specified */ +#ifndef EARLY_UART_REG_SHIFT +#define EARLY_UART_REG_SHIFT 0 +#endif + +#define print_char_uart _C2 ( print_char_uart_, EARLY_UART_MODEL ) + + /* Print character via nonexistent UART */ + .macro print_char_uart_none + .endm + +/***************************************************************************** + * + * Print character via 8250-compatible early UART + * + ***************************************************************************** + * + * Print a single character via an 8250- or 16550-compatible UART. + * + * Parameters: + * + * a0 - Character to print + * + * Returns: + * + * a0 - Preserved + * a1 - Overwritten + * a7 - Overwritten + * + */ + +/* 8250-compatible UART transmit registers */ +#define EARLY_UART_8250_TX ( 0 << EARLY_UART_REG_SHIFT ) +#define EARLY_UART_8250_LSR ( 5 << EARLY_UART_REG_SHIFT ) +#define EARLY_UART_8250_LSR_THRE 0x20 + + .macro print_char_uart_8250 + li a7, EARLY_UART_REG_BASE + sb a0, EARLY_UART_8250_TX(a7) +uart_wait_\@: + lbu a1, EARLY_UART_8250_LSR(a7) + andi a1, a1, EARLY_UART_8250_LSR_THRE + beqz a1, uart_wait_\@ + .endm + /***************************************************************************** * * Print message to debug console @@ -159,6 +236,7 @@ print_message_alt: lbu a0, (t1) addi t1, t1, 1 beqz a0, 2f + print_char_uart print_char_dbcn beqz a0, 1b lbu a0, -1(t1) @@ -250,6 +328,7 @@ print_hex_value_alt: 1: /* Print each digit in turn */ srli a0, t1, ( __riscv_xlen - 4 ) nibble_to_ascii a0 + print_char_uart print_char_dbcn beqz a0, 2f srli a0, t1, ( __riscv_xlen - 4 ) diff --git a/src/config/serial.h b/src/config/serial.h index 27040dc54..09068d8e0 100644 --- a/src/config/serial.h +++ b/src/config/serial.h @@ -27,6 +27,11 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define COMSTOP 1 /* Stop bits */ #endif +/* Early UART configuration (for bare metal prefix debugging only) */ +//#define EARLY_UART_MODEL 8250 +//#define EARLY_UART_REG_BASE 0x10000000 +//#define EARLY_UART_REG_SHIFT 0 + #include #include NAMED_CONFIG(serial.h) #include