3. 设备树编译器:DTC(Device Tree Compiler)的使用方法
设备树源文件(.dts)是给人阅读和编辑的文本格式,而内核引导时实际加载的是二进制设备树 Blob(.dtb)。DTC(Device Tree Compiler)就是完成这一转换的核心工具。本章将系统讲解 DTC 的安装、编译、反编译以及常见调试技巧。
核心概念: DTC 是设备树生态的“翻译官”,负责将人类可读的
.dts 转换为机器可解析的 .dtb,同时支持反向还原,是驱动开发调试中不可或缺的瑞士军刀。
3.1 DTC 工具链安装与验证
DTC 通常包含在 device-tree-compiler 软件包中。不同发行版的安装命令如下:
| 发行版 | 安装命令 | 验证命令 |
|---|---|---|
| Ubuntu / Debian | sudo apt install device-tree-compiler |
dtc --version |
| Fedora / RHEL | sudo dnf install dtc |
dtc --version |
| Arch Linux | sudo pacman -S dtc |
dtc --version |
| Yocto / Buildroot | 默认包含在 host-utils 中 |
dtc -v |
提示: 如果系统未安装,也可以从内核源码的
scripts/dtc/ 目录下直接编译使用:make scripts/dtc/dtc。
3.2 从 .dts 编译为 .dtb
编译是最常用的操作。基本语法如下:
dtc -I dts -O dtb -o output.dtb input.dts
参数说明:
-I dts:指定输入格式为设备树源文件(.dts)。-O dtb:指定输出格式为设备树二进制 Blob(.dtb)。-o output.dtb:指定输出文件名。input.dts:输入的源文件。
实战示例: 假设我们有一个简单的设备树源文件 myboard.dts:
/dts-v1/;
/ {
compatible = "myboard,devkit";
#address-cells = <1>;
#size-cells = <1>;
uart0: serial@10000000 {
compatible = "ns16550";
reg = <0x10000000 0x1000>;
interrupts = <0 33 4>;
clock-frequency = <24000000>;
};
};
执行编译命令:
dtc -I dts -O dtb -o myboard.dtb myboard.dts
编译成功后,会生成 myboard.dtb 文件。可以使用 hexdump 或 strings 查看其二进制内容:
hexdump -C myboard.dtb | head -20
strings myboard.dtb
常见错误: 如果
.dts 文件中引用了 .dtsi 头文件(如 #include "soc.dtsi"),编译时需确保头文件路径正确,或使用 -i 参数指定搜索路径:dtc -I dts -O dtb -i ./include -o output.dtb input.dts。
3.3 从 .dtb 反编译为 .dts
反编译用于调试、逆向分析或从现有系统中提取设备树配置。基本语法:
dtc -I dtb -O dts -o output.dts input.dtb
参数说明:
-I dtb:指定输入格式为二进制设备树。-O dts:指定输出格式为源文件。-o output.dts:输出反编译后的源文件。
实战示例: 将上一节编译出的 myboard.dtb 反编译:
dtc -I dtb -O dts -o myboard_recovered.dts myboard.dtb
查看反编译结果:
cat myboard_recovered.dts
输出应基本还原原始 .dts 内容,但节点顺序和注释可能会丢失。
实用技巧: 在嵌入式 Linux 开发板上,可以通过
/sys/firmware/fdt 获取当前内核使用的设备树二进制文件:cp /sys/firmware/fdt /tmp/current.dtb,然后反编译分析实际生效的设备树配置。
3.4 DTC 编译与反编译流程 SVG 图
下图展示了 DTC 在设备树开发中的核心工作流:
3.5 常用编译选项详解
DTC 提供了丰富的选项来控制编译行为,下表列出了最常用的参数:
| 选项 | 全称 | 功能说明 | 示例 |
|---|---|---|---|
-I |
Input format | 指定输入文件格式:dts、dtb、fs(文件系统) |
-I dts |
-O |
Output format | 指定输出文件格式:dts、dtb、asm(汇编) |
-O dtb |
-o |
Output file | 指定输出文件名 | -o board.dtb |
-i |
Include path | 添加头文件搜索路径(可多次使用) | -i ./include |
-@ |
Symbols | 生成符号节点(用于设备树叠加层) | -@ |
-H |
Phandle format | 指定 phandle 格式:legacy、epapr |
-H epapr |
-W |
Warning | 启用特定警告(如 -W unit_address_vs_reg) |
-W no-unit_address_vs_reg |
-E |
Error | 将警告升级为错误 | -E unit_address_vs_reg |
3.6 编译检查与调试
DTC 在编译时会进行语法和语义检查,常见警告及处理方法如下:
- unit_address_vs_reg:节点名中的地址与
reg属性不匹配。检查节点命名规范,如serial@10000000应与reg = <0x10000000 ...>一致。 - avoid_unnecessary_addr_size:根节点不必要地定义了
#address-cells和#size-cells。如果子节点没有reg属性,可以移除。 - graph_child_address:图形相关节点地址格式错误。检查
ports、endpoint等节点的reg属性。 - interrupt_provider:中断控制器节点缺少
#interrupt-cells属性。确保中断控制器节点正确声明。
调试技巧: 使用
-W no-xxx 可以临时屏蔽特定警告,但建议在开发阶段保持所有警告可见。使用 -E xxx 可将特定警告升级为错误,强制修复问题。
3.7 设备树叠加层(DT Overlay)编译
设备树叠加层(.dtbo)用于运行时动态修改设备树,常用于 FPGA 配置、外设热插拔等场景。编译叠加层需要添加 -@ 选项:
dtc -I dts -O dtb -@ -o overlay.dtbo overlay.dts
叠加层源文件示例:
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = &uart0;
__overlay__ {
status = "okay";
baud-rate = <115200>;
};
};
};
编译后生成 overlay.dtbo,可通过内核的 configfs 接口动态加载:
mkdir /sys/kernel/config/device-tree/overlays/my_overlay
cat overlay.dtbo > /sys/kernel/config/device-tree/overlays/my_overlay/dtbo
3.8 实战:完整编译与反编译流程
以下是一个完整的实战流程,涵盖从编写到验证的全过程:
- 编写源文件:创建
myboard.dts,包含必要的节点和属性。 - 编译为 .dtb:
dtc -I dts -O dtb -o myboard.dtb myboard.dts - 检查编译结果:
dtc -I dtb -O dts myboard.dtb快速查看内容。 - 反编译验证:
dtc -I dtb -O dts -o myboard_check.dts myboard.dtb - 对比差异:
diff myboard.dts myboard_check.dts确认还原度。 - 生成叠加层:
dtc -I dts -O dtb -@ -o myboard.dtbo myboard_overlay.dts
最佳实践: 在版本控制中同时保存
.dts 和 .dtsi 源文件,.dtb 作为构建产物不纳入仓库。每次修改后执行编译+反编译双重验证,确保设备树语义正确。
3.9 本章小结
DTC 是设备树开发的核心工具,掌握其编译与反编译操作是驱动开发的基本功。通过本章学习,你应该能够:
- 独立完成
.dts到.dtb的编译。 - 从现有
.dtb反编译出可读的.dts用于调试。 - 理解常用编译选项的含义和适用场景。
- 处理常见的编译警告和错误。
- 编译设备树叠加层用于动态配置。