[第2课时 · 8/8] 编译 Kernel 并修改设备树

0. 这一节要解决什么

前面把两条构建链拆开讲清楚了,这一节把它们合起来走一遍:修改一个可见、可验证、低风险的设备树属性,完成「改 → 编译 → 定位 → 部署 → 验证」的完整闭环,并掌握「改了没生效」的六站排查法。

1. 闭环总览

修改 ──> 编译 ──> 定位 ──> 部署 ──> 启动 ──> 验证
(改哪层) (extboot)(产物路径)(boot 分区)(U-Boot 加载)(/proc/device-tree)

2. 实验目标:改 model 字符串

选 model 作为第一个目标,因为它最安全且天然可验证——/proc/device-tree/model 直接读出。目标:把板子上的 model 改成带个人标记的字符串,然后让它真的生效。

3. 第一步:修改

cd kernel/arch/arm64/boot/dts/rockchip/
cp rk3576-firefly-roc-rk3576-pc.dts rk3576-firefly-roc-rk3576-pc.dts.bak   # 先备份
vim  rk3576-firefly-roc-rk3576-pc.dts

把

model = "Firefly ROC-RK3576-PC Linux HDMI";

改为

model = "UESTC-ZS <你的学号或姓名缩写> ROC-RK3576-PC";

回滚手段:保留的 .bak、或 git checkout -- <文件>(SDK 是 git 仓库)。

4. 第二步与第三步:编译并定位产物

cd <SDK>
./build.sh lunch          # 确认选中的是 firefly_rk3576_roc-rk3576-pc_ubuntu_defconfig
./build.sh extboot

编译完成后核对三处证据:

ls -l kernel/extboot.img                          # ① 镜像时间戳应为刚刚
ls -l kernel/extboot/                             # ② 目录内的 Image 与 dtb
dtc -I dtb -O dts kernel/extboot/rk3576-firefly-roc-rk3576-pc.dtb | grep model
                                                  # ③ DTB 里 model 已是新字符串

第 ③ 条是关键:在产物层面确认改动已进入 DTB,再谈部署。

5. 第四步:部署

两种方式任选:

方式 A · 拷文件(推荐,快)——板子能进系统、网络或 U 盘可用时:

# PC → 板子(scp 示例,IP 以板子实际为准)
scp kernel/extboot/* firefly@<板子IP>:/tmp/extboot/

# 板子上
sudo cp /tmp/extboot/Image /tmp/extboot/*.dtb /boot/
sudo cp -r /tmp/extboot/extlinux /boot/
sudo reboot

方式 B · 烧写镜像(板子进不了系统时用)——板子进 Loader 模式(RECOVERY 键 + 复位),PC 上:

sudo upgrade_tool di -boot kernel/extboot.img

两种方式等价:boot 分区的三个组成物被更新即可。

6. 第五步与第六步:启动并验证

重启板子,进系统后:

cat /proc/device-tree/model
# 预期输出:UESTC-ZS <你的学号或姓名缩写> ROC-RK3576-PC

tr -d '\0' < /proc/device-tree/compatible
# 预期输出:rockchip,rk3576-firefly-roc-rk3576-pcrockchip,rk3576

model 变了 → 六站闭环走通:从这一刻起,本板的内核设备树是自己编的版本,后续所有设备树实验都在它之上进行。

7. 六站排查:改了没生效怎么办

站 问题 证据
1 源文件 改的是被目标 DTS include 的文件吗 目标 dts 的 include 列表
2 语法规则 dtc 报错了吗(分号、括号、cells) 编译日志末尾 DTC 输出
3 配置目标 编译选的是当前板卡的 DTS 吗 defconfig 的 RK_KERNEL_DTS_NAME
4 编译产物 目标 .dtb 时间戳更新了吗 ls -l kernel/extboot/
5 启动选择 U-Boot 实际加载的是这个 DTB 吗 extlinux.conf 的 fdt 行
6 运行结果 model / compatible 变了吗 /proc/device-tree

第 5 站最容易漏:编译产物是新的,U-Boot 却仍加载旧文件(部署位置不对、extlinux 指向别处)。

8. 进阶:改 status 开关一个设备

model 只动了字符串。第二步实验动「设备是否存在」:

  1. 在 dts(或其 dtsi)中选一个本实验不需要的设备节点,如某个摄像头接口
  2. status = "okay" ↔ "disabled" 各编译部署一次
  3. 对比 /sys/bus/ 下对应设备实例与 dmesg 的出现 / 消失

status 影响的是设备树条件——实例被创建与否。这是后续「某外设为什么不工作」类问题的第一查。

9. 本节小结

  • 闭环六站:修改 → 编译 → 定位 → 部署 → 启动 → 验证,每站留证据
  • 产物层面先验证(dtc 反编译 grep),再烧板——排错成本最低的顺序
  • 部署两方式:拷 kernel/extboot/ 三件套,或 upgrade_tool di -boot
  • 「没生效」沿六站查,第 5 站(启动选择)最容易漏

10. 本节思考

Q1:为什么把「在产物层面验证」放在部署之前?颠倒顺序的代价是什么?

查看答案

产物验证只需一条 dtc ... | grep 命令,秒级完成;若跳过它直接部署,编译侧的问题(改错文件、DTS 配置目标不对)要到重启后才发现,表现为「板子没变化」,此时需要在六站里回溯,还要重新走一遍部署。验证越靠前,单次定位成本越低——与第 1 课时「先确认输入再执行」的原则同源。

Q2:改动进入了 DTB,/proc/device-tree/model 却没变。最可能是哪一站出了问题?给出两条检查命令。

查看答案

第 5 站(启动选择)或部署不到位。检查:① U-Boot 侧读 extlinux.conf 确认 fdt 行指向的文件;② ls -l /boot/ 对比板上 dtb 的时间戳与编译产物是否一致。此外确认部署后确实重启过——/proc/device-tree 是启动时内存中的映射,不重启不会变。

Q3:直接改公共 dtsi 完成本实验可行吗?为什么实验仍建议改 dts 入口?

查看答案

可行,model 在根节点、改 dtsi 的根节点同样生效。但公共 dtsi 可能被多块板共用,改动的评估面更大;dts 入口文件改动只影响本板,风险最小。原则:优先改影响面最小的层——这也是工程上「板级配置收拢在板级文件」的用意。备份与 git 回滚同样不能省。