Skip to content

Commit

Permalink
x86/early_printk: Add support for MMIO-based UARTs
Browse files Browse the repository at this point in the history
During the bring-up of an x86 board, the kernel was crashing before
reaching the platform's console driver because of a bug in the firmware,
leaving no trace of the boot progress.

The only available method to debug the kernel boot process was via the
platform's MMIO-based UART, as the board lacked an I/O port-based UART,
PCI UART, or functional video output.

Then it turned out that earlyprintk= does not have a knob to configure
the MMIO-mapped UART.

Extend the early printk facility to support platform MMIO-based UARTs
on x86 systems, enabling debugging during the system bring-up phase.

The command line syntax to enable platform MMIO-based UART is:

  earlyprintk=mmio,membase[,{nocfg|baudrate}][,keep]

Note, the change does not integrate MMIO-based UART support to:

  arch/x86/boot/early_serial_console.c

Also, update kernel parameters documentation with the new syntax and
add the missing 'nocfg' setting to the PCI serial cards description.

Signed-off-by: Denis Mukhin <dmukhin@ford.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Link: https://lore.kernel.org/r/20250324-earlyprintk-v3-1-aee7421dc469@ford.com
Denis Mukhin authored and Ingo Molnar committed Mar 25, 2025
1 parent 2c118f5 commit 3181424
Showing 2 changed files with 52 additions and 2 deletions.
9 changes: 8 additions & 1 deletion Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
@@ -1407,14 +1407,21 @@
earlyprintk=serial[,0x...[,baudrate]]
earlyprintk=ttySn[,baudrate]
earlyprintk=dbgp[debugController#]
earlyprintk=pciserial[,force],bus:device.function[,baudrate]
earlyprintk=pciserial[,force],bus:device.function[,{nocfg|baudrate}]
earlyprintk=xdbc[xhciController#]
earlyprintk=bios
earlyprintk=mmio,membase[,{nocfg|baudrate}]

earlyprintk is useful when the kernel crashes before
the normal console is initialized. It is not enabled by
default because it has some cosmetic problems.

Only 32-bit memory addresses are supported for "mmio"
and "pciserial" devices.

Use "nocfg" to skip UART configuration, assume
BIOS/firmware has configured UART correctly.

Append ",keep" to not disable it when the real console
takes over.

45 changes: 44 additions & 1 deletion arch/x86/kernel/early_printk.c
Original file line number Diff line number Diff line change
@@ -190,7 +190,6 @@ static __init void early_serial_init(char *s)
early_serial_hw_init(divisor);
}

#ifdef CONFIG_PCI
static __noendbr void mem32_serial_out(unsigned long addr, int offset, int value)
{
u32 __iomem *vaddr = (u32 __iomem *)addr;
@@ -207,6 +206,45 @@ static __noendbr unsigned int mem32_serial_in(unsigned long addr, int offset)
}
ANNOTATE_NOENDBR_SYM(mem32_serial_in);

/*
* early_mmio_serial_init() - Initialize MMIO-based early serial console.
* @s: MMIO-based serial specification.
*/
static __init void early_mmio_serial_init(char *s)
{
unsigned long baudrate;
unsigned long membase;
char *e;

if (*s == ',')
s++;

if (!strncmp(s, "0x", 2)) {
/* NB: only 32-bit addresses are supported. */
membase = simple_strtoul(s, &e, 16);
early_serial_base = (unsigned long)early_ioremap(membase, PAGE_SIZE);

static_call_update(serial_in, mem32_serial_in);
static_call_update(serial_out, mem32_serial_out);

s += strcspn(s, ",");
if (*s == ',')
s++;
}

if (!strncmp(s, "nocfg", 5)) {
baudrate = 0;
} else {
baudrate = simple_strtoul(s, &e, 0);
if (baudrate == 0 || s == e)
baudrate = DEFAULT_BAUD;
}

if (baudrate)
early_serial_hw_init(115200 / baudrate);
}

#ifdef CONFIG_PCI
/*
* early_pci_serial_init()
*
@@ -351,6 +389,11 @@ static int __init setup_early_printk(char *buf)
keep = (strstr(buf, "keep") != NULL);

while (*buf != '\0') {
if (!strncmp(buf, "mmio", 4)) {
early_mmio_serial_init(buf + 4);
early_console_register(&early_serial_console, keep);
buf += 4;
}
if (!strncmp(buf, "serial", 6)) {
buf += 6;
early_serial_init(buf);

0 comments on commit 3181424

Please sign in to comment.