一、课程导论:为什么需要设备描述机制?从裸机到操作系统的演进

1.1 裸机时代的“硬编码”噩梦

我刚入行那会儿,做的是基于STM32的裸机项目。那时候写驱动,说白了就是对着芯片手册,把寄存器地址一个个敲进代码里。

比如点亮一个LED,你得这么写:

#define GPIOB_BASE 0x40010C00
#define GPIOB_CRL  (GPIOB_BASE + 0x00)
#define GPIOB_ODR  (GPIOB_BASE + 0x0C)

void led_init(void) {
    *(volatile uint32_t *)GPIOB_CRL = 0x33222222;
    *(volatile uint32_t *)GPIOB_ODR |= (1 << 0);
}

你看,地址是写死的。换一块板子,GPIOB的基地址变了,或者引脚号不同了,就得改代码重新编译。

我印象特别深,有一次给客户做方案,硬件改版了三次。每次改版,我都得熬夜改驱动代码。改到后来,我自己都分不清哪个版本对应哪块板子了。

核心痛点:硬件变化 → 代码重写 → 维护成本爆炸

1.2 操作系统的“统一抽象”需求

后来我开始做Linux驱动开发。Linux要跑在成千上万种硬件上,总不能为每块板子都编译一个独立的内核吧?

你想想看,如果内核里全是这种硬编码:

if (board_type == BOARD_A) {
    uart_base = 0x10000000;
} else if (board_type == BOARD_B) {
    uart_base = 0x20000000;
} else if (...) {
    // 无穷无尽的if-else
}

那内核代码得膨胀成什么样?维护起来简直是灾难。

所以,操作系统需要一种机制——把硬件描述从驱动代码里剥离出来。驱动只关心“怎么操作”,不关心“操作哪个硬件”。

这就是设备描述机制的由来。

1.3 设备描述机制要解决什么问题?

我个人总结,设备描述机制要解决三个核心问题:

  1. 硬件信息与驱动代码解耦——换硬件不改驱动代码
  2. 支持多平台、多板型——同一份内核镜像跑在不同硬件上
  3. 提供标准化的硬件描述语言——让硬件工程师和软件工程师能沟通

举个例子,同样是UART控制器,在A芯片上基地址是0x1000,在B芯片上是0x2000。有了设备描述,驱动代码里只需要写:

struct uart_device *dev = of_device_get_match_data(&pdev->dev);
void __iomem *base = devm_platform_ioremap_resource(pdev, 0);

至于基地址是多少,中断号是多少,统统交给设备描述文件去定义。

我的经验:在项目中,我见过不少团队把设备树当成“万能药”,什么参数都往里塞。其实设备树只描述硬件本身,不描述策略。比如“波特率是多少”是策略,不应该放在设备树里。

1.4 从裸机到操作系统的演进路径

为了让你更直观地理解这个演进过程,我画了一张图:

设备描述机制演进路径 裸机时代 硬编码寄存器地址 简单OS时代 宏定义 + 条件编译 现代OS时代 设备树 / ACPI 各阶段对比 裸机 简单OS 现代OS 地址写死在代码里 用宏定义区分板型 设备树/ACPI描述 换硬件必须改代码 换硬件改宏定义 换硬件改描述文件 无标准化 厂商自定义 IEEE标准/ACPI规范 维护成本极高 维护成本中等 维护成本低

1.5 设备树 vs ACPI:两条技术路线

到了现代操作系统时代,主流的设备描述机制有两条路线:

对比项 设备树 (Device Tree) ACPI
起源 SPARC / PowerPC 架构 x86 架构
主要应用 ARM / RISC-V 嵌入式 x86 / ARM服务器
描述方式 文本文件 (.dts),编译为 .dtb 二进制表 (ASL编译为AML)
运行时修改 支持设备树覆盖 (overlay) 支持动态表加载
复杂度 相对简单 非常复杂
学习曲线 平缓 陡峭

我在项目中两种都接触过。说实话,设备树更符合嵌入式工程师的直觉——一个文本文件,描述硬件连接关系,简单直接。ACPI嘛,嗯,功能确实强大,但光那几百页的规范就够你啃半年的。

避坑指南:我曾经在一个ARM服务器项目里,试图用设备树去描述复杂的电源管理关系。结果发现设备树根本搞不定——它没有ACPI那种定义功耗状态、热区、性能协作的能力。后来老老实实切回了ACPI。所以,选型很重要:嵌入式用设备树,服务器用ACPI,这是行业共识。

1.6 为什么你要学这个课程?

你可能觉得,设备描述机制不就是写写配置文件吗?有什么好学的?

我跟你讲,没那么简单。我在面试中经常问候选人一个问题:

“设备树里interrupt-parent和interrupts这两个属性,到底是怎么关联起来的?”

能答清楚的人,十个里面不到三个。很多人只是照着模板抄,出了问题根本不知道怎么排查。

这个课程,我会带你:

  • 从零开始写设备树文件,而不是复制粘贴
  • 理解ACPI表的生成和加载过程
  • 对比两种机制的优劣,知道什么场景用什么
  • 实战调试——设备树写错了,内核会怎么报错?怎么定位?

说白了,我希望你学完之后,不再是“会用设备树”,而是“懂设备树”。

好,导论就到这里。下一节,我们正式开始设备树的语法学习。


公众号:蓝海资料掘金营,微信deep3321