[riscv] Support mapping early UARTs outside of the identity map

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>
This commit is contained in:
Michael Brown
2025-05-27 16:18:17 +01:00
parent 98fdfdd255
commit 2e27d772ca

View 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