Linux设备树到底是啥?一张图看懂硬件适配的「翻译官」

电子说

1.4w人已加入

描述

 

 

你有没有想过:同一份 Linux 内核镜像,为啥能在不同型号的开发板上跑起来?比如一块 ARM 架构的开发板,今天换个显示屏、明天加个传感器,内核不用重新编译就能识别新硬件 —— 这背后,设备树(Devicetree 功不可没。

 

 

很多嵌入式工程师刚接触设备树时,总被节点”“属性”“绑定规范” 这些术语绕晕。其实设备树的本质特别简单:它就是硬件和内核之间的翻译官,把硬件的长相” 和 能力” 写成标准化的文件,让内核不用 硬编码” 就能读懂硬件。

 

 

今天咱们用人话 流程图” 拆解设备树,从 为什么需要它” 到 内核怎么用它,一次讲透核心逻辑。

 

 

一、先搞懂:没有设备树时,Linux 有多 

 

在设备树出现前,Linux 适配硬件靠的是 硬编码”—— 把硬件参数(比如串口地址、中断号)直接写进内核代码里。比如要支持一款新开发板,工程师得:

 

 

1.在内核中新增一个板级文件,写死该板子的所有硬件配置;

 

 

2.编译内核时选择对应板子的配置,生成专属镜像;

 

 

3.要是换个硬件(比如把串口从 UART1 换成 UART2),就得修改代码、重新编译。

 

 

这种方式的痛点太明显了:一款硬件对应一个内核镜像,嵌入式厂商要维护几十上百个镜像,成本极高。

 

 

而设备树的出现,彻底解决了这个问题:它把硬件描述从内核中剥离” 出来,做成独立的 DTB 文件(设备树二进制文件)。内核启动时读取 DTB,就能动态识别硬件 —— 从此实现 一个内核镜像适配 N 种硬件

 

 

二、设备树的核心:层结构,像给硬件画 家谱

 

设备树的结构特别像一棵硬件家谱,最核心的是 个概念:节点(Node属性(Property路径(Path。咱们用一个简单的例子看懂:

 

 

  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
/* 设备树源码(DTS文件)示例 *// {                  // 根节点:代表整个硬件系统    compatible = "ti,omap3-beagleboard""ti,omap3";  // 属性:告诉内核这是哪款硬件        chosen {         // 子节点:专门存储运行时配置        bootargs = "console=ttyS0,115200";  // 属性:内核命令行(指定串口控制台)    };    soc {            // 子节点:代表SoC(系统级芯片)        compatible = "simple-bus";  // 属性:说明这是“简单内存映射总线”                uart0: serial@4806a000 {  // 子节点:串口设备(@后是基地址)            compatible = "ti,omap3-uart";  // 属性:告诉内核用什么驱动            reg = <0x4806a000 0x1000>;     // 属性:地址范围(基地址+大小)            interrupts = <72>;             // 属性:中断号        };    };};

简单理解:

 

 

节点:对应一个硬件模块(如根节点 = 整个系统、uart0 = 串口),用节点名@地址命名(地址可选,用于区分同类型设备);

 

 

属性:描述硬件的具体参数,格式是=(值可以是字符串、数字、二进制),比如compatible设备兼容性标识reg内存 / IO 地址

 

 

路径:像文件路径一样定位节点,比如串口节点的路径是/soc/uart0

 

 

记住一个关键原则:设备树只描述硬件有什么、参数是多少,不包含任何驱动逻辑—— 驱动靠 匹配设备树属性” 来关联硬件。

 

 

三、内核怎么用设备树?步流程 + 1 张图讲透

 

设备树的生命周期从编译” 到 内核使用,分为 个关键阶段。咱们结合流程图,一步步看内核是如何通过设备树识别并控制硬件的。

 

 

第一步:设备树文件的变身(编译阶段)

 

工程师写的是DTS 文件(设备树源码,人类可读),但内核只能识别DTB 文件(设备树二进制,机器可读)。这个转换靠工具dtcDevice Tree Compiler)完成:

 

 

  •  
dtc -I dts -O dtb -o my_board.dtb my_board.dts

最终生成的 DTB 文件,会和内核镜像一起放在开发板的启动分区(比如 boot 分区)。

 

 

第二步:启动时传递 DTB(引导阶段)

 

开发板上电后,先运行引导程序(如 U-Boot,引导程序做两件关键的事:

 

 

1.初始化硬件(比如内存、串口);

 

 

2. DTB 文件加载到内存的指定地址,然后启动内核,并告诉内核 “DTB 在内存的哪里

 

 

这一步就像:引导程序把硬件家谱DTB)递给内核,说 这是你要管理的硬件,先看看说明书

 

 

第三步:内核解析 DTB,创建设备(内核初始化阶段)

 

这是最核心的阶段,内核通过 3 个关键步骤,把 DTB 中的 硬件描述” 变成可操作的 设备实例。咱们用流程图 通俗解释拆解:

 

 

设备树

咱们把每个阶段掰开揉碎讲:

 

 

阶段 1:平台识别 —— 内核先搞清楚 我跑在哪个板子上

 

内核启动后,首先要确定自己跑在什么硬件上(比如是 BeagleBoard 还是树莓派),这一步靠根节点的 compatible 属性

 

 

比如根节点的compatible = "ti,omap3-beagleboard", "ti,omap3",这个属性是从具体到通用” 的列表:

 

 

第一个值“ti,omap3-beagleboard”:精确匹配 “TI 的 omap3 系列 BeagleBoard 开发板

 

 

第二个值“ti,omap3”:兼容 “TI 的 omap3 系列所有板子

 

 

内核会遍历自己的平台描述库,找到和compatible最匹配的项—— 比如找到 BeagleBoard 的初始化逻辑,就执行对应的硬件初始化(如设置时钟、电源)。

 

 

阶段 2:运行时配置 —— 内核获取 启动参数

 

设备树中的/chosen节点是专门给内核传参数的通道,最常用的是bootargs属性(内核命令行)。

 

 

比如bootargs = "console=ttyS0,115200 loglevel=8",意思是:

 

 

console=ttyS0,115200:把串口 0UART0)作为控制台,波特率 115200

 

 

loglevel=8:显示所有级别的内核日志(方便调试)。

 

 

内核会解析这些参数,完成基础配置—— 比如初始化串口控制台,让开发者能通过串口看到内核启动日志。

 

 

阶段 3:创建设备 —— 内核把 硬件描述” 变成 可操作设备

 

这是设备树的最终目的:内核根据 DTB 中的节点,动态创建 设备实例,再让驱动去匹配这些设备。

 

 

关键函数是of_platform_populate(),它的逻辑很简单:

 

 

1.从指定节点(默认是根节点)开始,遍历所有子节点;

 

 

2.对每个包含compatible属性的节点,创建一个平台设备platform_device);

 

 

3.驱动通过of_match_table(设备树匹配表),根据compatible属性找到对应的设备,完成驱动 设备” 绑定。

 

 

举个例子:串口节点uart0compatible = "ti,omap3-uart",内核会:

 

 

创建一个名为serial@4806a000的平台设备;

 

 

串口驱动的of_match_table中,正好有“ti,omap3-uart” 这一项,于是驱动和设备绑定;

 

 

绑定后,驱动就能通过设备树中的reg(地址)、interrupts(中断号),控制串口硬件收发数据。

 

 

四、记住 3 个关键问题,避免踩坑

 

1.设备树能替代驱动吗?

 

 

不能!设备树只描述硬件参数,驱动才是控制硬件的大脑。比如设备树告诉内核 串口在 0x4806a000 地址,但怎么发数据、收数据,还得靠串口驱动实现。

 

 

2.compatible 属性写错了会怎样?

 

 

驱动找不到设备!比如把“ti,omap3-uart” 写成 “ti,omap4-uart”,串口驱动的匹配表中没有这个值,设备就会处于 未绑定” 状态,无法使用。

 

 

3.DTB 文件放错位置会怎样?

 

 

内核启动失败!引导程序如果没加载 DTB,或者内核没找到 DTB,会报 “Cannot find device tree” 错误,然后卡住 —— 因为内核不知道自己要管理什么硬件。

 

 

五、总结:设备树的本质是硬件标准化描述

 

其实设备树的核心价值,就在于标准化

 

 

对硬件厂商:按规范写 DTS,不用改内核代码;

 

 

对内核开发者:按规范写驱动,不用适配每款硬件;

 

 

对嵌入式工程师:换硬件只换 DTB,不用重新编译内核。

 

 

记住一句话:设备树是硬件的说明书,驱动是 读懂说明书并操作硬件的人—— 两者配合,才能让 Linux 在千变万化的硬件上跑起来。

 

 

如果看完还是有点晕,建议找一款简单的开发板,打开它的 DTS 文件,对照本文的流程逐行看:根节点的 compatiblechosen 节点的 bootargs、外设节点的 reg 和 interrupts—— 慢慢就会发现,设备树其实没那么复杂~

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分