1. 设备树基础概念
1.1 设备树的起源与历史背景
设备树(Device Tree,DT)是一种描述硬件资源的数据结构,最早源于 Open Firmware(IEEE 1275)规范。在嵌入式 Linux 早期(2.4 ~ 2.6 内核时代),ARM、PowerPC、MIPS 等架构的板级硬件描述大量依赖 board-*.c 和 mach-*.c 文件,每个开发板都需要在内核源码中硬编码物理地址、中断号、时钟频率等信息。这种模式导致内核源码树中充斥着大量重复、难以维护的板级代码。
2011 年,Linux 内核主线正式引入 Flattened Device Tree(FDT),将硬件描述从内核源码中剥离,形成独立的 .dts / .dtsi 文件。这一变革使得同一份内核镜像可以支持多个硬件平台,只需更换设备树二进制(.dtb)即可适配不同板卡。
1.2 设备树的核心作用
设备树在嵌入式 Linux 启动流程中扮演 硬件拓扑描述者 和 资源清单提供者 的双重角色。其核心作用可归纳为以下四点:
| 作用维度 | 具体说明 | 典型示例 |
|---|---|---|
| 硬件枚举 | 描述 CPU、内存、外设控制器、总线拓扑等所有可编程硬件节点 | cpus { cpu@0 { ... } } |
| 资源分配 | 定义寄存器地址范围、中断号、DMA 通道、时钟频率等资源 | reg = <0x1c00000 0x1000> |
| 驱动绑定 | 通过 compatible 属性将设备节点与内核驱动匹配 |
compatible = "ti,am335x-uart" |
| 配置解耦 | 将引脚复用、时钟频率、电压等级等板级参数从内核源码中分离 | pinctrl-0 = &uart0_pins |
1.3 设备树与 ACPI 的对比
ACPI(Advanced Configuration and Power Interface)是 x86 和 ARM64 服务器领域的主流硬件描述标准,与设备树在理念和实现上有显著差异:
| 对比维度 | 设备树(DT) | ACPI |
|---|---|---|
| 起源 | Open Firmware / 嵌入式社区 | PC / 服务器工业标准 |
| 数据格式 | 文本(.dts)→ 二进制(.dtb) | ASL 源码 → AML 字节码 |
| 运行时解析 | Bootloader 加载 .dtb 到内存,内核直接解析 | BIOS/UEFI 提供 ACPI 表,内核通过 AML 解释器解析 |
| 动态性 | 静态描述,运行时可通过 overlay 扩展 | 支持热插拔、电源状态动态协商 |
| 适用场景 | 嵌入式、IoT、消费电子、ARM SoC | x86 服务器、桌面、ARM64 服务器 |
| 驱动匹配方式 | compatible 字符串匹配 |
HID/CID + 设备 ID 匹配 |
| 社区生态 | Linux 内核主线 + 设备树规范 | UEFI 论坛 + 微软/Intel 主导 |
1.4 设备树在嵌入式 Linux 中的核心地位
在当前的嵌入式 Linux 生态中,设备树已经从一个可选组件演变为 事实上的硬件描述标准。其核心地位体现在以下三个层面:
- 启动流程的必经环节: 从 Bootloader(U-Boot、TF-A)到内核启动,设备树是传递硬件信息的唯一通道。没有有效的 .dtb,内核无法完成内存映射、中断控制器初始化、时钟树建立等基础操作。
- 驱动开发的契约接口: 设备树节点中的
compatible、reg、interrupts、clocks等属性构成了驱动与硬件之间的“契约”。驱动开发者只需按照设备树绑定文档编写驱动,即可适配任意符合该描述的硬件。 - 产品迭代的配置中心: 同一 SoC 的不同产品变体(如不同内存容量、不同外设组合)只需修改 .dts 文件,无需改动内核源码。设备树 overlay 机制还支持运行时动态加载,满足模块化产品的需求。
1.5 设备树文件体系与编译流程
设备树源文件采用 文本 → 二进制 的编译模型,整个文件体系包含以下类型:
| 文件后缀 | 全称 | 作用 | 示例 |
|---|---|---|---|
.dts |
Device Tree Source | 顶层设备树源文件,描述具体板卡的硬件 | imx6ull-evk.dts |
.dtsi |
Device Tree Source Include | 公共头文件,描述 SoC 通用部分或模块复用部分 | imx6ull.dtsi |
.dtb |
Device Tree Blob | 编译后的二进制文件,供 Bootloader 加载 | imx6ull-evk.dtb |
.dtbo |
Device Tree Blob Overlay | 设备树覆盖层,用于运行时动态添加/修改节点 | mcp2515-can0.dtbo |
编译命令示例:
# 将 .dts 编译为 .dtb
dtc -I dts -O dtb -o imx6ull-evk.dtb imx6ull-evk.dts
# 反编译 .dtb 为可读的 .dts
dtc -I dtb -O dts -o imx6ull-evk-decompiled.dts imx6ull-evk.dtb
# 编译设备树覆盖层
dtc -I dts -O dtb -@ -o mcp2515-can0.dtbo mcp2515-can0.dts
arch/<arch>/boot/dts/ 目录下。编译内核时,make dtbs 命令会递归编译所有 .dts 文件,生成对应的 .dtb。建议在开发阶段使用 dtc -I dtb -O dts 反编译验证生成的 .dtb 是否符合预期。
1.6 本章小结
设备树是嵌入式 Linux 从“硬编码时代”迈向“配置驱动时代”的关键技术。它通过标准化的树形数据结构,将硬件描述与内核源码解耦,使得驱动开发、板级适配、产品迭代的效率得到数量级提升。理解设备树的起源、作用、与 ACPI 的差异以及其在启动流程中的核心地位,是掌握后续设备树语法、绑定编写、驱动集成技巧的基石。