2. 设备树编译与反编译
设备树源文件(.dts)是给人阅读和编辑的文本格式,而内核引导时实际加载的是二进制设备树 Blob(.dtb)。DTC(Device Tree Compiler)是完成这一转换的核心工具。掌握 DTC 的编译、反编译及常用选项,是设备树开发的基本功。
2.1 DTC 工具概述
DTC 是设备树编译器的标准实现,通常随内核源码一起发布,路径为 scripts/dtc/dtc。在嵌入式开发环境中,也可通过包管理器单独安装:
# Ubuntu / Debian
sudo apt-get install device-tree-compiler
# CentOS / RHEL / Fedora
sudo yum install dtc
# 验证安装
dtc --version
# 输出示例:Version DTC 1.6.1
提示:建议使用与内核版本匹配的 DTC 版本。较新的内核特性(如 overlay 语法、
#include 预处理)需要 DTC 1.4.7 以上版本支持。
2.2 编译 .dts 为 .dtb
最基本的编译命令将 .dts 源文件转换为 .dtb 二进制文件:
dtc -I dts -O dtb -o output.dtb input.dts
参数说明:
| 选项 | 含义 | 说明 |
|---|---|---|
-I dts |
输入格式 | 指定源文件为文本格式 .dts |
-O dtb |
输出格式 | 指定目标文件为二进制 .dtb |
-o |
输出文件 | 指定输出的 .dtb 文件名 |
-@ |
生成符号节点 | 为 overlay 编译时必须添加,生成 __symbols__ 节点 |
实际示例:
# 普通编译
dtc -I dts -O dtb -o myboard.dtb myboard.dts
# 为 overlay 编译(生成符号)
dtc -I dts -O dtb -@ -o myoverlay.dtbo myoverlay.dts
注意:overlay 文件通常使用
.dtbo 扩展名,但 DTC 本身不强制扩展名。使用 -@ 选项是 overlay 编译的关键,缺少该选项会导致 overlay 加载时无法解析符号。
2.3 反编译 .dtb 为 .dts
反编译用于从二进制 .dtb 恢复可读的 .dts 源文件,常用于调试、逆向分析或验证编译结果:
dtc -I dtb -O dts -o output.dts input.dtb
实际示例:
# 反编译内核使用的 dtb
dtc -I dtb -O dts -o decompiled.dts /boot/dtb/am335x-boneblack.dtb
# 反编译并保留 phandle 原始值
dtc -I dtb -O dts -f -o full.dts board.dtb
反编译时常用选项:
| 选项 | 作用 | 适用场景 |
|---|---|---|
-f |
强制输出,忽略错误 | 处理损坏或不完整的 .dtb |
-s |
按地址排序节点 | 便于对比不同版本的 .dtb |
-R |
保留原始 phandle 值 | 需要精确还原引用关系时 |
2.4 常用编译选项详解
DTC 提供丰富的选项来控制编译行为,以下为最常用的选项:
| 选项 | 全称 | 功能描述 |
|---|---|---|
-@ |
symbols | 生成 __symbols__ 节点,overlay 编译必需 |
-H |
phandle format | 指定 phandle 格式:epapr(默认)、linux、both |
-W |
warnings | 启用特定警告,如 -W no-unit_address_vs_reg |
-E |
errors | 将警告升级为错误,如 -E unit_address_vs_reg |
-b |
boot cpu | 设置引导 CPU 编号,多核系统使用 |
-p |
padding | 在 .dtb 末尾添加填充字节 |
-S |
size | 指定 .dtb 最小尺寸,不足时填充 |
-v |
version | 显示 DTC 版本信息 |
高级编译示例:
# 启用所有警告,并将地址/大小不匹配视为错误
dtc -I dts -O dtb -o safe.dtb -W all -E unit_address_vs_reg input.dts
# 指定 phandle 格式为 linux 兼容模式
dtc -I dts -O dtb -H linux -o linux_phandle.dtb input.dts
# 生成最小 4KB 的 dtb,末尾填充 256 字节
dtc -I dts -O dtb -S 4096 -p 256 -o padded.dtb input.dts
2.5 编译与反编译流程
2.6 预处理与编译联合使用
实际项目中,.dts 文件通常通过 #include 引用 .dtsi 头文件。DTC 本身不处理 #include,需要先经过 C 预处理器(cpp)展开:
# 手动预处理 + 编译
cpp -nostdinc -I include -undef -x assembler-with-cpp \
input.dts preprocessed.dts
dtc -I dts -O dtb -o output.dtb preprocessed.dts
# 一步完成(推荐)
dtc -I dts -O dtb -o output.dtb -i include input.dts
其中 -i 选项指定头文件搜索路径,可多次使用:
dtc -I dts -O dtb -o output.dtb \
-i include \
-i arch/arm/boot/dts \
-i arch/arm/boot/dts/include \
input.dts
2.7 编译检查与调试
DTC 提供丰富的警告和错误检查机制,帮助发现设备树中的问题:
| 检查类别 | 典型警告/错误 | 说明 |
|---|---|---|
| 地址/大小 | unit_address_vs_reg |
节点地址与 reg 属性不匹配 |
| 中断 | interrupt_provider |
中断控制器声明不一致 |
| GPIO | gpio_cells |
GPIO 描述符单元数错误 |
| 时钟 | clock_provider |
时钟提供者/消费者不匹配 |
| 语法 | syntax |
分号、括号、引号等语法错误 |
调试示例:
# 启用所有警告
dtc -I dts -O dtb -o test.dtb -W all test.dts
# 将特定警告升级为错误
dtc -I dts -O dtb -o test.dtb -E unit_address_vs_reg test.dts
# 只显示错误,不输出 dtb
dtc -I dts -O dtb -o /dev/null test.dts 2>&1 | grep ERROR
实战建议:在提交设备树代码前,使用
dtc -W all 进行完整检查。对于 overlay 文件,额外使用 dtc -@ -W all 确保符号生成正确。将警告数控制在 0 是设备树开发的最佳实践。
2.8 常用操作速查表
| 操作 | 命令 | 说明 |
|---|---|---|
| 编译 .dts → .dtb | dtc -I dts -O dtb -o out.dtb in.dts |
基本编译 |
| 编译 overlay | dtc -I dts -O dtb -@ -o out.dtbo in.dts |
必须加 -@ |
| 反编译 .dtb → .dts | dtc -I dtb -O dts -o out.dts in.dtb |
基本反编译 |
| 强制反编译 | dtc -I dtb -O dts -f -o out.dts in.dtb |
忽略错误 |
| 带预处理编译 | dtc -I dts -O dtb -i include_dir -o out.dtb in.dts |
自动处理 #include |
| 完整检查 | dtc -I dts -O dtb -W all -o out.dtb in.dts |
启用所有警告 |
| 查看版本 | dtc -v |
确认工具版本 |