1. 设备树概述:起源、作用、与 ACPI 的区别及启动流程位置
1.1 设备树的起源与背景
在早期的 Linux 内核中,板级硬件描述信息(如内存基址、外设寄存器地址、中断号、GPIO 映射等)被直接硬编码在 arch/arm/ 或 arch/powerpc/ 等平台目录下的 board-*.c 文件中。这种“代码即配置”的方式带来了严重的维护问题:
- 代码膨胀:每增加一款开发板,就需要新增或修改大量 C 源码。
- 耦合度高:内核镜像与具体硬件绑定,无法实现通用内核(Generic Kernel)的启动。
- 社区分裂:厂商频繁提交板级补丁,导致主线内核维护成本急剧上升。
为了解决上述问题,设备树(Device Tree) 技术被引入 Linux 内核。它最初源于 Open Firmware(IEEE 1275)的 FDT(Flattened Device Tree)规范,并在 PowerPC 架构上率先大规模使用,随后被 ARM、RISC-V、x86(少数场景)等架构广泛采纳。
核心思想: 将硬件描述从内核源码中剥离,以结构化的树形数据格式(DTS → DTB)传递给内核,实现“硬件描述与内核代码分离”。
1.2 设备树的作用
设备树在 Linux 内核中承担以下关键职责:
| 作用维度 | 具体说明 |
|---|---|
| 硬件拓扑描述 | 定义 CPU、内存、总线、外设的层级关系与地址映射。 |
| 资源参数传递 | 提供寄存器基址、中断号、DMA 通道、时钟频率、GPIO 引脚等关键参数。 |
| 驱动匹配依据 | 通过 compatible 属性将设备节点与内核驱动进行绑定。 |
| 运行时配置 | 支持通过 bootloader 修改 DTB,实现同一内核适配不同硬件变体。 |
| 电源与时钟管理 | 描述设备的电源域、时钟源、复位信号等依赖关系。 |
提示: 设备树是 静态描述,不包含动态硬件枚举逻辑。所有外设必须预先在 DTS 中声明,内核启动时通过 DTB 解析并初始化。
1.3 设备树与 ACPI 的区别
ACPI(Advanced Configuration and Power Interface)是 x86 平台主流的硬件描述标准,与设备树在理念和实现上有显著差异:
| 对比项 | 设备树(DT) | ACPI |
|---|---|---|
| 起源 | Open Firmware / PowerPC | PC/AT 兼容机 + 高级电源管理 |
| 描述语言 | DTS 文本 → DTB 二进制 | ASL 源码 → AML 字节码 |
| 运行时解释 | 内核直接解析 DTB 结构体 | AML 虚拟机解释执行 |
| 动态性 | 静态,启动后一般不修改 | 支持热插拔、动态配置、事件 |
| 适用架构 | ARM、RISC-V、PowerPC、MIPS | x86、x86_64、少量 ARM 服务器 |
| 驱动匹配 | compatible 字符串匹配 |
HID/CID + 命名空间路径 |
| 复杂性 | 简单、扁平、易读 | 庞大、分层、功能丰富 |
注意: 在嵌入式领域,设备树是绝对主流;ACPI 主要用于 PC/服务器。两者不可直接互换,但内核提供了
CONFIG_OF 和 CONFIG_ACPI 编译开关来支持不同平台。
1.4 设备树在 Linux 内核启动流程中的位置
设备树参与内核启动的关键阶段如下:
- Bootloader 阶段:U-Boot 等加载 DTB 到内存,并将 DTB 物理地址通过寄存器(如 ARM 的 r2)传递给内核。
- 早期解压与入口:内核解压后,在
start_kernel()之前调用setup_arch(),该函数从 DTB 中提取内存大小、命令行参数、机器类型等。 - 设备树解析:
unflatten_device_tree()将扁平 DTB 转换为内核可遍历的树形结构struct device_node。 - 驱动初始化:内核遍历设备树节点,匹配
compatible属性,调用对应驱动程序的probe()函数。 - 设备注册:驱动通过
platform_device_register()或i2c/spi_new_device()将设备注册到内核总线。
关键函数调用链:
start_kernel() → setup_arch() → early_init_dt_scan() → unflatten_device_tree() → of_platform_populate()
1.5 设备树文件体系
设备树涉及三种文件格式,它们之间的关系如下:
| 文件类型 | 扩展名 | 格式 | 作用 |
|---|---|---|---|
| DTS | .dts |
文本(可读) | 设备树源文件,开发者编写硬件描述 |
| DTSI | .dtsi |
文本(可读) | 公共头文件,被 #include 到 DTS 中 |
| DTB | .dtb |
二进制(不可读) | DTS 编译后的产物,内核直接使用 |
编译命令:
反编译命令:
dtc -I dts -O dtb -o output.dtb input.dts反编译命令:
dtc -I dtb -O dts -o output.dts input.dtb
1.6 本章小结
- 设备树解决了嵌入式 Linux 板级代码泛滥的问题,实现了硬件描述与内核代码的解耦。
- 设备树通过
compatible属性驱动匹配,是 ARM/RISC-V 平台的标准硬件描述方案。 - 与 ACPI 相比,设备树更轻量、静态、适合嵌入式场景。
- 设备树在内核启动的
setup_arch()阶段被解析,直接影响内存、外设、驱动的初始化顺序。