0. 这一节要解决什么
第 1 课时的启动链讲过:U-Boot 交接给内核的是四个对象——Kernel、DTB、bootargs、(可选 initrd)。DTB 是其中之一。本节把「源码侧的 DTS」与「启动侧的 DTB」接起来:boot 分区里到底放了什么、U-Boot 怎么决定加载哪个 DTB、如何确认板子用的正是期望的版本。
1. DTB 在启动时间线上的位置
boot 分区(extboot.img) U-Boot Kernel
┌───────────────────────┐ ┌───────────────────┐ ┌──────────────────┐
│ Image │──>│ 读 extlinux.conf │──>│ 解析 DTB 建设备 │
│ <board>.dtb │ │ 加载 Image+DTB │ │ 从 /chosen 取 │
│ extlinux/extlinux.conf│ │ bootargs→/chosen │ │ bootargs(1课时) │
└───────────────────────┘ └───────────────────┘ └──────────────────┘
回顾第 1 课时的两条结论,在这里都有了着落:
- 交接三要素:
booti <Image 地址> <initrd 地址> <DTB 地址>——DTB 地址是显式参数 - bootargs 的传递媒介:U-Boot 把参数写进 DTB 的
/chosen节点——DTB 同时是硬件描述和参数的载体
2. 本 SDK:extboot 封装与 extlinux 配置
本 SDK 板级配置带 USE_EXTBOOT=y,./build.sh extboot 产出的 kernel/extboot.img(及同内容的 kernel/extboot/ 目录)就是 boot 分区的全部内容:
kernel/extboot/
├── Image 内核镜像
├── rk3576-firefly-roc-rk3576-pc.dtb
└── extlinux/extlinux.conf U-Boot 的启动配置
extlinux.conf 是 U-Boot 侧的「启动菜单」:它声明加载哪个内核、哪个 DTB、附加什么 bootargs。U-Boot 启动时读取它,而不是写死在环境变量里——改 DTB 选择,改的就是这个文件。
观念辨析(第 1 课时的延伸):extboot.img 只是封装容器。启动阶段仍是
U-Boot → Kernel,封装不是链路中的一棒——分区存在 ≠ 已被读取,读取 ≠ 已正确加载。
3. 「用哪个 DTB」由谁决定
三层,从上到下:
| 层 | 内容 | 谁控制 |
|---|---|---|
| 源码层 | 板级入口 defconfig 的 RK_KERNEL_DTS_NAME="rk3576-firefly-roc-rk3576-pc" |
编译配置 |
| 打包层 | extlinux.conf 的内核与 fdt 行 |
build.sh extboot 生成 |
| 运行层 | U-Boot 实际读取 boot 分区哪个文件 | boot 分区内容 + U-Boot 环境 |
三层要一致,闭环才算走通——任何一层指向别处,板子用的就不是期望的 DTB。这正是「改了没生效」最常发生的地方。
4. DTB 与板卡不匹配会发生什么
| 症状 | 原因 |
|---|---|
早期 panic / 卡死在 Starting kernel ... 之后 |
DTB 描述与实际硬件差异过大(如内存、控制台地址) |
| 系统能起,某外设缺失或行为异常 | 节点缺失或配置不符(如换屏未换对应 dtsi) |
| 一切正常但改动无效 | 加载的是旧 DTB(部署没到位 / extlinux 指向别处) |
5. 双侧验证
U-Boot 侧(打断倒计时进命令行):
ls mmc 0:4 / # boot 分区根目录(分区号以 part list 结果为准)
ls mmc 0:4 /extlinux
load mmc 0:4 ${loadaddr} /extlinux/extlinux.conf && cat ${loadaddr}
内核侧(进入系统后):
cat /proc/device-tree/model
tr -d '\0' < /proc/device-tree/compatible
ls /sys/firmware/devicetree/base/ # 与 /proc/device-tree 同源
对齐判断:U-Boot 读到的 extlinux.conf 里 fdt 指向的文件名,应与内核侧 /proc/device-tree/model 反映的 DTS 一致——两侧对上了,才证明「编译的 = 部署的 = 运行的」。
6. Lab:读出 boot 分区的真实内容
# 1) U-Boot 侧
# 打断倒计时后:
ls mmc 0:4 /extlinux
load mmc 0:4 ${loadaddr} /extlinux/extlinux.conf && cat ${loadaddr}
# 记录:fdt 行指向的 dtb 文件名、append 行的 bootargs
# 2) 内核侧(等系统起来后)
cat /proc/device-tree/model
tr -d '\0' < /proc/device-tree/compatible
# 3) 对照:三者的 DTS 名称是否一致?
7. 本节小结
- DTB 是 U-Boot 交给内核的对象之一;同时承担
/chosen传参的载体 - 本 SDK 的 boot 分区 = Image + DTB +
extlinux/extlinux.conf,由./build.sh extboot打包 - 「用哪个 DTB」有三层:编译配置 → extlinux.conf → U-Boot 实际读取,三层一致才生效
- 验证靠双侧对齐:U-Boot 读到的配置 vs
/proc/device-tree的内容
8. 本节思考
Q1:extlinux.conf 里的 bootargs 和 U-Boot 环境变量 bootargs 是什么关系?
查看答案
extlinux.conf 的 append 行由 extlinux 启动路径解析并写进 DTB 的 /chosen,效果与手工 setenv bootargs 一致;两者是同一对象的两个来源。优先级以实际走的启动路径为准——手工 booti 前设置的 bootargs 直接生效,extlinux 自动启动则用 append 行。排障时用 printenv bootargs 与 extlinux.conf 互相印证。
Q2:为什么 /proc/device-tree 能反映「板子实际在用哪个 DTB」,而看 boot 分区文件不能?
查看答案
boot 分区里可能同时存在多个 dtb / 多份配置,文件在那里不等于被加载。/proc/device-tree 是内核解析传入的那个 DTB 后在内存中的映射,它反映的是事实而非库存。这就是「分区存在 ≠ 已找到 ≠ 已生效」三段式的应用——验证必须看生效侧的证据。
Q3:如果想让同一块板子在两块屏幕之间切换,按本节模型应该动哪一层?
查看答案
动源码层的板级配置:本板的屏幕相关节点位于单独的 dtsi(rk3576-firefly-roc-rk3576-pc-mipi101-....dtsi),Firefly 的做法是不同屏配对应 dts/dtsi 变体,由 RK_KERNEL_DTS_NAME 选定后重新 ./build.sh extboot 并部署。也可以在 DTB 成品上做 overlay(dtbo)热切换,那属于进阶用法,本课先掌握「重新编译完整 DTB」的路径。