当前位置:首页>Linux>Linux 内核早期日志体系:console、earlycon、loglevel 到底怎么配?

Linux 内核早期日志体系:console、earlycon、loglevel 到底怎么配?

  • 2026-09-03 19:39:17
Linux 内核早期日志体系:console、earlycon、loglevel 到底怎么配?

做内核启动调试时,最容易犯的一个错就是:

屏幕一黑,串口一静,就下结论说“系统挂了”。

但实际情况经常不是这样。

很多时候,系统根本没死,只是日志链路没打通。内核还在跑,只是它没法把启动信息送到你眼前。

这也是为什么 console=、earlycon=、loglevel= 这几个参数看起来很小,却特别实用。把它们搞明白,很多“黑屏疑案”会简单很多。

一、为什么会出现“系统没死,只是没日志”

Linux 启动是分阶段进行的。

在最早期,CPU 刚进入内核,很多基础能力都还没完全准备好。这个时候即使内核代码已经开始执行,也不代表日志一定能正常输出。

常见现象是:

1. Bootloader 阶段串口有输出,一进内核就安静了。

2. 后面能看到登录提示,但前面的启动日志完全没有。

3. 板子其实还能 ping 通,但串口没任何信息。

4. 明明程序在跑,看起来却像“死机”。

问题的关键不是有没有 printk,而是当前有没有一条可用的日志输出通道。

没有通道,你就会误判。

二、console= 和 earlycon= 到底差在哪

这两个参数经常一起出现,但作用完全不同。

console= 是正式控制台。

比如:

console=ttyS0,115200

它的意思是,等正式串口驱动起来之后,把日志输出到 ttyS0,波特率是 115200。

注意重点:等驱动起来之后。

所以只配 console=,通常只能看到“后半段”日志。真正最早那一段,你还是看不到。

earlycon= 是早期控制台。

比如:

earlycon

或者:

earlycon=uart8250,mmio,0xfe660000

它的作用是,在正式控制台还没建立之前,先临时把早期日志打出来。

一句话总结:

earlycon= 解决“最开始能不能看到”

console= 解决“后面稳定输出到哪里”

这俩不是二选一,很多时候是要一起配的。

三、为什么建议两个一起用

最常见、也最稳的做法就是:

earlycon console=ttyS0,115200 loglevel=8

或者平台相关一点:

earlycon=uart8250,mmio,0xfe660000 console=ttyS0,115200 loglevel=8

启动过程可以理解成接力:

1. earlycon 先负责最早期输出

2. 正式串口驱动初始化

3. console= 指定的控制台接手

4. 整段日志尽量连续

如果你只写 console=,前面有一大段时间其实还是黑的。

四、串口名写错,系统可能是好的,但你就是看不到

这是特别常见的坑。

很多人以为 Bootloader 用的是某个串口,Linux 肯定也是同一个名字。其实不一定。

不同平台常见的串口名可能是:

ttyS0

ttyAMA0

ttymxc0

ttyMSM0

如果 console= 里的名字写错了,会发生什么?

很简单:系统可能正常启动了,但日志没打到你监听的那个口上。你这边一片安静,于是误以为内核挂了。

所以看到“没日志”,先别急着判断死机,先确认串口名对不对。

五、波特率不对,常见表现不是没日志,而是乱码

比如你串口工具开的是 115200,内核实际按别的波特率在发,那你看到的往往不是“完全没输出”,而是一堆乱码。

这时候很容易误判成内存踩坏、程序跑飞、异常打印。

实际上,问题可能只是串口参数没对上。

要确认的点很简单:

● 串口工具波特率是否正确

● Bootloader 和内核是否一致

● 当前监听的是不是对的物理串口

● 早期日志阶段本来就脆弱,参数不准,看到的东西就不可信。

六、MMIO 地址为什么会影响 early log

earlycon 经常会带一个 MMIO 地址:

earlycon=uart8250,mmio,0xfe660000

这个地址不是随便填的,它是 UART 控制器寄存器基地址。

因为 early console 工作得非常早,那时候很多完整驱动机制还没起来,所以它需要你直接告诉它:“去这个寄存器地址发字符。”

如果地址写错了,后果通常是:

1. 完全没日志

2. 日志乱码

3. 更糟时直接访问异常

所以 earlycon 这件事,最重要的不只是“写了没有”,而是“类型和地址对不对”。

七、loglevel= 控制的是日志多少,不是日志往哪打

这个点也很容易混。

loglevel= 的作用不是选输出设备,而是决定哪些级别的日志允许打印到控制台。

调试时常见写法:

loglevel=8

有时还会搭配:

ignore_loglevel

它们的作用是尽量把更多日志放出来,方便排查问题。

但要注意,如果 console 或 earlycon 根本没打通,那你把 loglevel 调再高也没用。

因为它只决定“打不打”,不决定“打到哪”。

所以这三个参数要分开理解:

● earlycon=:最早期能不能看见

● console=:正式日志往哪去

●loglevel=:日志放多少出来

八、怎么让启动过程更“可见”

如果你的目标是排障,而不是碰运气,建议这样配:

console=ttyS0,115200 earlycon=uart8250,mmio,0xfe660000 loglevel=8 ignore_loglevel

如果还想更强一点,可以临时加:

initcall_debug

它很适合看内核卡在哪个初始化调用附近。

调试阶段的核心思路就一句话:

先让系统尽可能多说话,再去分析它说了什么。

九、一个非常实用的判断思路

启动日志最有价值的地方,不只是“有没有”,而是“断在哪”。

比如:

● 连 Linux version 都看不到:说明问题非常早

● 能看到 early log,后面没了:可能是 early console 结束后,正式 console 没接上

● 能看到大量驱动初始化:说明系统其实已经跑到很后面了

所以启动调试时,千万别一看到没输出就说“系统死了”。

更准确的问法应该是:

系统是真的停住了,还是只是从这里开始我看不见了?

这两个问题,差别非常大。

十、最容易踩的几个坑

1. console= 设备名写错

2. earlycon= 串口类型写错

3. MMIO 地址写错

4. 波特率不匹配

5. 只配 console= 不配 earlycon=

6. 日志一断就直接断言系统挂了

真正有经验的人,遇到启动黑屏时,第一反应通常不是“死机”,而是:

先查日志链路。

结尾

console=、earlycon=、loglevel= 这几个参数虽然小,但它们解决的是启动调试里最关键的一件事:可见性。

很多启动问题,不是代码没跑,而是你没看见它跑到哪了。

可以把它们记成三句话:

● earlycon= 把最早期照亮

● console= 把正式输出接稳

● loglevel= 把该看的日志尽量放出来

做内核 bring-up 的时候,最怕的不是报错太多,最怕的是什么都看不见。

启动调试的第一步,不是证明系统死了,而是先确认:它是不是只是没有机会开口说话。

最新文章

随机文章