3. 设备树编译与反编译:DTC工具使用、dtb生成、fdtdump反编译、设备树覆盖(overlay)简介
设备树源文件(.dts / .dtsi)是文本格式的描述文件,必须经过编译生成二进制设备树 Blob(.dtb),才能被内核或引导加载程序解析。本章深入讲解设备树的编译与反编译工具链、二进制格式、以及动态修改设备树的覆盖(Overlay)机制。
3.1 DTC 工具与设备树编译流程
DTC(Device Tree Compiler)是设备树源文件的官方编译器,负责将 .dts 文本转换为 .dtb 二进制,并支持反编译与输出汇编格式。
3.1.1 DTC 工具安装与版本
| 平台 | 安装命令 | 验证版本 |
|---|---|---|
| Ubuntu/Debian | sudo apt install device-tree-compiler |
dtc --version |
| Fedora/RHEL | sudo dnf install dtc |
dtc --version |
| Buildroot/Yocto | 默认包含在 host-dtc 包中 |
内核源码 scripts/dtc/ 内置 |
内核内置 DTC: Linux 内核源码
scripts/dtc/ 目录下包含 DTC 源码,编译内核时会自动构建。使用 make dtbs 可直接编译内核中的设备树。
3.1.2 编译命令与参数
基本编译命令格式:
dtc -I dts -O dtb -o output.dtb input.dts
常用参数说明:
- -I:输入格式,
dts(源文件)、fs(文件系统)、dtb(二进制) - -O:输出格式,
dtb(二进制)、dts(源文件)、asm(汇编) - -o:输出文件名
- -@:生成符号节点,支持 Overlay 动态加载
- -H:指定 phandle 格式(epapr/linux)
- -W / -E:启用/禁用特定警告或错误检查
生产环境建议: 编译时始终添加
-@ 参数,即使当前不使用 Overlay,也能保留未来扩展能力。同时使用 -W no-unit_address_vs_reg 避免某些 SoC 特有的误报。
3.1.3 编译流程示意图
3.2 DTB 二进制格式与结构
DTB 是设备树的二进制表示,采用扁平化结构(Flattened Device Tree, FDT),由头部(Header)、内存预留块(Memory Reservation Block)、结构块(Structure Block)和字符串块(Strings Block)四部分组成。
3.2.1 DTB 头部字段
| 偏移 | 字段名 | 大小 | 说明 |
|---|---|---|---|
| 0x00 | magic | 4 字节 | 魔数,固定为 0xD00DFEED |
| 0x04 | totalsize | 4 字节 | DTB 文件总大小(大端序) |
| 0x08 | off_dt_struct | 4 字节 | 结构块偏移 |
| 0x0C | off_dt_strings | 4 字节 | 字符串块偏移 |
| 0x10 | off_mem_rsvmap | 4 字节 | 内存预留块偏移 |
| 0x14 | version | 4 字节 | 版本号,当前为 17 |
| 0x18 | last_comp_version | 4 字节 | 向后兼容最低版本,通常为 16 |
| 0x1C | boot_cpuid_phys | 4 字节 | 引导 CPU 的物理 ID |
| 0x20 | size_dt_strings | 4 字节 | 字符串块大小 |
| 0x24 | size_dt_struct | 4 字节 | 结构块大小 |
3.2.2 结构块节点类型
结构块使用令牌(Token)标记节点边界,每个令牌 4 字节对齐:
- FDT_BEGIN_NODE (0x00000001):节点开始,后跟节点名(含 '\0' 填充对齐)
- FDT_END_NODE (0x00000002):节点结束
- FDT_PROP (0x00000003):属性定义,后跟属性值长度、属性名偏移、属性值
- FDT_NOP (0x00000004):空操作,用于填充对齐
- FDT_END (0x00000009):结构块结束
字节序注意: DTB 所有多字节字段均使用大端序(Big-Endian)。在 x86 等小端序平台上解析时,必须进行字节序转换。内核使用
be32_to_cpu() 宏处理。
3.3 fdtdump 反编译与调试
fdtdump 是 DTC 工具包提供的 DTB 反编译工具,可将二进制 DTB 转换为可读的文本格式,用于调试和逆向分析。
3.3.1 基本用法
# 反编译 DTB 到标准输出
fdtdump board.dtb
# 保存到文件
fdtdump board.dtb > board_debug.dts
# 使用 dtc 反编译(更规范的输出)
dtc -I dtb -O dts -o board_reverse.dts board.dtb
3.3.2 fdtdump 与 dtc 反编译对比
| 特性 | fdtdump | dtc -I dtb -O dts |
|---|---|---|
| 输出格式 | 原始十六进制 + 文本混合 | 标准 DTS 语法 |
| 可读性 | 较低,适合底层调试 | 高,可直接修改后重新编译 |
| 保留注释 | 不保留 | 不保留 |
| 地址显示 | 显示原始偏移 | 不显示偏移 |
| 适用场景 | 验证 DTB 结构完整性 | 逆向工程、恢复源文件 |
3.3.3 反编译输出解读
// 使用 fdtdump 查看 DTB 头部
$ fdtdump board.dtb | head -20
/dts-v1/;
// magic: 0xd00dfeed
// totalsize: 0x1000 (4096)
// off_dt_struct: 0x48
// off_dt_strings: 0x9c0
// off_mem_rsvmap: 0x28
// version: 17
// last_comp_version: 16
// boot_cpuid_phys: 0x0
// size_dt_strings: 0x40
// size_dt_struct: 0x978
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
#address-cells = <0x1>;
#size-cells = <0x1>;
...
};
调试技巧: 当内核启动时设备树解析失败,可使用
fdtdump 检查 DTB 的 totalsize 是否与文件实际大小一致,以及结构块偏移是否在文件范围内。常见错误是编译时 #include 路径错误导致节点缺失。
3.4 设备树覆盖(Overlay)简介
设备树覆盖(Device Tree Overlay)允许在系统运行时动态添加或修改设备树节点,无需重新编译整个 DTB。Overlay 在 FPGA 动态重配置、外设热插拔、内核模块加载等场景中广泛应用。
3.4.1 Overlay 工作原理
3.4.2 Overlay 源文件编写
Overlay 源文件使用 /dts-v1/; 和 /plugin/; 标记,通过 &label 引用基础 DTB 中的节点:
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target = &am33xx_pinmux;
__overlay__ {
my_device_pins: my_device_pins {
pinctrl-single,pins = <0x078 0x07 0x038 0x07>;
};
};
};
fragment@1 {
target = &ocp;
__overlay__ {
my_device {
compatible = "my,driver";
pinctrl-0 = <&my_device_pins>;
reg = <0x48000000 0x1000>;
interrupts = <56>;
status = "okay";
};
};
};
};
3.4.3 Overlay 编译与加载
编译 Overlay 时必须添加 -@ 参数生成符号表:
# 编译 Overlay
dtc -@ -I dts -O dtb -o my_overlay.dtbo my_overlay.dts
# 通过 configfs 加载(内核需配置 CONFIG_OF_OVERLAY)
mkdir /sys/kernel/config/device-tree/overlays/my_overlay
cat my_overlay.dtbo > /sys/kernel/config/device-tree/overlays/my_overlay/dtbo
# 卸载 Overlay
rmdir /sys/kernel/config/device-tree/overlays/my_overlay
3.4.4 Overlay 与传统 DTB 对比
| 特性 | 传统 DTB | Overlay (.dtbo) |
|---|---|---|
| 加载时机 | 系统启动时一次性加载 | 系统运行时动态加载/卸载 |
| 修改范围 | 定义完整硬件拓扑 | 增量修改,可新增/覆盖/禁用节点 |
| 符号解析 | 无需外部符号 | 依赖基础 DTB 的 __symbols__ |
| 编译参数 | 无需特殊参数 | 必须使用 -@ |
| 典型应用 | 固定硬件平台 | FPGA 重配置、扩展板、热插拔 |
Overlay 使用限制: 内核需启用
CONFIG_OF_OVERLAY 和 CONFIG_CONFIGFS_FS。Overlay 不能删除已有节点,只能通过设置 status = "disabled" 禁用。多个 Overlay 加载顺序可能影响最终设备树视图,需谨慎管理依赖关系。
3.5 本章小结
- DTC 工具是设备树编译的核心,支持
dts→dtb编译和反向操作,-@参数为 Overlay 提供符号支持。 - DTB 格式采用大端序扁平化结构,包含头部、内存预留块、结构块和字符串块,内核通过 OF API 逐令牌解析。
- fdtdump 提供底层 DTB 结构查看能力,
dtc -I dtb -O dts则生成可重新编译的标准 DTS。 - 设备树覆盖通过
/plugin/和fragment机制实现运行时动态修改,是 FPGA 和可扩展平台的关键技术。