1、设备树基础概念:什么是设备树、为什么需要设备树、设备树与ACPI的区别
1.1 什么是设备树?
设备树,英文叫 Device Tree,是一套描述硬件资源的数据结构。
说白了,它就是一份「硬件清单」。CPU 有几个核、内存多大、外设挂在哪里、中断怎么连……这些信息都写在一个文本文件里。内核启动时读这个文件,就知道自己跑在什么板子上了。
我个人习惯把设备树理解成「硬件的身份证」。没有它,内核就得靠一堆杂乱无章的板级文件来猜硬件配置——那场面,想想就头疼。
设备树的文件后缀通常是 .dts(源文件)或 .dtb(编译后的二进制)。你写一个 .dts,然后用 dtc 工具编译成 .dtb,内核在启动时解析它。
核心要点:设备树把硬件描述和内核代码分开了。换一块板子,改改 .dts 就行,不用重新编译内核。
1.2 为什么需要设备树?
这个问题,得从 Linux 内核的历史说起。
早期 Linux 内核里,每个 ARM 板子都有自己的 board-xxx.c 文件。这些文件里写满了硬件的初始化代码。你想想看,几百块板子,就有几百个这样的文件。内核维护者光是合并这些代码就快疯了。
我在项目中遇到过一件事:公司同时维护三款硬件平台,每款平台的外设地址都不一样。每次升级内核版本,都要手动改一堆 board 文件,改完还得反复测试。有一次漏改了一个 GPIO 的配置,整块板子点不亮,排查了两天才找到原因。
设备树就是为了解决这个痛点而生的。它把硬件描述从内核代码里抽离出来,变成一份独立的数据文件。好处很明显:
- 代码复用性高——同一份内核镜像,换不同的 .dtb 就能适配不同板子
- 维护成本低——改硬件配置不用动内核源码
- 社区统一——所有 ARM 平台都用同一套描述语言,不再各自为政
嗯,这里要注意:设备树不是 Linux 独有的。U-Boot、FreeBSD 等系统也支持它。它已经成了嵌入式领域的事实标准。
1.3 设备树与 ACPI 的区别
ACPI(Advanced Configuration and Power Interface)是 x86 平台上的硬件描述标准。很多从 x86 转过来做嵌入式的朋友,一开始容易把两者搞混。
我简单列个对比表,你一看就明白了:
| 对比项 | 设备树 (DT) | ACPI |
|---|---|---|
| 主要平台 | ARM、RISC-V、PowerPC | x86、x86_64 |
| 描述方式 | 文本文件 (.dts),编译为二进制 (.dtb) | AML 字节码,存放在 BIOS 中 |
| 运行时解析 | 内核直接解析 .dtb | 由 ACPI 驱动解析 AML 字节码 |
| 动态性 | 静态描述,运行时一般不修改 | 支持热插拔、电源管理等动态行为 |
| 复杂度 | 相对简单,学习曲线平缓 | 非常复杂,规范文档上千页 |
| 适用场景 | 嵌入式、IoT、单板计算机 | 服务器、PC、笔记本 |
为什么会这样?其实跟历史有关。x86 平台硬件高度标准化,BIOS/UEFI 负责枚举硬件,ACPI 负责描述电源管理和热插拔。而 ARM 平台千奇百怪,没有统一的固件标准,设备树就成了最轻量的解决方案。
我的建议:如果你做的是嵌入式 Linux 开发,专心学设备树就够了。ACPI 那套东西,等你哪天做服务器固件开发时再碰也不迟。
1.4 避坑指南
我曾经踩过的一个坑:刚开始用设备树时,我以为 .dts 文件里写的地址就是物理地址,直接拿来就用。结果发现某些平台有地址映射偏移,设备树里写的是总线地址,不是 CPU 看到的物理地址。后来查了芯片手册才搞清楚。
所以,拿到一块新板子,第一件事就是确认:设备树里的地址是总线地址还是物理地址?不同平台规则不一样。
另外,设备树不是万能的。它只描述硬件「有什么」,不描述硬件「怎么用」。驱动的行为逻辑还是得写在 C 代码里。别指望靠改几行 .dts 就能让一个外设跑起来——驱动代码才是灵魂。
1.5 小结
设备树是嵌入式 Linux 开发者的基本功。它把硬件描述从内核代码中解放出来,让同一份内核可以适配多种硬件平台。与 ACPI 相比,它更轻量、更简单、更适合嵌入式场景。
下一章,我会带你手写一个最简单的 .dts 文件,看看设备树到底长什么样。到时候你就知道,这东西其实没那么神秘。