2、DTS、DTB、DTC 关系详解:源文件、编译产物与编译器工作流程

设备树从可读的文本描述到内核可解析的二进制数据,需要经过一个明确的编译流程。理解 DTS(源文件)、DTB(二进制) 与 DTC(编译器) 三者之间的关系,是调试设备树编译报错的基础。

2.1 核心概念定义

在深入工作流程之前,先明确三个核心组件的定义与角色:

组件 全称 文件格式 核心作用
DTS Device Tree Source 纯文本(.dts / .dtsi) 开发者编写的设备树源文件,描述硬件拓扑、寄存器地址、中断、时钟等节点信息。
DTC Device Tree Compiler 可执行程序 将 DTS 源文件编译为 DTB 二进制文件的工具,同时负责语法检查与错误报告。
DTB Device Tree Blob 二进制(.dtb) Bootloader 传递给内核的最终设备树数据,内核通过解析 DTB 来枚举和配置硬件。
关键区分: .dtsi 文件是“包含头文件”,通常用于存放 SoC 公共定义(如 CPU 核、中断控制器、时钟控制器),而 .dts 文件是板级文件,通过 #include 引用 .dtsi 并添加或覆盖板级特有的外设节点。

2.2 完整工作流程:从源文件到二进制

DTC 的编译过程并非简单的文本到二进制转换,它包含预处理、语法解析、节点合并、符号生成和二进制打包等多个阶段。下图展示了从 .dts 源文件到 .dtb 二进制文件的完整流水线:

DTS → DTB 编译流水线 阶段1:预处理 展开 #include 宏 合并 .dts + .dtsi 阶段2:语法解析 词法/语法分析 构建抽象语法树 阶段3:节点合并 同名节点属性覆盖 标签引用解析 阶段4:符号生成 生成符号表 生成 /memreserve/ 阶段5:二进制打包输出 生成 DTB 头部 + 结构块 + 字符串块 输入:.dts + .dtsi 输出:.dtb 二进制文件

2.3 编译命令与典型输出

在实际开发中,最常用的 DTC 编译命令格式如下:

# 基本编译:将 .dts 编译为 .dtb
dtc -I dts -O dtb -o output.dtb input.dts

# 反编译:将 .dtb 反编译为 .dts(调试利器)
dtc -I dtb -O dts -o output.dts input.dtb

# 生成符号表(用于设备树叠加层)
dtc -@ -I dts -O dtb -o output.dtb input.dts
参数说明:
  • -I:指定输入格式(dts 或 dtb)。
  • -O:指定输出格式(dtb 或 dts)。
  • -o:指定输出文件名。
  • -@:生成符号表,支持设备树叠加层(DTO)功能。
  • -Wno-unit_address_vs_reg:忽略某些非致命警告,常用于清理编译输出。

2.4 编译过程中的常见报错类型

DTC 在编译过程中会执行严格的语法和语义检查。理解报错类型有助于快速定位问题:

错误类型 典型报错信息 常见原因
语法错误 syntax error before '...' token 缺少分号、花括号不匹配、属性值格式错误。
节点重复 Duplicate node name 'xxx' 同一层级下出现两个相同名称的节点,且未使用 label: node 区分。
属性类型错误 Expected integer value for property 'reg' reg 属性需要 <u32> 或 <u64> 格式,却写成了字符串。
引用未定义 Reference to non-existent node or label '&xxx' 使用 &xxx 引用标签,但该标签未在任何地方定义。
地址格式错误 Bad cell value for 'reg' reg 属性中的地址或长度值不是合法的十六进制数。

2.5 反编译验证:调试的“照妖镜”

当 DTC 编译成功但内核行为异常时,反编译验证 是最有效的调试手段之一。通过将编译后的 .dtb 反编译回 .dts,可以检查 DTC 是否按照预期合并了节点、覆盖了属性。

反编译验证的典型场景:
  • 节点覆盖检查: 确认 .dtsi 中的默认值是否被板级 .dts 正确覆盖。
  • 标签解析验证: 检查 &xxx 引用是否被正确展开为完整节点路径。
  • 属性值精度确认: 验证 reg、interrupts 等数值属性是否按预期编码。
  • 删除操作确认: 检查 /delete-node/ 或 /delete-property/ 是否生效。

反编译命令示例:

# 将编译后的 DTB 反编译为可读的 DTS
dtc -I dtb -O dts -o decompiled.dts compiled.dtb

# 对比原始 DTS 与反编译 DTS 的差异
diff -u original.dts decompiled.dts

2.6 工作流程中的关键注意事项

  • 预处理顺序: DTC 内部调用 C 预处理器(cpp)处理 #include、#define 和 #ifdef,因此可以在 .dts 中使用 C 风格的宏定义。
  • 节点合并规则: 同名节点在合并时,后出现的属性值会覆盖先出现的属性值,但子节点会递归合并而非覆盖。
  • 标签作用域: 标签(label)在整个设备树中必须是唯一的,否则 DTC 会报重复标签错误。
  • 二进制对齐: DTB 文件内部结构要求 4 字节对齐,DTC 会自动填充对齐字节,开发者无需手动处理。