Documentation/admin-guide/kernel-parameters.txt | 4 +++ arch/x86/kernel/early_printk.c | 45 ++++++++++++++++++++++++- 2 files changed, 48 insertions(+), 1 deletion(-)
From: Denis Mukhin <dmukhin@ford.com>
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.
It was discovered that 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
Signed-off-by: Denis Mukhin <dmukhin@ford.com>
---
Documentation/admin-guide/kernel-parameters.txt | 4 +++
arch/x86/kernel/early_printk.c | 45 ++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index fb8752b42ec8582b8750d7e014c4d76166fa2fc1..bee9ee18a506d019dc3d330268e3e1c83434ebba 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1414,11 +1414,15 @@
earlyprintk=pciserial[,force],bus:device.function[,baudrate]
earlyprintk=xdbc[xhciController#]
earlyprintk=bios
+ earlyprintk=mmio,membase[,{nocfg|baudrate}][,keep]
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.
+ 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.
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index 44f937015e1e25bf41532eb7e1031a6be32a6523..19248c73b5b0950e9edf1a60ba67829f1cd3279e 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -191,7 +191,6 @@ static __init void early_serial_init(char *s)
early_serial_hw_init(divisor);
}
-#ifdef CONFIG_PCI
static void mem32_serial_out(unsigned long addr, int offset, int value)
{
u32 __iomem *vaddr = (u32 __iomem *)addr;
@@ -206,6 +205,45 @@ static unsigned int mem32_serial_in(unsigned long addr, int offset)
return readl(vaddr + offset);
}
+/*
+ * early_mmio_serial_init() - Initialize MMIO-based early serial console.
+ * @membase: UART base address.
+ * @nocfg: Skip configuration, assume BIOS has configured UART correctly.
+ * @baudrate (int): Baud rate.
+ * @keep: Keep after the real driver is available.
+ */
+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)) {
+ membase = simple_strtoul(s, &e, 16);
+ early_serial_base = (unsigned long)early_ioremap(membase, PAGE_SIZE);
+ serial_in = mem32_serial_in;
+ 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()
*
@@ -352,6 +390,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);
---
base-commit: 8aed61b8334e00f4fe5de9f2df1cd183dc328a9d
change-id: 20250313-earlyprintk-f68bcf10febc
Best regards,
--
Denis Mukhin <dmukhin@ford.com>
Hi,
On 3/13/25 4:45 PM, Denis Mukhin via B4 Relay wrote:
> From: Denis Mukhin <dmukhin@ford.com>
>
> 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.
>
> It was discovered that 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
>
> Signed-off-by: Denis Mukhin <dmukhin@ford.com>
> ---
> Documentation/admin-guide/kernel-parameters.txt | 4 +++
> arch/x86/kernel/early_printk.c | 45 ++++++++++++++++++++++++-
> 2 files changed, 48 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index fb8752b42ec8582b8750d7e014c4d76166fa2fc1..bee9ee18a506d019dc3d330268e3e1c83434ebba 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -1414,11 +1414,15 @@
> earlyprintk=pciserial[,force],bus:device.function[,baudrate]
> earlyprintk=xdbc[xhciController#]
> earlyprintk=bios
> + earlyprintk=mmio,membase[,{nocfg|baudrate}][,keep]
>
> 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.
>
> + 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.
>
> diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
> index 44f937015e1e25bf41532eb7e1031a6be32a6523..19248c73b5b0950e9edf1a60ba67829f1cd3279e 100644
> --- a/arch/x86/kernel/early_printk.c
> +++ b/arch/x86/kernel/early_printk.c
> @@ -191,7 +191,6 @@ static __init void early_serial_init(char *s)
> early_serial_hw_init(divisor);
> }
>
> -#ifdef CONFIG_PCI
> static void mem32_serial_out(unsigned long addr, int offset, int value)
> {
> u32 __iomem *vaddr = (u32 __iomem *)addr;
> @@ -206,6 +205,45 @@ static unsigned int mem32_serial_in(unsigned long addr, int offset)
> return readl(vaddr + offset);
> }
>
> +/*
> + * early_mmio_serial_init() - Initialize MMIO-based early serial console.
> + * @membase: UART base address.
> + * @nocfg: Skip configuration, assume BIOS has configured UART correctly.
> + * @baudrate (int): Baud rate.
Looks like unsigned long to me.
> + * @keep: Keep after the real driver is available.
These 4 "parameters" are not the function arguments.
@s is the function argument.
You could say in a comment that @s is scanned to obtain
these 4 parameters or something like that.
> + */
> +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)) {
> + membase = simple_strtoul(s, &e, 16);
> + early_serial_base = (unsigned long)early_ioremap(membase, PAGE_SIZE);
> + serial_in = mem32_serial_in;
> + 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()
> *
> @@ -352,6 +390,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);
>
> ---
--
~Randy
On Thursday, March 13th, 2025 at 5:04 PM, Randy Dunlap <rdunlap@infradead.org> wrote:
>
>
> Hi,
>
> On 3/13/25 4:45 PM, Denis Mukhin via B4 Relay wrote:
>
> > From: Denis Mukhin dmukhin@ford.com
> >
> > 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.
> >
> > It was discovered that 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
> >
> > Signed-off-by: Denis Mukhin dmukhin@ford.com
> > ---
> > Documentation/admin-guide/kernel-parameters.txt | 4 +++
> > arch/x86/kernel/early_printk.c | 45 ++++++++++++++++++++++++-
> > 2 files changed, 48 insertions(+), 1 deletion(-)
> >
> > diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> > index fb8752b42ec8582b8750d7e014c4d76166fa2fc1..bee9ee18a506d019dc3d330268e3e1c83434ebba 100644
> > --- a/Documentation/admin-guide/kernel-parameters.txt
> > +++ b/Documentation/admin-guide/kernel-parameters.txt
> > @@ -1414,11 +1414,15 @@
> > earlyprintk=pciserial[,force],bus:device.function[,baudrate]
> > earlyprintk=xdbc[xhciController#]
> > earlyprintk=bios
> > + earlyprintk=mmio,membase[,{nocfg|baudrate}][,keep]
> >
> > 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.
> >
> > + 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.
> >
> > diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
> > index 44f937015e1e25bf41532eb7e1031a6be32a6523..19248c73b5b0950e9edf1a60ba67829f1cd3279e 100644
> > --- a/arch/x86/kernel/early_printk.c
> > +++ b/arch/x86/kernel/early_printk.c
> > @@ -191,7 +191,6 @@ static __init void early_serial_init(char *s)
> > early_serial_hw_init(divisor);
> > }
> >
> > -#ifdef CONFIG_PCI
> > static void mem32_serial_out(unsigned long addr, int offset, int value)
> > {
> > u32 __iomem *vaddr = (u32 __iomem *)addr;
> > @@ -206,6 +205,45 @@ static unsigned int mem32_serial_in(unsigned long addr, int offset)
> > return readl(vaddr + offset);
> > }
> >
> > +/*
> > + * early_mmio_serial_init() - Initialize MMIO-based early serial console.
> > + * @membase: UART base address.
> > + * @nocfg: Skip configuration, assume BIOS has configured UART correctly.
> > + * @baudrate (int): Baud rate.
>
>
> Looks like unsigned long to me.
>
> > + * @keep: Keep after the real driver is available.
>
>
> These 4 "parameters" are not the function arguments.
> @s is the function argument.
>
> You could say in a comment that @s is scanned to obtain
> these 4 parameters or something like that.
Sorry, I messed the description.
These 4 parameters meant to describe the arguments of the string to parse:
membase[,{nocfg|baudrate}][,keep]
I will update.
Thanks!
>
> > + */
> > +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)) {
> > + membase = simple_strtoul(s, &e, 16);
> > + early_serial_base = (unsigned long)early_ioremap(membase, PAGE_SIZE);
> > + serial_in = mem32_serial_in;
> > + 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()
> > *
> > @@ -352,6 +390,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);
> >
> > ---
>
>
>
> --
> ~Randy
On 3/13/25 16:45, Denis Mukhin via B4 Relay wrote:
> 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.
>
> It was discovered that 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.
This is a pretty exotic piece of hardware, right? It's not some off the
shelf laptop?
Is there a driver for it during normal runtime?
> 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]
I'll stick this in the queue to take a closer look after the next merge
window closes. It's a bit on the late side in the 6.14 cycle for new stuff.
I do appreciate the importance of having this tool in your toolbox.
earlyprintk has saved my bacon more times than I can count.
On Thursday, March 13th, 2025 at 5:04 PM, Dave Hansen <dave.hansen@intel.com> wrote:
>
>
> On 3/13/25 16:45, Denis Mukhin via B4 Relay wrote:
>
> > 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.
> >
> > It was discovered that 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.
>
>
> This is a pretty exotic piece of hardware, right? It's not some off the
> shelf laptop?
Correct, this is not off the shelf laptop.
>
> Is there a driver for it during normal runtime?
Yes, that is a variant of NS16550 UART.
>
> > 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]
>
>
>
> I'll stick this in the queue to take a closer look after the next merge
> window closes. It's a bit on the late side in the 6.14 cycle for new stuff.
>
> I do appreciate the importance of having this tool in your toolbox.
> earlyprintk has saved my bacon more times than I can count.
Thanks!
--
Denis
© 2016 - 2025 Red Hat, Inc.