2. 设备树编译与反编译:DTC工具的使用、DTS编译为DTB、DTB反编译为DTS、反编译实战
设备树源文件(.dts)是人类可读的文本描述,而内核引导时实际使用的是二进制格式的设备树二进制文件(.dtb)。DTC(Device Tree Compiler)是完成这一转换的核心工具。掌握DTC的编译与反编译操作,是进行设备树调试、驱动移植和覆盖(Overlay)开发的基础。
2.1 DTC工具概述
DTC是Linux内核源码树中自带的设备树编译器,通常位于 scripts/dtc/ 目录下。编译内核时会自动生成DTC可执行文件,也可单独编译安装。
| 文件类型 | 扩展名 | 说明 |
|---|---|---|
| 设备树源文件 | .dts |
文本格式,人类可读写,包含节点、属性和值 |
| 设备树二进制文件 | .dtb |
二进制格式,内核引导加载程序直接使用 |
| 设备树源包含文件 | .dtsi |
公共设备树片段,通过 #include 引入 |
| 设备树覆盖源文件 | .dtso |
用于运行时覆盖的源文件(Linux 5.x+ 推荐) |
| 设备树覆盖二进制文件 | .dtbo |
编译后的覆盖文件 |
提示:在较新的内核版本(5.x+)中,DTC 对覆盖源文件推荐使用
.dtso 扩展名,以与普通 .dts 区分。但传统上 .dts 仍可编译为 .dtbo。
2.2 DTS 编译为 DTB
将 .dts 源文件编译为 .dtb 二进制文件是设备树开发中最常用的操作。基本命令格式如下:
# 基本编译
dtc -I dts -O dtb -o output.dtb input.dts
# 常用参数说明
# -I dts : 指定输入格式为 dts
# -O dtb : 指定输出格式为 dtb
# -o : 指定输出文件名
# -@ : 生成 __symbols__ 节点(用于覆盖支持)
# -H epapr : 生成 EPAPR 标准头部(PowerPC 等架构使用)
# -W no-unit_address_vs_reg : 忽略某些警告
实战示例:编译一个简单的设备树文件,并启用覆盖支持。
# 1. 查看源文件内容
cat myboard.dts
# 2. 编译为 dtb(带符号表,支持覆盖)
dtc -I dts -O dtb -@ -o myboard.dtb myboard.dts
# 3. 验证编译结果
dtc -I dtb -O dts myboard.dtb | head -20
编译过程中常见的警告与处理方法:
| 警告信息 | 含义 | 处理建议 |
|---|---|---|
unit_address_vs_reg |
节点地址与 reg 属性不匹配 | 检查节点名称中的 @ 地址是否与 reg 一致 |
avoid_unnecessary_addr_size |
不必要的地址/大小单元 | 若总线只有单设备,可省略 #address-cells 和 #size-cells |
graph_child_address |
图形子节点地址问题 | 检查 ports/port 节点的 reg 属性 |
interrupt_provider |
中断控制器属性缺失 | 确认 interrupt-controller 和 #interrupt-cells 已添加 |
2.3 DTB 反编译为 DTS
反编译是将二进制 .dtb 还原为可读的 .dts 文本,常用于分析现有设备树、验证编译结果或从运行中的系统提取设备树。
# 基本反编译
dtc -I dtb -O dts -o output.dts input.dtb
# 反编译并保留所有信息(包括空节点、phandle 等)
dtc -I dtb -O dts -f -o output.dts input.dtb
# 从 /sys/firmware/devicetree 反编译运行中的设备树
dtc -I fs -O dts -o running.dts /sys/firmware/devicetree/base
注意:反编译得到的
.dts 文件与原始源文件在格式上可能略有差异。例如,phandle 属性会被显式写出,而原始源文件中可能使用 &label 引用。反编译结果主要用于分析和调试,不建议直接作为修改后的源文件重新编译。
2.4 反编译实战:从运行系统提取设备树
在实际嵌入式开发中,经常需要从正在运行的目标板上提取设备树,以分析当前硬件配置或作为移植的起点。
步骤一:确认设备树接口
# 检查 /sys/firmware/devicetree 是否存在
ls -l /sys/firmware/devicetree/base
# 若存在,说明内核通过设备树启动
# 若不存在,可能是 ACPI 或旧式板级文件
步骤二:使用 DTC 反编译
# 方法1:直接从 /sys 文件系统反编译
dtc -I fs -O dts -o extracted.dts /sys/firmware/devicetree/base
# 方法2:先复制 dtb,再反编译
cp /sys/firmware/fdt /tmp/board.dtb
dtc -I dtb -O dts -o extracted.dts /tmp/board.dtb
步骤三:分析反编译结果
# 查看设备树结构概览
grep -E "^[[:space:]]*[a-zA-Z]" extracted.dts | head -30
# 查找特定外设节点
grep -A 10 "uart" extracted.dts
# 查看内存配置
grep -A 5 "memory" extracted.dts
实战要点:
/sys/firmware/fdt是原始 DTB 的完整拷贝,大小与 DTB 文件一致。/sys/firmware/devicetree/base是内核解析后的文件系统视图,以目录结构呈现。- 反编译得到的
.dts中所有节点地址和大小都以十六进制显示,与原始源文件可能不同。 - 若目标板使用 U-Boot 引导,可在 U-Boot 命令行使用
fdt list查看设备树。
2.5 设备树编译与反编译流程
2.6 常见问题与避坑指南
| 问题 | 现象 | 解决方案 |
|---|---|---|
编译报错 syntax error |
DTC 解析失败 | 检查分号、花括号是否匹配;确认属性值格式正确 |
| 反编译后节点顺序错乱 | 与原始源文件顺序不同 | DTC 按地址排序,不影响功能;使用 -f 保留原始顺序 |
反编译出现 phandle 数值 |
引用变为数字 | 原始源文件中的 &label 被解析为数字 phandle,属正常现象 |
| 覆盖编译失败 | 缺少 __symbols__ 节点 |
编译时添加 -@ 参数生成符号表 |
运行系统无 /sys/firmware/devicetree |
内核未配置设备树支持 | 检查内核配置 CONFIG_OF 和 CONFIG_PROC_DEVICETREE |
重要提醒:反编译得到的 DTS 文件虽然语法正确,但通常包含大量
phandle 和 linux,phandle 属性,这些在原始源文件中并不存在。直接修改反编译后的 DTS 并重新编译可能导致引用关系混乱。正确的做法是:以反编译结果为参考,在原始源文件中进行修改。
2.7 本章小结
设备树的编译与反编译是嵌入式驱动开发中的基础技能。通过本章学习,应掌握:
- DTC 工具的基本用法和常用参数
- 将
.dts编译为.dtb的标准流程 - 从
.dtb或运行系统反编译为.dts的方法 - 编译与反编译过程中的常见问题及解决方案