很多人第一次看 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 阶段,而且日志最少、排查最难。