第3章 设备树编译器:DTC工具安装、编译与反编译
设备树写好了,怎么变成机器能懂的东西?
这就得靠DTC——Device Tree Compiler。说白了,它就是个翻译官,把咱们写的.dts文本文件,转成二进制.dtb,让内核能直接解析。反过来,也能把.dtb还原成.dts,方便调试。
我个人习惯把DTC比作「菜刀」——切菜、剁肉、拍蒜都靠它。你用熟了,后面所有设备树工作都会顺手很多。
3.1 DTC工具安装
不同平台安装方式不一样。我列个表,你对照自己的环境来。
| 操作系统 | 安装命令 | 备注 |
|---|---|---|
| Ubuntu/Debian | sudo apt install device-tree-compiler |
最省事,推荐 |
| CentOS/RHEL | sudo yum install dtc |
EPEL源可能需要先配好 |
| Arch Linux | sudo pacman -S dtc |
滚动更新,版本较新 |
| macOS (Homebrew) | brew install dtc |
记得先装Xcode Command Line Tools |
| 源码编译 | make && sudo make install |
从内核源码scripts/dtc/目录编译 |
装完之后,验证一下:
dtc --version
# 输出类似:Version DTC 1.6.1
看到版本号,说明装好了。
3.2 编译:从.dts到.dtb
编译是DTC最常用的功能。命令格式很简单:
dtc -I dts -O dtb -o 输出.dtb 输入.dts
参数说明:
-I dts:输入格式是.dts文本-O dtb:输出格式是.dtb二进制-o 输出.dtb:指定输出文件名- 最后一个参数:输入文件名
举个例子。假设你写了个my-board.dts,想编译成my-board.dtb:
dtc -I dts -O dtb -o my-board.dtb my-board.dts
运行完,当前目录下就会多出my-board.dtb文件。
3.2.1 常用编译选项
实际项目中,光用基本命令不够。我整理了几个常用选项:
| 选项 | 作用 | 示例 |
|---|---|---|
-@ |
生成插件节点(overlay)支持 | dtc -@ -I dts -O dtb -o out.dtb in.dts |
-H |
指定phandle格式(epapr或linux) | dtc -H epapr -I dts -O dtb ... |
-W |
启用特定警告 | dtc -W no-unit_address_vs_reg ... |
-E |
启用特定错误检查 | dtc -E no_property_name ... |
-O |
输出格式(dtb/dts/asm) | -O dtb |
-I |
输入格式(dts/dtb/fs) | -I dts |
避坑指南:我曾经在一个项目里,编译出来的dtb加载后系统直接panic。后来发现是忘了加-@选项,导致overlay节点没被正确处理。如果你用设备树插件(overlay),-@必须加上。
3.2.2 编译过程中的常见错误
编译报错是家常便饭。我遇到过最多的几种:
- 语法错误:少了个分号、括号不匹配。DTC会提示行号,直接去改就行。
- 引用未定义节点:比如
&uart0引用了不存在的节点。检查label定义。 - 属性值类型错误:比如
reg属性写了字符串而不是数字。DTC会报Bad property value。 - 文件包含路径问题:
#include找不到头文件。用-i选项指定搜索路径。
举个例子,一个典型的语法错误:
// 错误写法:少了分号
/ {
compatible = "my-board"
model = "test";
};
// 正确写法
/ {
compatible = "my-board";
model = "test";
};
DTC会报:ERROR: Input tree missing ';' at line 3。看到这个,直接去第3行加个分号就行。
3.3 反编译:从.dtb到.dts
反编译就是把二进制.dtb还原成文本.dts。这在调试时特别有用——比如你拿到一个别人编译好的.dtb,想看看里面到底配了什么。
命令格式:
dtc -I dtb -O dts -o 输出.dts 输入.dtb
举个例子:
dtc -I dtb -O dts -o my-board-reverse.dts my-board.dtb
运行完,my-board-reverse.dts就是反编译出来的文本。
.dts可能和原始文件不完全一样。比如注释会丢失,节点顺序可能调整。但核心内容——节点、属性、值——是完整的。我经常用反编译来验证编译过程有没有「偷工减料」。
3.3.1 反编译的实用场景
- 调试内核加载的dtb:从
/sys/firmware/devicetree/base复制出来,反编译看看内核实际用了什么配置。 - 逆向别人的设备树:拿到一个闭源板子的
.dtb,反编译后学习它的硬件布局。 - 验证编译结果:编译完再反编译,对比原始
.dts,确保没有信息丢失。
我记得有一次,客户给了一个.dtb文件,说板子启动有问题。我反编译一看,发现GPIO的gpio-hog节点配错了——输出电平写反了。改完重新编译,问题解决。反编译在这类场景下就是救命稻草。
3.4 DTC工作流程总览
下面这张图,把DTC的编译、反编译、以及它在整个设备树开发流程中的位置,画清楚了。
从这张图能看出来:
- 正向流程:
.dts→ 编译 →.dtb→ 内核加载 - 反向流程:
.dtb→ 反编译 →.dts→ 调试/验证 - 迭代开发:编辑 → 编译 → 测试 → 反编译验证 → 再编辑
嗯,这个循环就是设备树开发的日常。你想想看,没有DTC,咱们连第一步都迈不出去。
3.5 实战:完整编译与反编译示例
光说不练假把式。咱们拿一个最简单的.dts文件,走一遍完整流程。
先创建一个test.dts:
/dts-v1/;
/ {
compatible = "test-board";
model = "Test Board v1.0";
cpu@0 {
compatible = "arm,cortex-a7";
reg = <0x00>;
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>;
};
};
然后编译:
dtc -I dts -O dtb -o test.dtb test.dts
没有报错的话,反编译看看:
dtc -I dtb -O dts -o test-reverse.dts test.dtb
打开test-reverse.dts,内容应该和原始文件基本一致,只是注释没了,节点顺序可能微调。核心数据——compatible、reg、model——都在。
验证技巧:用diff命令对比原始文件和反编译文件,看差异在哪里。
diff test.dts test-reverse.dts
如果只有注释和空行的差异,说明编译/反编译过程没问题。
3.6 本章小结
DTC是设备树开发的基础工具。装好它,学会编译和反编译,你就能在.dts和.dtb之间自由切换。后面章节里,我们会频繁用到这两个操作——写设备树、编译、加载、调试、反编译验证,循环往复。
我个人觉得,反编译这个功能被很多人低估了。它不只是「逆向」,更是「验证」和「学习」的利器。你拿到一个陌生的.dtb,反编译一看,里面的硬件布局、地址分配、中断配置,全都清清楚楚。比看文档还直观。