(本文是 Linux 启动第15篇)
很多人排 Linux 启动问题,
一上来就把 bootcmd 和 bootargs 混在一起。
最常见的话就是:
这俩不都是启动参数吗?哪个错了系统都起不来。
这句话不对。
它们都重要。
但根本不是一层东西。
bootcmd 管的是:
U-Boot 到底执行什么动作,把内核拉起来。
bootargs 管的是:
内核起来以后,拿着什么参数继续往下跑。
所以这篇只讲一件事:
bootcmd 和 bootargs 各自管哪一段,启动失败时该先查谁。
一句话先讲明白
bootcmd 管启动动作链,决定镜像怎么装、dtb 怎么带、最后怎么跳进内核;
bootargs 管内核启动参数,决定内核起来后按什么方式继续初始化。
bootcmd 错了,常常连内核都进不去;
bootargs 错了,内核往往能起来一段,但会死在 console、rootfs、init 这些后续环节。
第一,先分清角色
bootcmd 是一段 U-Boot 命令链。
它解决的是:
现在要怎么把内核启动起来。
常见内容包括:
从 eMMC、SD、flash、网络读取镜像
装载设备树
设置加载地址
调 bootm、booti、bootz
bootargs 是传给 Linux 内核的一串参数。
它解决的是:
内核接手以后,要按什么配置继续初始化。
常见内容包括:
console=
root=
rootwait
init=
mem=
最实用的记法就一句:
bootcmd 决定怎么进内核,bootargs 决定进内核后怎么继续跑。
第二,bootcmd 错了,系统通常死在内核前
这类问题本质上是 U-Boot 启动动作链错了。
典型现象是:
这类问题的共同点很明确:
Linux 还没真正接手。
所以只要卡在这里,
你去改 root=、console=,通常都打不到点上。
第三,bootargs 错了,系统通常死在内核接手后
bootargs 错,
往往不是“没启动”。
而是:
内核已经起来了,但拿到的启动说明书是错的。
典型现象包括:
所以 bootargs 这层的问题,
本质上是:
内核入口参数错了。
第四,现场到底先查谁
最实用的分界线只有一条:
内核到底有没有真正开始跑。
如果答案是:
没有。
那先查 bootcmd:
实际执行了什么
镜像和 dtb 从哪里读
地址对不对
bootm、booti、bootz 用得对不对
哪一步报错
如果答案是:
已经看到解压信息,或者 early boot log。
那优先查 bootargs:
这条线最有用。
因为它直接对应启动阶段。
第五,一个特别容易踩的坑
很多人默认以为:
printenv bootargs 看到什么,内核拿到的就一定是什么。
这经常不成立。
打印原始命令:
最终生效的 kernel cmdline,可能来自:
环境变量里的 bootargs
bootcmd 动态拼出来的参数
设备树里的 /chosen/bootargs
板级代码里的覆盖逻辑
所以真正要看的不是:
环境变量里写了什么。
而是:
最后传给内核的 kernel cmdline 到底是什么。
调试技巧:如何确认内核到底拿到了什么?
如果你怀疑 bootargs被覆盖,
不要猜,直接在内核源码或启动日 里找:
方法1:查看内核启动日志(dmesg)
Kernel command line:
console=ttymxc0,115200
root=/dev/mmcblk0p2 rootwait
方法2:在运行系统中查看
cat /proc/cmdline
只要这里显示的和 printenv bootargs不一样,100% 是被 bootcmd动态修改或 /chosen/bootargs覆盖了。
第六,最常见的几个误区
1. 把 bootcmd 和 bootargs 都当成“启动参数”
这会把动作链和内核参数链混在一起。
2. 一看到系统起不来就先改 bootargs
如果内核都没进,这通常是白改。
3. 以为 printenv bootargs 就等于最终 kernel cmdline
这在很多系统里都不成立。
4. 看到内核有输出,就以为 bootargs 一定没问题
很多 rootfs 和 init 问题都发生在后面。
最后怎么一句话记住
bootcmd 决定 U-Boot 怎么把系统送进内核,
bootargs 决定内核进去后按什么参数继续跑;
排障时先分清系统死在进内核前,还是死在进内核后。
现场排障速查
1. 系统无任何内核输出
先查 bootcmd:
镜像路径
dtb 地址
bootm、booti、bootz 是否正确
2. 内核能跑,但串口乱码或无输出
先查 bootargs 里的 console=。
3. 内核报 VFS: Cannot open root device
优先查 bootargs 里的 root= 和 rootwait。
4. 改了 bootargs,但系统没变化
先查是不是被别的地方覆盖了。
重点看:
/chosen/bootargs
bootcmd 里有没有动态重拼
板级逻辑有没有覆盖