1. 设备树基础概念:什么是设备树、为什么需要设备树、设备树在Linux内核中的角色
1.1 什么是设备树?一个很直白的解释
设备树,英文叫 Device Tree,缩写是 DT。说白了,它就是一份描述硬件信息的“清单”。
你想想看,一块板卡上有什么CPU、什么外设、中断怎么连、GPIO接在哪个引脚上——这些信息总得有个地方告诉内核吧?设备树就是干这个的。
我习惯把它比作“硬件的身份证”。内核启动时,通过读取这份身份证,就知道自己跑在什么硬件上,该初始化哪些驱动。
设备树的本质:一种描述硬件资源的数据结构,以树形层级组织,从根节点往下展开,每个节点代表一个硬件设备或总线。
设备树的源文件是 .dts(Device Tree Source),编译后生成 .dtb(Device Tree Blob),内核直接加载 .dtb 来识别硬件。
1.2 为什么需要设备树?—— 一段历史故事
在设备树出现之前,Linux 内核是怎么知道硬件信息的?
答案是:硬编码。每个板卡都在内核源码里写一堆 arch/arm/mach-xxx 的板级文件。那时候,每换一块板子,就得重新编译内核。
我记得刚入行那会儿,公司有七八块不同的 ARM 板卡。每次内核升级,光维护这些板级文件就够头疼的。更别提新加一块板卡,得复制粘贴一大段代码,稍不留神就改出问题。
为什么会这样?因为内核和硬件信息是“紧耦合”的。换硬件就得改内核源码,这显然不科学。
设备树解决了这个问题:
- 解耦硬件描述与内核代码 —— 硬件信息从内核源码里抽出来,放到独立的
.dts文件中 - 同一内核镜像支持多块板卡 —— 启动时加载不同的
.dtb即可 - 社区统一标准 —— ARM、RISC-V、PowerPC 都用同一套描述方式
我的经验:早期项目里,一块板卡从原型到量产,硬件改过三次引脚分配。如果没有设备树,每次改硬件都得重新编译内核。有了设备树,改改 .dts 文件,重新编译一下,几分钟搞定。这效率提升,谁用谁知道。
1.3 设备树在Linux内核中的角色
设备树在内核启动过程中扮演什么角色?我画了一张图,你看完就明白了。
从这张图可以看到,设备树在内核启动中贯穿了好几个阶段:
- Bootloader 加载 .dtb —— 把编译好的设备树二进制文件放到内存指定位置
- 内核早期解析 —— 内核启动时,从内存中读取设备树,建立设备模型
- 驱动匹配 —— 驱动通过
compatible属性与设备树节点匹配 - 资源分配 —— 中断号、寄存器地址、时钟频率等信息从设备树中获取
- 设备初始化 —— 匹配成功后,调用驱动的
probe函数 - 用户空间可见 —— 通过
/sys/firmware/devicetree可以查看设备树内容
我曾经踩过的坑:有一次调试一块新板卡,内核死活起不来。查了两天,最后发现是 Bootloader 传给内核的设备树地址不对。内核拿到的是乱码,自然解析失败。所以,设备树地址传递是第一个要确认的点。
1.4 设备树的核心数据结构
设备树的结构其实很简单,就是一棵树。每个节点有属性,属性有值。
看一个最简单的例子:
/dts-v1/;
/ {
model = "MyBoard";
compatible = "vendor,myboard";
cpu@0 {
compatible = "arm,cortex-a7";
reg = <0x00>;
};
serial@1c00000 {
compatible = "ns16550";
reg = <0x01c00000 0x1000>;
interrupts = <0 12 4>;
};
};
这里有几个关键概念:
| 概念 | 说明 | 示例 |
|---|---|---|
| 根节点 | 用 / 表示,整棵树的起点 |
/ { ... }; |
| 节点 | 每个硬件设备或总线 | cpu@0, serial@1c00000 |
| 属性 | 描述节点的特征 | compatible, reg, interrupts |
| compatible | 驱动匹配的关键字段 | "arm,cortex-a7" |
| reg | 地址和大小信息 | <0x01c00000 0x1000> |
我的习惯:写设备树时,我一般先画一张硬件框图,把CPU、总线、外设的层级关系理清楚。然后再动手写 .dts。这样不容易漏节点,也不会搞错父子关系。
1.5 设备树与驱动的“握手”过程
设备树和驱动是怎么配合的?我简单说一下流程:
- 驱动里声明一个
of_device_id表,里面写上支持的compatible字符串 - 内核启动时,遍历设备树的所有节点
- 对每个节点,查找是否有驱动注册了对应的
compatible - 匹配成功,调用驱动的
probe函数 - 驱动在
probe里通过of_系列 API 读取设备树中的资源信息
说白了,设备树就是驱动和硬件之间的“翻译官”。驱动不需要知道硬件具体怎么接的,只需要从设备树里读配置就行。
一句话总结:设备树让硬件描述与内核代码分离,让同一份内核镜像可以适配多块板卡。这是嵌入式 Linux 从“单板定制”走向“多板统一”的关键一步。
嗯,这一章的内容就到这里。设备树的概念虽然简单,但它是后面所有章节的基础。你把这个根扎稳了,后面讲多板卡统一管理、设备树复用、overlay 这些高级话题时,就不会觉得吃力。