1. 设备树基础概念:什么是设备树、为什么需要设备树、设备树与ACPI的对比

1.1 什么是设备树?

设备树,英文叫 Device Tree,是一套描述硬件资源的数据结构。说白了,它就是一份硬件清单,告诉内核:你的板子上有哪些外设、它们挂在哪个总线上、中断号是多少、寄存器地址在哪。

我刚开始接触嵌入式Linux时,总觉得这玩意儿有点多余。那时候我习惯把硬件信息直接写死在代码里,改一个GPIO就要重新编译整个内核。后来有一次,客户临时换了颗Flash芯片,我连夜改代码、编译、烧录,折腾到凌晨三点。嗯,从那以后,我再也不敢把硬件信息写死了。

设备树用文本文件(.dts)描述硬件,通过编译器(dtc)生成二进制文件(.dtb),最终由Bootloader传递给内核。内核解析这个二进制文件,动态创建平台设备,完成驱动与硬件的绑定。

核心要点:设备树是硬件描述与内核代码的解耦层。没有它,换一块板子就得改内核源码;有了它,换板子只需要换一个.dtb文件。

1.2 为什么需要设备树?

在设备树出现之前,ARM Linux社区是怎么做的?每个板子都在 arch/arm/mach-xxx 目录下写一堆 board 文件。这些文件里塞满了 GPIO 编号、时钟配置、内存映射……代码量巨大,而且重复。

举个例子,TI 的 OMAP 平台,光是 board 文件就有几十个。每个文件几百行,大部分代码都是复制粘贴。维护起来简直是噩梦。我记得有一次,一个同事改了一个 board 文件里的 I2C 总线号,结果另一个板子莫名其妙挂了——因为两个板子共用了同一个结构体,改了一个影响了一片。

设备树解决了三个核心问题:

  • 硬件描述标准化:用统一的语法描述硬件,不再依赖C语言结构体。
  • 内核与硬件解耦:同一份内核镜像可以支持多个板子,只要更换.dtb文件。
  • 社区统一:PowerPC、ARM、RISC-V 等架构都采用设备树,减少了碎片化。

我的经验:在项目早期就定义好设备树节点,哪怕有些外设还没调通。这样后期加硬件时,只需要改.dts文件,不用动内核源码。我曾经在一个项目里,靠这个习惯把硬件适配周期从两周压缩到了两天。

1.3 设备树与ACPI的对比

ACPI(高级配置与电源管理接口)是x86平台上的硬件描述标准。它和设备树虽然目标相似,但设计哲学完全不同。我最早做x86 BIOS开发时,天天跟ACPI表打交道,后来转到嵌入式ARM,看到设备树的第一反应是:这玩意儿怎么这么简单?

下面这张图展示了设备树与ACPI在系统启动流程中的位置差异:

设备树与ACPI启动流程对比 设备树 vs ACPI 启动流程对比 设备树(ARM/嵌入式) Bootloader 加载 .dtb 内核解析设备树节点 动态创建 platform_device 驱动匹配并 probe ACPI(x86/服务器) BIOS/UEFI 生成 ACPI 表 内核解析 DSDT/SSDT 表 ACPI 驱动枚举设备 驱动匹配并 probe 设备树:静态文本 → 二进制 → 内核解析,流程简单,适合嵌入式 ACPI:BIOS 运行时生成表,支持热插拔、电源管理,功能更复杂

两者的核心差异,我整理了一张对比表:

对比维度 设备树 ACPI
起源 PowerPC(Open Firmware) x86(PC/服务器)
描述方式 文本文件(.dts)→ 二进制(.dtb) AML字节码(DSDT/SSDT表)
运行时修改 不支持(需重新编译) 支持(通过UEFI运行时表)
电源管理 弱(依赖驱动实现) 强(内置C状态、P状态)
热插拔 不支持原生热插拔 原生支持PCIe热插拔
适用场景 嵌入式、ARM、RISC-V x86、服务器、笔记本
复杂度 低(学习成本低) 高(需要理解AML语言)

避坑指南:我曾经在一个项目里试图用设备树实现PCIe热插拔,折腾了两周发现根本行不通。设备树的设计初衷就是静态描述,别指望它能做ACPI的事情。反过来,在ARM服务器上强行上ACPI,也会因为缺少BIOS支持而寸步难行。选型时一定要搞清楚你的硬件平台和生态。

1.4 什么时候用设备树,什么时候用ACPI?

这个问题其实没有绝对答案。我个人的经验是:

  • 嵌入式Linux(ARM、RISC-V、MIPS):无脑选设备树。生态成熟,工具链完善,社区支持好。
  • x86嵌入式(如Intel Atom、AMD嵌入式):看BIOS支持。如果BIOS支持ACPI,优先用ACPI;如果BIOS很简陋(比如某些工控板),可以用设备树。
  • ARM服务器:现在趋势是ACPI。因为服务器需要热插拔、电源管理、NUMA感知,这些是设备树的短板。
  • 混合架构:有些SoC同时支持设备树和ACPI(比如某些ARM+FPGA平台)。这时候需要根据启动方式动态选择。

我的建议:如果你刚开始做嵌入式Linux,从设备树入手。它简单、直观,调试起来也方便。等你把设备树玩熟了,再去看ACPI,你会发现很多概念是相通的——都是硬件抽象,只是抽象层次不同。

1.5 本章小结

设备树是嵌入式Linux的基石。它把硬件描述从内核代码中剥离出来,让同一份内核镜像可以适配不同的板子。ACPI虽然功能更强大,但复杂度也更高,不适合资源受限的嵌入式场景。

记住一句话:设备树解决的是「硬件是什么」的问题,ACPI解决的是「硬件怎么用」的问题。两者没有优劣之分,只有适用场景的不同。