1. 设备树基础概念

1.1 什么是设备树 (Device Tree)

设备树(Device Tree,简称 DT)是一种描述硬件资源的数据结构,它以树状层次结构将嵌入式系统中的 CPU、内存、外设、中断控制器、GPIO 控制器、时钟、总线等硬件信息组织起来。设备树源文件(.dts)经过设备树编译器(DTC)编译为二进制设备树 Blob(.dtb),在系统启动时由 Bootloader 传递给内核,内核解析该结构后完成设备驱动与硬件资源的绑定。

核心要点:设备树是“硬件拓扑的静态描述文件”,它不包含可执行代码,只描述“有什么硬件、在哪里、怎么配置”。
设备树层次结构示意图 / (根节点) cpus memory soc chosen serial i2c gpio touch sensor 属性示例: compatible = "vendor,device"; reg = <0x10000000 0x1000>; interrupts = <0 33 4>;

1.2 为什么需要设备树

在设备树出现之前,嵌入式 Linux 内核维护着大量 Board File(板级文件),每个开发板都需要在 arch/arm/mach-xxx 下编写数百行 C 代码来注册平台设备、配置资源。这种模式导致内核代码冗余、维护困难,且每次硬件变更都需要重新编译内核。

对比维度 传统 Board File 方式 设备树方式
硬件描述位置 内核源码 arch/arm/mach-xxx 独立 .dts 文件,与内核解耦
硬件变更影响 需修改内核源码并重新编译内核 只需修改 .dts 并重新编译 DTB
多板支持 每个板子一份 mach 文件,代码膨胀 同一内核镜像通过不同 DTB 支持多板
驱动与硬件耦合度 高,驱动中硬编码资源地址 低,驱动通过设备树获取资源
社区维护成本 高,ARM 社区曾因此陷入混乱 低,已成为 ARM/ARM64/RISC-V 标准
关键收益:设备树实现了“内核镜像与硬件描述分离”,同一份 zImage 搭配不同的 .dtb 文件即可启动不同的开发板,极大降低了嵌入式 Linux 的维护成本。
传统 Board File vs 设备树方式对比 传统 Board File 方式 编写 mach-xxx.c 板级文件 注册 platform_device / 资源 重新编译内核镜像 设备树方式 编写 board.dts 设备树源文件 编译为 board.dtb 二进制 Bootloader 加载 DTB 到内存

1.3 设备树与 ACPI 的区别

ACPI(Advanced Configuration and Power Interface)是 x86/x86_64 平台上的硬件资源描述标准,与设备树在理念和实现上有显著差异。下表从多个维度进行对比:

对比维度 设备树 (DT) ACPI
主要应用平台 ARM、ARM64、RISC-V、PowerPC x86、x86_64、IA64
描述语言 DTS 源文件(文本)+ DTB 二进制 ASL(ACPI Source Language)→ AML 字节码
运行时可修改性 启动时由 Bootloader 传递,内核只读解析 支持运行时动态修改(通过 ACPI 方法)
电源管理 弱,需额外驱动支持 强,内置 D-state、C-state、热插拔等
硬件枚举方式 静态树状结构,内核遍历匹配 命名空间 + 控制方法,支持动态枚举
代码体积 轻量,DTB 通常几十 KB 重量级,AML 表可达数 MB
社区生态 嵌入式、物联网、移动设备 服务器、桌面 PC、笔记本
注意:虽然 ARM64 服务器也开始支持 ACPI,但在嵌入式 Linux 领域,设备树仍然是绝对主流。两者在可预见的未来会长期共存,分别服务于不同的硬件生态。
设备树 vs ACPI 架构对比 设备树 (Device Tree) DTS 源文件 (文本) DTC 编译器 DTB 二进制 (~50KB) 内核 OF API 解析 ACPI ASL 源文件 iASL 编译器 AML 表 (~1-5MB) ACPI 解释器 + 命名空间 DT:静态描述,轻量,适合嵌入式 | ACPI:动态方法,重量,适合 PC/服务器

1.4 设备树在 Linux 启动流程中的位置

设备树在系统启动过程中扮演着“硬件信息传递者”的角色,其典型流程如下:

  1. Bootloader 阶段:U-Boot 等 Bootloader 从存储介质(eMMC、NAND、网络)读取 .dtb 文件到内存。
  2. 内核入口:Bootloader 将 DTB 内存地址通过寄存器(如 ARM 的 r2)传递给内核。
  3. 早期解析:内核启动早期调用 unflatten_device_tree() 将 DTB 展开为 device_node 树。
  4. 驱动匹配:总线驱动(如 platform bus)遍历设备树节点,与驱动中的 of_match_table 进行匹配。
  5. 资源获取:驱动通过 of_property_read_* 系列 API 读取寄存器地址、中断号、GPIO 等资源。
一句话总结:设备树是 Bootloader 与内核之间的“硬件配置契约”,它让内核不再关心具体板级细节,只关心“如何解析树状描述”。