]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Add support for writing prefix debug messages direct to a UART
authorMichael Brown <mcb30@ipxe.org>
Tue, 27 May 2025 13:49:06 +0000 (14:49 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 27 May 2025 13:49:18 +0000 (14:49 +0100)
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 <mcb30@ipxe.org>
src/arch/riscv/prefix/libprefix.S
src/config/serial.h

index d3278f07debaa3c5f71e515d8b26cd81be22b038..41d03769ec13950258e8946a6bea0495359013b1 100644 (file)
@@ -29,6 +29,8 @@
  *
  */
 
+#include <config/serial.h>
+
        .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 )
index 27040dc545a72753ee6b20611096a697a7984782..09068d8e015ee32f7fb7c21a8f2ed0c165bc861e 100644 (file)
@@ -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 <config/named.h>
 #include NAMED_CONFIG(serial.h)
 #include <config/local/serial.h>