What Is earlycon?
During early kernel boot, the standard console subsystem (serial drivers, framebuffer consoles, etc.) hasn’t been initialized yet. If the kernel panics or you need debug output during this phase, you get nothing — unless you have earlycon.
earlycon is a minimal console mechanism that provides output as soon as the kernel enters C code (start_kernel). It works by directly writing to UART registers (via MMIO) without relying on the full serial driver stack. Once the real console driver takes over, earlycon is automatically unregistered.
Enabling earlycon
Two kernel config options are required:
CONFIG_SERIAL_EARLYCON=y
CONFIG_OF_EARLY_FLATTREE=y
Then pass the earlycon parameter on the kernel command line. The format is:
earlycon=<name>,<io_type>,<addr>,<options>
For example:
earlycon=uart8250,mmio32,0xfe660000,115200n8
earlycon=pxa_serial,0xd4017000
earlycon=sbi # RISC-V SBI console
earlycon # auto-detect from device tree stdout-path
When earlycon is passed without arguments, the kernel uses the device tree stdout-path to find the right UART and driver (covered in the DT path section below).
Path 1: Command-Line Based Initialization
Call Chain
start_kernel()
→ setup_arch()
→ parse_early_param()
→ parse_early_options()
→ do_early_param() // iterates all __setup("earlycon", ...) entries
→ param_setup_earlycon()
→ setup_earlycon()
→ register_earlycon()
How early_param Works
The kernel’s parse_early_param() scans the boot command line and calls handler functions registered via the early_param() macro. For earlycon, this is:
| |
parse_args() tokenizes the command line into key-value pairs and calls do_early_param() for each one:
| |
This iterates the __setup section — a linker-defined table of early parameter handlers. When it finds the "earlycon" entry, it calls param_setup_earlycon(val) where val is the string after earlycon=.
setup_earlycon: Matching the Driver
| |
The function iterates __earlycon_table — a linker section populated by the EARLYCON_DECLARE and OF_EARLYCON_DECLARE macros. It first tries to match entries with an empty compatible field (command-line drivers), then falls back to DT-compatible entries.
After stripping the driver name prefix, the remaining string (e.g., "0xd4017000") is passed to register_earlycon().
The __earlycon_table Section
Drivers register themselves into __earlycon_table using two macros:
| |
The earlycon_id struct:
| |
The linker script places these in a contiguous table:
.init.data : {
__earlycon_table = .;
KEEP(*(__earlycon_table))
__earlycon_table_end = .;
}
Example: SpacemiT K1 (pxa_serial)
| |
With earlycon=pxa_serial,0xd4017000 on the command line:
setup_earlyconmatches"pxa_serial"in__earlycon_tablebufbecomes"0xd4017000"after stripping the nameregister_earlyconparses the address and callspxa_early_console_setup
register_earlycon: Bringing the Console Online
| |
Key steps:
- parse_options — parses the I/O type (
mmio,mmio32,io) and physical address from the parameter string, setsport->mapbaseandport->iotype - earlycon_map — maps the physical UART register address into virtual memory via
ioremapso the kernel can access it - match->setup — calls the driver-specific setup function (e.g.,
pxa_early_console_setup), which sets thewritecallback - register_console — registers the earlycon as an active console; from this point,
printkoutput goes to the UART
parse_options: Address and Baud Rate Parsing
| |
The I/O type determines how the UART registers are accessed:
UPIO_MEM— byte-width MMIOUPIO_MEM32— 32-bit MMIO (most common on ARM/RISC-V SoCs)UPIO_PORT— x86-style I/O port access
Path 2: Device Tree Based Initialization
When earlycon is passed without arguments on the command line (or not passed at all but CONFIG_SERIAL_EARLYCON is enabled), the kernel can auto-detect the earlycon UART from the device tree’s stdout-path property.
| |
This function:
- Finds the
/chosennode in the flattened device tree - Reads
stdout-path(e.g.,"/serial@d4017000:115200") - Splits the path and options at the
:delimiter - Resolves the path to a DT node and checks its
compatibleproperty against__earlycon_tableentries registered viaOF_EARLYCON_DECLARE - Calls
of_setup_earlyconwhich extracts the MMIO address from the DT node’sregproperty and calls the driver’s setup function
This is the preferred approach for device-tree platforms — no hardcoded addresses on the command line.
Lifecycle: earlycon → Real Console
earlycon is registered with the CON_BOOT flag, which tells the console subsystem it’s a temporary boot console:
| |
When the real serial driver initializes later in boot (e.g., 8250_port.c, pxa.c) and calls register_console(), the kernel automatically unregisters all CON_BOOT consoles. You’ll see this in dmesg:
[ 0.000000] earlycon: uart0 at MMIO32 0xfe660000 (options '115200n8')
[ 0.000000] printk: legacy bootconsole [uart0] enabled
...
[ 1.234567] printk: legacy bootconsole [uart0] disabled
The handoff is seamless — no output is lost because CON_PRINTBUFFER ensures any messages buffered during the transition are replayed on the new console.