当前位置:首页>Linux>Linux 启动第十二篇:Linux内核early boot卡死、无串口输出?一文讲透早期启动流程

Linux 启动第十二篇:Linux内核early boot卡死、无串口输出?一文讲透早期启动流程

  • 2026-10-11 08:17:31
Linux 启动第十二篇:Linux内核early boot卡死、无串口输出?一文讲透早期启动流程

很多人第一次看 Linux 启动日志,

都会有一种感觉:

前面 U-Boot 还比较好懂,

一到内核接手,

日志突然就变得又密、又快、又硬。

更麻烦的是现场排障时,

这段还特别容易出一种让人发懵的现象:

• 内核明明已经开始启动了  

• 但系统就是死在 very early 阶段  

• 没有用户态  

• 没有 shell  

• 甚至连完整串口输出都没有

这时候很多人会下意识觉得:

内核不是已经起来了吗,为什么还能死得这么早?

问题就出在这里。

内核“开始启动”和“系统已经真正站稳”不是一回事。

一句话先讲明白

early boot 本质上是内核刚接过 CPU 后,在系统还没真正完整建立起来之前,先把最基础的运行骨架搭起来的一段早期初始化阶段。

这些骨架包括:

• CPU 最早期运行环境  

• 内存管理基础  

• 设备树和 bootargs

• 早期控制台输出  

• init 之前的核心子系统基础初始化

所以 early boot 的关键不是功能多,

而是:

它是后面一切正常运行的前提。

第一,什么叫 early boot?

可以把它简单理解成:

从 bootloader 跳进内核入口开始,到内核把最基础的自举初始化做完、准备继续往后启动的这一段。

这时候的系统状态很特别:

• 已经不归 U-Boot 管了  

• 但还远没到用户空间  

• 内核正在一边初始化自己,一边把硬件环境真正接管过来

也就是说,

系统虽然已经“进了内核”,

但还没有进入大家熟悉的 Linux 正常运行状态。

它最像什么?

最像一个刚接手现场、先把工作台搭起来的阶段。

如果这张工作台还没搭稳,

后面的初始化、驱动加载、挂根文件系统、启动 init,

都没法谈。

第二,内核在 early boot 里到底先干什么?

内核刚接过 CPU,

第一件事当然不是启动应用,

而是先满足自己最基本的生存条件。

粗一点看,

early boot 主要在搭 4 类东西。

1. 先把 CPU 运行环境站稳

包括:

• 建立最早期执行路径  

• 准备早期栈  

• 做架构相关初始化  

• 建立异常处理最基础的前提

这部分很底层,

但没它就根本走不下去。

2. 把最早期内存管理立起来

内核得尽快知道:

• 内存在哪  

• 有多大  

• 哪些区域能用  

• 哪些区域不能碰

所以内存识别、地址映射、早期分配这些事,

几乎一定是 early boot 主线。

3. 解析设备树和启动参数

比如:

• 板级硬件描述是不是对的  

• /chosen/bootargs 是什么  

• console 和 earlycon 怎么配  

• 保留内存在哪里  

• 哪些设备后面应该初始化

这一步一旦错,

后面很多现象都会被整体带歪。

4. 建立最早期可观测性

很多平台你能不能看到 early log,

取决于 earlycon 和串口早期输出有没有起来。

所以 early boot 干的不只是“继续初始化”,

也在努力建立:

我至少还能把自己现在跑到哪说出来。

第三,为什么很多问题都死在 early boot?

因为这段最脆弱。

它正好卡在一个很尴尬的位置:

• bootloader 已经退出  

• 用户空间还没开始  

• 内核正在裸接管整台机器  

• 但很多基础能力又还没完全就绪

所以这时候只要某个基础条件没满足,

系统就很容易直接卡死。

现场最常见的根因,

通常集中在这几类。

1. 内存相关问题

比如:

• 内存识别不对  

• 设备树里的 memory 节点不对  

• reserved-memory 冲突  

• 早期页表或地址映射异常

这类问题最致命,

因为 early boot 非常依赖最基础的内存可用性。

2. 设备树问题

比如:

• dtb 跟板子不匹配  

• /chosen/bootargs 不对  

• 串口节点错了  

• 中断控制器描述有问题  

• 某些关键外设描述不成立

它的麻烦在于:

表现经常不像“设备树错了”,而像“系统莫名其妙起不来”。

3. 输出链路没打通

有时候内核其实还在继续跑,

只是你看不到。

这会形成一个非常典型的误判:

你以为内核死了,其实只是 earlycon 或 console 没起来。

4. SoC 早期交接条件不成立

比如某些平台的:

• 时钟状态  

• 中断控制器初始化前提  

• 电源域状态  

• cache 或 MMU 切换条件

如果 bootloader 到内核这一步交得不完整,

内核在 very early 阶段就很容易翻车。

一句话说透:

early boot 初始化的不是普通功能,而是系统最基本的生存条件。

第四,为什么 early boot 问题特别难查?

因为它天生就缺三样东西:

• 日志  

• 上下文  

• 后手

日志少,

