1. 设备树基础概念
1.1 什么是设备树 (Device Tree)
设备树(Device Tree,简称 DT)是一种描述硬件资源的数据结构,它以树状层次结构将嵌入式系统中的 CPU、内存、外设、中断控制器、GPIO 控制器、时钟、总线等硬件信息组织起来。设备树源文件(.dts)经过设备树编译器(DTC)编译为二进制设备树 Blob(.dtb),在系统启动时由 Bootloader 传递给内核,内核解析该结构后完成设备驱动与硬件资源的绑定。
核心要点:设备树是“硬件拓扑的静态描述文件”,它不包含可执行代码,只描述“有什么硬件、在哪里、怎么配置”。
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 的维护成本。
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 领域,设备树仍然是绝对主流。两者在可预见的未来会长期共存,分别服务于不同的硬件生态。
1.4 设备树在 Linux 启动流程中的位置
设备树在系统启动过程中扮演着“硬件信息传递者”的角色,其典型流程如下:
- Bootloader 阶段:U-Boot 等 Bootloader 从存储介质(eMMC、NAND、网络)读取
.dtb文件到内存。 - 内核入口:Bootloader 将 DTB 内存地址通过寄存器(如 ARM 的
r2)传递给内核。 - 早期解析:内核启动早期调用
unflatten_device_tree()将 DTB 展开为device_node树。 - 驱动匹配:总线驱动(如 platform bus)遍历设备树节点,与驱动中的
of_match_table进行匹配。 - 资源获取:驱动通过
of_property_read_*系列 API 读取寄存器地址、中断号、GPIO 等资源。
一句话总结:设备树是 Bootloader 与内核之间的“硬件配置契约”,它让内核不再关心具体板级细节,只关心“如何解析树状描述”。