1. 设备树基础概念
1.1 什么是设备树(Device Tree)
设备树(Device Tree,DT)是一种描述硬件资源的数据结构,它使用树形节点来表述系统中所有可寻址的设备及其连接关系。设备树源文件(.dts)经过设备树编译器(dtc)编译生成二进制设备树(.dtb),在系统启动时由引导加载程序传递给内核。
设备树的核心思想是:将硬件描述从内核代码中剥离出来,使同一份内核二进制能够适配多种硬件平台,而无需重新编译。
关键术语速查表
| 术语 | 全称 | 说明 |
|---|---|---|
| DTS | Device Tree Source | 设备树源文件,人类可读的文本格式 |
| DTB | Device Tree Blob | 编译后的二进制设备树,内核直接使用 |
| DTC | Device Tree Compiler | 将 DTS 编译为 DTB 的工具 |
| DTBO | Device Tree Blob Overlay | 设备树叠加层,用于运行时修改 |
| OF | Open Firmware | 设备树的起源规范,现由 ePAPR 标准继承 |
💡 记忆点:设备树本质上是一个"硬件数据库",内核在启动时读取它来知道"我运行在什么硬件上"。
1.2 为什么需要设备树
在设备树出现之前(Linux 2.6 ~ 3.x 早期),ARM 架构的硬件描述方式存在严重问题:
- 硬编码泛滥:每个板级平台都需要在
arch/arm/mach-xxx下编写大量 C 代码来描述硬件地址、中断号、时钟配置。 - 内核膨胀:同一份内核需要包含所有支持的板级文件,导致内核镜像体积巨大。
- 维护噩梦:新增一款硬件需要修改内核源码,社区维护成本呈指数级增长。
设备树解决了以下核心痛点:
| 痛点 | 设备树方案 |
|---|---|
| 硬件描述与内核代码耦合 | 硬件描述独立为 .dts 文件,内核只读取不硬编码 |
| 多平台内核镜像过大 | 同一内核二进制 + 不同 DTB 即可适配不同硬件 |
| 板级代码重复 | SoC 级 DTSI 可被多个板级 DTS 复用 |
| 外设地址/中断硬编码 | 统一使用 reg、interrupts 属性描述 |
| 启动参数传递混乱 | chosen 节点标准化传递 bootargs、initrd 等 |
⚠️ 历史教训:在 ARM Linux 社区,设备树的引入被称为"ARM 板级代码的清洗运动"。Linus Torvalds 曾公开批评 ARM 内核的板级代码混乱,设备树是解决这一问题的关键举措。
1.3 设备树与 ACPI 的区别
ACPI(Advanced Configuration and Power Interface)是 x86/x86_64 平台使用的硬件描述标准,与设备树在理念上有本质差异:
| 对比维度 | 设备树(Device Tree) | ACPI |
|---|---|---|
| 起源 | Open Firmware(IEEE 1275),PowerPC 平台 | Intel、Microsoft、Toshiba 联合制定 |
| 主要应用平台 | ARM、RISC-V、PowerPC、MIPS | x86、x86_64(PC/服务器) |
| 描述方式 | 静态树形结构,编译为 DTB | AML 字节码 + 表结构,支持运行时解释执行 |
| 运行时能力 | 静态描述,启动后基本不变(Overlay 除外) | 支持热插拔、电源管理、动态配置 |
| 复杂度 | 轻量,语法简单,易于理解 | 庞大复杂,包含大量表格和方法 |
| 内核支持 | 通过 OF 子系统解析 | 通过 ACPI 子系统解析 |
| 适用场景 | 嵌入式、IoT、移动设备 | PC、服务器、工作站 |
| 工具链 | dtc(设备树编译器) | iasl(ACPI 源语言编译器) |
🔑 核心差异总结:
- 设备树 = 静态硬件清单:启动时一次性读取,描述"有什么硬件、在哪里"。
- ACPI = 动态硬件管理层:不仅描述硬件,还包含电源管理、热插拔、设备状态切换等运行时逻辑。
- 在嵌入式领域,设备树是事实标准;在 PC/服务器领域,ACPI 是强制要求。
1.4 设备树在嵌入式 Linux 中的定位
在典型的嵌入式 Linux 启动流程中,设备树扮演着"硬件翻译官"的角色:
- 引导加载程序(U-Boot 等)从存储介质加载 DTB 到内存。
- 引导加载程序根据实际硬件情况修改 DTB(如内存大小、MAC 地址)。
- 内核启动时通过
of_scan_flat_dt()解析 DTB,建立设备模型。 - 驱动匹配通过
of_match_table查找 compatible 属性,完成设备绑定。
📌 调试切入点:当外设无法正常工作时,首先检查 DTB 是否正确传递到内核。可以通过内核日志中的
Machine model: 和 OF: fdt: 信息来验证。