是因为很多输出能力本身还没完全起来。

上下文少,

是因为用户空间、服务、调试工具都还不存在。

后手少,

是因为系统一旦卡死,

你能拿到的信息非常有限。

所以 early boot 最烦人的地方就在这里:

• 现象常常只是“停住了”  

• 停住之前未必留下足够线索  

• 你也没法像用户态问题那样临时加很多观测手段

这也是为什么真正做启动排障的人,

都会优先抓这几个入口:

• earlycon

• 串口早期输出  

• 设备树和 bootargs 

• 启动阶段分层判断

因为这几样东西,

往往就是 early boot 排障最基本的抓手。

第五,现场最常见的 early boot 表现是什么?

如果问题死在这段,

现场通常会看到这几种典型表现。

1. 停在 “Starting kernel ...” 后没下文

这通常说明:

• U-Boot 已经把控制权交给内核了  

• 但内核接手后非常早就出问题了  

• 或者输出链路根本没打通

2. 有几行 early log,然后突然没了

这往往比“完全没输出”更有价值。

因为它至少说明:

内核不是完全没跑,而是死在某个更具体的早期初始化点。

3. 内核似乎启动了,但串口一直很安静

这类情况最容易误判。

优先看:

• console= 对不对  

• earlycon 有没有开  

• 串口节点和时钟配置对不对  

• dtb 和实际硬件是不是匹配

4. 偶发卡在 very early 阶段

这类情况要特别警惕:

• 内存边界问题  

• 时序问题  

• 某些底层条件不稳定

如果现象带随机性,

就不要只盯“代码逻辑对不对”,

还要看底层前提是不是稳定。

第六,工程上怎么快速判断更像是 early boot 问题?

最实用的办法不是盲猜,

而是先判断:

系统最远到底走到了哪。

可以先粗分三层。

1. 如果还停在 U-Boot,连 “Starting kernel ...” 都没看到

那问题大概率还不属于 early boot,

如果连 Uncompressing Linux...都没出现,问题通常不在内核初始化,而在 内核解压阶段或者 U-Boot 传参(如 entry point)不对。

更可能在:

• U-Boot 加载流程  

• 启动命令  

• kernel、dtb、initrd 地址  

• bootargs

2. 如果已经看到 “Starting kernel ...”

那说明控制权大概率已经交给内核了。

这时候,

early boot 就应该进入优先怀疑范围。

3. 如果有少量 early log,但没有后续初始化日志

优先看:

• 设备树  

• earlycon 和 console

• 内存描述  

• 架构相关早期初始化

所以判断 early boot,

核心不是“感觉像不像”,

而是:

先确认控制权是不是已经交给内核了,再看它死在初始化哪一层。

第七,工程上最该怎么理解 early boot?

如果你想把这件事真正理解透,

最重要的不是去背一串启动函数名,

而是先抓住它的本质。

early boot 不是在“正常跑系统”,而是在“先把系统骨架搭起来”。

这套骨架至少包括:

• 让内核自己能稳定执行  

• 让内核知道硬件长什么样  

• 让内核知道内存怎么用  

• 让内核能继续初始化后续核心子系统  

• 最终把系统带到 initramfs 或根文件系统挂载前

所以 early boot 一旦失败,

影响的不是某一个局部功能,

而是:

整个 Linux 系统后面还有没有机会成立。

第八,工程上到底怎么把 earlycon 配起来?(附实操抓手)

前面反复强调 earlycon 是救命稻草,那到底怎么把它拉起来?

不用记复杂的源码,工程上只要盯住三个抓手:

1. 先确认内核把“早期打印”的开关打开了

在 make menuconfig时,至少要保证这几个宏是开着的:

a. CONFIG_SERIAL_EARLYCON(总开关)

b. 对应你所用串口的早期驱动

PL011 串口对应:CONFIG_SERIAL_AMBA_PL011_EARLYCON 8250 串口对应:CONFIG_SERIAL_8250_EARLYCON

2. 让 bootargs 知道你要用谁

U-Boot 传给内核的 bootargs 里,需要明确指定 earlycon。

最稳妥的写法是直接指定驱动和寄存器地址,

earlycon=pl011,0x90000000

如果不想硬编码地址,也可以偷懒用设备树里的别名,

earlycon=pl011,mmio32,0x90000000

3. 确保设备树里的 stdout-path 没指错路

内核初始化早期,会去设备树的 /chosen节点里找 stdout-path。

如果这个路径和你的实际串口节点对不上,earlycon 一样哑火。

所以排障时,顺手 fdtdump 看一下 dtb 里的 /chosen/stdout-path指向哪个串口。

一句话总结配置逻辑:

内核开好宏 ➔ U-Boot 传对参数 ➔ 设备树指对路子。

最后怎么一句话记住?

内核 early boot 是 Linux 刚接过 CPU 后、先把最基础运行环境搭起来的一段早期初始化阶段;它要完成最早期 CPU 环境、内存、设备树、控制台等关键基础工作,这一步一旦失败,系统往往就会死在 very early 阶段,而且日志最少、排查最难。

最新文章

随机文章