fix(console): the serial line is found, not assumed -- from the devicetree on a board, COM1 by probe on a PC
Each board has one serial line that is its console, the lowest common denominator beside the screen and keyboard. Its address was QEMU's, fixed: on a Raspberry Pi 5 the aarch64 one is ordinary RAM, written to with every character printed; on a Milk-V Mars the riscv64 one is the board's UART with registers four bytes apart, and the UEFI loader would have waited for ever on its first character; on a PC with no COM1 the prompt read 0xFF for ever. console_attach_serial(), called before anything prints: COM1 if a UART answers there; elsewhere the UART that /chosen/stdout-path names (fdt_uart.c: alias, path, the address carried up through each bus's ranges, reg-shift and reg-io-width); with no devicetree, QEMU's. A devicetree that names no usable console gives no line, not a guess. A line that does not come ready is given up, not waited on. The riscv64 loader's early serial does the same. tools/fdt_uart_test.c, run by hand, 19 checks plain and under the sanitizers: devicetrees shaped like the Mars's, the Pi 5's and QEMU's, what must find nothing, and a block cut short at every length; and the Pi 5's real devicetree gives a PL011 at 0x107d001000. Acceptance, one QEMU at a time: v3 on amd64 (logs/20261013-204436), aarch64 (-204803) and riscv64 (-205001) to the zuse prompt, no unknown word, hash 0x08873e0f44b7cb2a on all three as before. -204600 is an aarch64 run during which the disk images were restored under it by a script that had been refused a second QEMU; it passed and is kept, and was run again. v4 on the three ISAs (-211149, -211444, -211857): POST 538 of 538, dict_hash 0xe5a57f3eb72ff94a, the typed session unchanged. The Mars image through OpenSBI and U-Boot in QEMU took its line and its interrupt controller from the devicetree and passed POST. Found on the way and not mended (boards/BRINGUP.md 1.6): built with EMERGENCY_CONSOLE_ENABLED=1 the prompt floods with empty lines. -210442 shows it; the commit before this does the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
f4e359859a
commit
c95191736e
@@ -53,6 +53,8 @@
|
||||
#include "elf64.h"
|
||||
#include "starkernel/cmdline.h"
|
||||
#include "starkernel/boot_info_offsets.h"
|
||||
#include "starkernel/fdt.h"
|
||||
#include "starkernel/fdt_uart.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/* Verify BootInfo field offsets match boot_info_offsets.h (BOOT_INFO_OFFSETS) */
|
||||
@@ -242,20 +244,56 @@ static void raw_serial_puts(const char *s)
|
||||
*/
|
||||
#define UART_MMIO_BASE 0x10000000UL
|
||||
|
||||
static inline void raw_mmio_outb(uint64_t addr, uint8_t val)
|
||||
/* That is QEMU's. A real board's console UART is the one its devicetree
|
||||
* names, and may be laid out otherwise: the Milk-V Mars's is at the same
|
||||
* address with its registers four bytes apart, and the byte-spaced write
|
||||
* below would wait for ever on what is not its status register
|
||||
* (boards/BRINGUP.md). So the line is found first, raw_serial_find(), by
|
||||
* the lookup the kernel's console uses (starkernel/fdt_uart.h); until then,
|
||||
* and on a board whose devicetree names no line this can use, RAW_LOG()
|
||||
* writes nothing. A line that does not come ready is given up. */
|
||||
#define RAW_SERIAL_THRE_MAX_SPIN 4000000u
|
||||
static int raw_serial_ready = 0;
|
||||
static uint64_t raw_uart_base = UART_MMIO_BASE;
|
||||
static unsigned raw_uart_shift = 0;
|
||||
static unsigned raw_uart_width = 1;
|
||||
|
||||
static inline uint32_t raw_uart_read(unsigned reg)
|
||||
{
|
||||
*(volatile uint8_t *)addr = val;
|
||||
uint64_t addr = raw_uart_base + ((uint64_t)reg << raw_uart_shift);
|
||||
return raw_uart_width == 4 ? *(volatile uint32_t *)addr : *(volatile uint8_t *)addr;
|
||||
}
|
||||
|
||||
static inline uint8_t raw_mmio_inb(uint64_t addr)
|
||||
static inline void raw_uart_write(unsigned reg, uint8_t val)
|
||||
{
|
||||
return *(volatile uint8_t *)addr;
|
||||
uint64_t addr = raw_uart_base + ((uint64_t)reg << raw_uart_shift);
|
||||
if (raw_uart_width == 4) *(volatile uint32_t *)addr = val;
|
||||
else *(volatile uint8_t *)addr = val;
|
||||
}
|
||||
|
||||
/* `dtb`: the devicetree the firmware handed over, or NULL if it gave none. */
|
||||
static void raw_serial_setup(const void *dtb)
|
||||
{
|
||||
fdt_uart_t u;
|
||||
raw_serial_ready = 0;
|
||||
if (fdt_console_uart(dtb, &u)) {
|
||||
if (u.kind != FDT_UART_16550) return;
|
||||
raw_uart_base = u.base; raw_uart_shift = u.reg_shift; raw_uart_width = u.io_width;
|
||||
raw_serial_ready = 1;
|
||||
} else if (!fdt_valid(dtb)) {
|
||||
raw_uart_base = UART_MMIO_BASE; raw_uart_shift = 0; raw_uart_width = 1; /* no devicetree: QEMU's */
|
||||
raw_serial_ready = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void raw_serial_putc(char c)
|
||||
{
|
||||
while ((raw_mmio_inb(UART_MMIO_BASE + 5) & 0x20) == 0) { }
|
||||
raw_mmio_outb(UART_MMIO_BASE + 0, (uint8_t)c);
|
||||
unsigned int spin = 0;
|
||||
if (!raw_serial_ready) return;
|
||||
while ((raw_uart_read(5) & 0x20) == 0) {
|
||||
if (++spin >= RAW_SERIAL_THRE_MAX_SPIN) { raw_serial_ready = 0; return; }
|
||||
}
|
||||
raw_uart_write(0, (uint8_t)c);
|
||||
}
|
||||
|
||||
static void raw_serial_puts(const char *s)
|
||||
@@ -691,6 +729,16 @@ EFI_STATUS EFIAPI efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable
|
||||
raw_serial_init();
|
||||
RAW_LOG("RAW SERIAL UP\n");
|
||||
debug_checkpoint(SystemTable, 2, L"Serial (COM1) initialized");
|
||||
#elif defined(__riscv) || defined(ARCH_RISCV64)
|
||||
{
|
||||
/* the serial line, before the first RAW_LOG(): from the devicetree, if the firmware gave one */
|
||||
const void *early_dtb = NULL;
|
||||
EFI_CONFIGURATION_TABLE *tables = (EFI_CONFIGURATION_TABLE *)SystemTable->ConfigurationTable;
|
||||
UINTN t;
|
||||
for (t = 0; tables && t < SystemTable->NumberOfTableEntries; ++t)
|
||||
if (guid_equals(&tables[t].VendorGuid, &EFI_DTB_TABLE_GUID)) { early_dtb = tables[t].VendorTable; break; }
|
||||
raw_serial_setup(early_dtb);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MONOLITHIC_BUILD
|
||||
|
||||
Reference in New Issue
Block a user