]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Support mapping early UARTs outside of the identity map
authorMichael Brown <mcb30@ipxe.org>
Tue, 27 May 2025 15:18:17 +0000 (16:18 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 27 May 2025 15:31:51 +0000 (16:31 +0100)
Some platforms (such as the Sipeed Lichee Pi 4A) choose to make early
debugging entertainingly cumbersome for the programmer.  These
platforms not only fail to provide a functional SBI debug console, but
also choose to place the UART at a physical address that cannot be
identity-mapped under the only paging model supported by the CPU.

Support such platforms by creating a virtual address mapping for the
early UART (in the 2MB megapage immediately below iPXE itself), and
using this as the UART base address whenever paging is enabled.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/riscv/prefix/libprefix.S

index 41d03769ec13950258e8946a6bea0495359013b1..e4ca54f716a38d1928efd3ac3681ed6f2ffe48ea 100644 (file)
@@ -149,10 +149,33 @@ prefix_virt:
 
 #define print_char_uart _C2 ( print_char_uart_, EARLY_UART_MODEL )
 
+#define early_uart_reg_base _C2 ( early_uart_reg_base_, __riscv_xlen )
+
        /* Print character via nonexistent UART */
        .macro  print_char_uart_none
        .endm
 
+       /*
+        * Get UART base address (64-bit addressing)
+        */
+       .macro  early_uart_reg_base_64 reg
+       csrr    \reg, satp
+       beqz    \reg, early_uart_reg_base_64_nonpaged_\@
+       LOADN   \reg, early_uart_reg_base_64_virt
+       j       early_uart_reg_base_64_done_\@
+early_uart_reg_base_64_nonpaged_\@:
+       li      \reg, EARLY_UART_REG_BASE
+early_uart_reg_base_64_done_\@:
+       .endm
+
+       /*
+        * Get UART base address (32-bit addressing)
+        */
+       .macro  early_uart_reg_base_32 reg
+       li      \reg, EARLY_UART_REG_BASE
+       sub     \reg, \reg, tp
+       .endm
+
 /*****************************************************************************
  *
  * Print character via 8250-compatible early UART
@@ -179,7 +202,7 @@ prefix_virt:
 #define EARLY_UART_8250_LSR_THRE       0x20
 
        .macro  print_char_uart_8250
-       li      a7, EARLY_UART_REG_BASE
+       early_uart_reg_base a7
        sb      a0, EARLY_UART_8250_TX(a7)
 uart_wait_\@:
        lbu     a1, EARLY_UART_8250_LSR(a7)
@@ -749,6 +772,7 @@ enable_paging_64:
         * a4 - PTE stride
         * a5 - size of accessible physical address space
         */
+
        progress " paging:"
        li      a1, SATP_MODE_SV57
 
@@ -818,6 +842,14 @@ enable_paging_64_loop:
        li      a4, 1
        slli    a4, a4, PTE_PPN1_LSB
 
+       /* Construct PTE[x-1] for early UART, if applicable */
+#ifdef EARLY_UART_REG_BASE
+       li      t0, ( EARLY_UART_REG_BASE & ~( ( 1 << VPN1_LSB ) - 1 ) )
+       srli    t0, t0, PTE_PPN_SHIFT
+       ori     t0, t0, PTE_LEAF
+       STOREN  t0, -PTE_SIZE(a3)
+#endif
+
        /* Construct PTE[x-y] for iPXE virtual address map */
        la      t0, _prefix
        srli    t0, t0, PTE_PPN_SHIFT
@@ -862,6 +894,20 @@ enable_paging_64_loop:
        .endif
        .endm
 
+       /* Early UART base address when 64-bit paging is enabled
+        *
+        * When an early UART is in use, we choose to use the 2MB
+        * "megapage" immediately below iPXE itself to map the UART.
+        */
+#ifdef EARLY_UART_REG_BASE
+       .section ".rodata.early_uart_reg_base_64_virt", "a", @progbits
+       .balign 8
+early_uart_reg_base_64_virt:
+       .dword  ( _base - ( 1 << VPN1_LSB ) + \
+                 ( EARLY_UART_REG_BASE & ( ( 1 << VPN1_LSB ) - 1 ) ) )
+       .size   early_uart_reg_base_64_virt, . - early_uart_reg_base_64_virt
+#endif
+
 /*****************************************************************************
  *
  * Disable 64-bit paging
@@ -1152,6 +1198,7 @@ install:
         * s6 - relocation offset
         * tp - virtual address offset
         */
+       mv      tp, zero
        progress "\r\nSBI->iPXE hart:"
        print_hex_reg a0
        progress " temp:"
@@ -1167,9 +1214,6 @@ install:
        mv      s2, ra
        la      s3, _edata
 
-       /* Initialise virtual address offset */
-       mv      tp, zero
-
        /* Attempt to enable paging, if we have temporary page table space */
        mv      a0, a2
        beqz    a2, 1f