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 内核启动流程中的位置

设备树参与内核启动的关键阶段如下:

  1. Bootloader 阶段:U-Boot 等加载 DTB 到内存,并将 DTB 物理地址通过寄存器(如 ARM 的 r2)传递给内核。
  2. 早期解压与入口:内核解压后,在 start_kernel() 之前调用 setup_arch(),该函数从 DTB 中提取内存大小、命令行参数、机器类型等。
  3. 设备树解析:unflatten_device_tree() 将扁平 DTB 转换为内核可遍历的树形结构 struct device_node。
  4. 驱动初始化:内核遍历设备树节点,匹配 compatible 属性,调用对应驱动程序的 probe() 函数。
  5. 设备注册:驱动通过 platform_device_register() 或 i2c/spi_new_device() 将设备注册到内核总线。
关键函数调用链:
start_kernel() → setup_arch() → early_init_dt_scan() → unflatten_device_tree() → of_platform_populate()
设备树在 Linux 内核启动流程中的位置 设备树在 Linux 内核启动流程中的位置 Bootloader 加载 DTB 到内存 setup_arch() 提取内存/命令行 unflatten_device_tree() DTB → device_node 树 of_platform_populate() 遍历节点 → 匹配驱动 probe() 回调 注册 platform/i2c/spi 设备 说明: • DTB 由 bootloader 通过特定寄存器传递 • 内核在 start_kernel() 之前完成设备树解析

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() 阶段被解析,直接影响内存、外设、驱动的初始化顺序。