2. DTS、DTB、DTC 关系:DTS 源文件、DTB 二进制文件、DTC 编译器的概念与工作流程
在嵌入式 Linux 开发中,设备树(Device Tree)是描述硬件资源的标准化数据结构。理解 DTS(源文件)、DTB(二进制文件)和 DTC(编译器)三者之间的关系,是掌握设备树机制的第一步。本章将系统梳理三者的定义、差异以及完整的编译工作流程。
2.1 核心概念定义
设备树的开发流程类似于 C 语言的“源文件 → 编译 → 二进制”模型。下表对比了三者的核心定位:
| 术语 | 全称 | 本质 | 可读性 | 用途 |
|---|---|---|---|---|
| DTS | Device Tree Source | 文本源文件 | 人类可读 | 开发者编写硬件描述 |
| DTB | Device Tree Blob | 二进制数据块 | 机器可读 | Bootloader 传递给内核 |
| DTC | Device Tree Compiler | 编译工具 | — | 将 DTS 编译为 DTB |
关键认知: DTS 是“图纸”,DTC 是“施工队”,DTB 是“成品”。内核启动时直接读取 DTB,不接触 DTS。
2.2 DTS 源文件详解
DTS 文件采用树形结构描述硬件节点,每个节点包含属性(property)和子节点。一个典型的 DTS 文件片段如下:
/dts-v1/;
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am335x";
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
compatible = "arm,cortex-a8";
reg = <0x0>;
};
};
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x10000000>; /* 256 MB */
};
};
- /dts-v1/; — 版本标识,必须位于文件头部。
- / — 根节点,所有硬件节点均挂载其下。
- model / compatible — 描述板级型号与兼容性。
- reg — 地址与大小信息,是节点最重要的属性之一。
2.3 DTB 二进制文件结构
DTB 是扁平化的二进制数据,由 DTC 编译生成。其内部结构包含三个主要区域:
- 头部(Header) — 魔数、大小、版本号、偏移量等信息。
- 结构块(Structure Block) — 以 token 形式存储节点和属性的树形结构。
- 字符串块(Strings Block) — 存储属性名称的字符串表,节省空间。
实际调试技巧: 使用
dtc -I dtb -O dts -o dump.dts board.dtb 可将 DTB 反编译为 DTS,用于验证编译结果或逆向分析。
2.4 DTC 编译器工作流程
DTC 不仅支持 DTS → DTB 的正向编译,还支持 DTB → DTS 的反向反编译,以及 DTS/DTB 与文件系统(fs)格式之间的转换。其标准工作流程如下:
2.5 完整编译命令示例
在实际开发中,最常用的 DTC 命令如下:
# 正向编译:DTS → DTB
dtc -I dts -O dtb -o myboard.dtb myboard.dts
# 反编译:DTB → DTS
dtc -I dtb -O dts -o myboard.dts myboard.dtb
# 生成可读的 DTS 文件(带标签和注释)
dtc -I dtb -O dts -o myboard.dts -@ myboard.dtb
# 检查 DTB 合法性
dtc -I dtb -O dtb -o /dev/null myboard.dtb
常见错误: 如果 DTS 中包含
#include 指令,必须使用 -i 参数指定头文件搜索路径,否则预处理阶段会失败。例如:dtc -I dts -O dtb -i ./include -o output.dtb input.dts。
2.6 三者在启动流程中的角色
从源码到内核启动,DTS/DTB/DTC 的完整链路如下:
- 开发阶段: 开发者编写
.dts和.dtsi(公共头文件)描述硬件。 - 编译阶段: 构建系统调用 DTC 将 DTS 编译为 DTB,通常集成在 Linux 内核的
make dtbs目标中。 - 烧录阶段: DTB 被烧录到存储介质(如 eMMC、NAND Flash)或与内核镜像打包在一起。
- 启动阶段: Bootloader(如 U-Boot)从存储介质加载 DTB 到内存,并将 DTB 地址传递给内核。
- 内核阶段: 内核解析 DTB,根据节点信息注册平台设备、初始化驱动。
2.7 常见问题与避坑指南
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 编译报错“syntax error” | DTS 文件缺少分号或括号不匹配 | 使用 dtc -I dts -O dtb -o /dev/null file.dts 检查语法 |
| 内核启动时“FDT”相关错误 | DTB 与内核版本不匹配或地址传递错误 | 确认 Bootloader 中 fdt_addr 设置正确 |
| 反编译后节点丢失 | DTB 编译时使用了 -@ 选项(保留符号) |
反编译时也使用 -@ 选项 |
| 设备驱动无法匹配 | compatible 字符串拼写错误 | 核对驱动源码中的 of_match_table |
最佳实践: 在项目初期建立
Makefile 自动化编译流程,将 dtc -I dts -O dtb 命令集成到构建脚本中,避免手动编译带来的低级错误。