The serial console is a very helpful debugging tool for kernel development. However, when a crash occurs early in the boot process, one is left in the dark. There are two early console implementations available with different merits. This post will throw some lights on them.
The kernel supports earlyprintk since… probably ever. At least 2.6.12, where the new age (git) started. After enabling “Kernel low-level debugging”, “Early printk” under “Kernel hacking” and selecting an appropriate low-level debugging port, you are ready to get early serial console output.
This functionality builds upon “Kernel low-level debugging”, which provides printascii, printch and printhex helper functions (written in ARM assembly, see arch/arm/kernel/debug.S). These functions build on the selected “low-level debugging port” implementation. A given platform has to implement addruart, senduart, busyuart and waituart. This basic “assembler UART driver” presumes that the boot loader already enabled the UART and configured its parameters (e.g. baudrate). Typically, a simple store operation puts the character into the UARTs data register and blocks in busyuart until the character is sent. When building a zImage, the low-level debugging port code is in the uncompressed part of the kernel binary and hence allows to print something even before uncompressing starts (the kernel prints “Uncompressing Linux… done, booting the kernel.”). It is obvious, that this is highly platform dependent and does not work well together with the ARM multi-platform support. However, it provides the earliest possible debugging support through a console.
Rob Herring proposed earlycon for arm64 in March 2014. The patchset consolidates common code from the earlycon support available for i386 (which was there since 2007, where it had been renamed from early_uart). The implementation builds upon early fixed MMU memory mapping support to access the IO registers (early fixmap). However, up until now, early fixmap support for 32-Bit ARM was still missing. With Linux 4.3 the early fixmap patchset, which I have been working on, has been merged upstream. This occasion lead me to blog about this.
A big advantage of earlycon is that it can be built into single or multi-platform kernels even for production use. This is useful if users encounter early kernel crashes which you can’t reproduce on your side. Asking the user to compile a kernel with earlyprintk might be not possible. Also, nowadays drivers can get initialized in a crazy order, leading to situations where the serial driver is being initialized rather late during the boot process (as it happen to be the case on Vybrid, the platform I work with a lot). This of course increases the chance to encounter kernel bugs which do not print anything on the serial console.
Currently, not many serial drivers support earlycon. The kernels kernel-parameter.txt documentation file lists the supported drivers. Another indication that a driver supports earlycon is if the SERIAL_EARLYCON config symbol is being selected (check the lower portion of the help text in make nconfig) or grep through the driver/tty/ tree and search for the earlycon registration macros (OF_)EARLYCON_DECLARE. There are two ways how the earlycon mechanism learns about the base address of the UART and which driver to use: Either from the device tree or from kernel arguments.
Most device trees supply the stdout-path property which specifies which UART instance shall be used as the serial console. If the kernel parameter “earlycon” (without further options) is specified, the kernel tries to find an appropriate earlycon UART driver by using the compatible property of the UART instance referenced by the stdout-path or linux,stdout-path property. The base address is then used from that same node. The kernel should start to use the serial console almost right away, indicating that earlycon is in use within the first few lines:
bootconsole [uart0] enabled
This variant has the advantage that the user does not need to know about these specific information of the platform.
If you see the following string instead, the early console is not in use:
Malformed early option 'earlycon'
The current implementation does not handle stdout-path properties with colons properly (e.g. “serial0:115200n8”). However, this is the preferred way how boards nowadays specify the standard serial console… There is already a fix lined up for Linux 4.4.
Using the kernel parameter method, one has to supply the driver name (again, check the kernel-parameters.txt for a list of the available driver names) plus options, usually the base address, e.g. “earlycon=lpuart,0x40028000“. Again, with that in place, the kernel should start to use the console almost right away and indicate that within the first few lines:
earlycon: Early serial console at MMIO 0x40027000 (options '') bootconsole [uart0] enabled
Btw, regarding Freescale Vybrid, I just now sent a patchset to enable earlycon for LPUART. 🙂