搜索
首页系统教程LINUXLinux设备树dts移植:如何描述和传递硬件配置信息

Linux设备树dts移植:如何描述和传递硬件配置信息

Feb 13, 2024 am 11:27 AM
linuxlinux教程linux系统linux命令外壳脚本嵌入式linuxlinux入门linux学习

在Linux系统中,设备树是一种描述硬件配置的树形数据结构,它起源于Open Firmware标准,用于提供操作系统软件和硬件之间的接口,启动和运行系统。设备树可以减少内核为支持新硬件而需要的改变,提高代码重用,加速Linux支持包的开发,使得单个内核镜像能支持多个系统。本文将介绍Linux设备树dts移植的基本步骤和方法,包括设备树的数据存储格式、源码描述语法、U-Boot和Linux内核对设备树的支持和解析过程等。

Linux设备树dts移植:如何描述和传递硬件配置信息

关键词:扁平设备树; DTS; PowerPC; Linux

IBM、Sun 等厂家的服务器最初都采用了Firmware(一种嵌入到硬件设备中的程序,用
于提供软件和硬件之间的接口),用于初始化系统配置,提供操作系统软件和硬件之间的接
口,启动和运行系统。后来为了标准化和兼容性,IBM、Sun 等联合推出了固件接口IEEE 1275
标准,让他们的服务器如IBM PowerPC pSeries,Apple PowerPC,Sun SPARC 等均采用Open
Firmware,在运行时构建系统硬件的设备树信息传递给内核,进行系统的启动运行[1]。这样
做的好处有,减少内核对系统硬件的严重依赖,利于加速支持包的开发,降低硬件带来的变
化需求和成本,降低对内核设计和编译的要求。

随着 Linux/ppc64 内核的发展,内核代码从原来的arch/ppc32 和arch/ppc64 逐渐迁移到
统一的arch/powerpc 目录,并在内核代码引入Open Firmware API 以使用标准固件接口[2]。
Linux 内核在运行时,需要知道硬件的一些相关信息。对于使用ARCH=powerpc 参数编译的
内核镜像,这个信息需要基于Open Firmware 规范,以设备树的形式存在[3]。这样内核在启
动时读取扫描Open Firmware 提供的设备树,从而获得平台的硬件设备信息,搜索匹配的设
备驱动程序并将该驱动程序绑定到设备。

在嵌入式 PowerPC 中,一般使用U-Boot 之类的系统引导代码,而不采用Open Firmware。
早期的U-Boot 使用include/asm-ppc/u-boot.h 中的静态数据结构struct bd_t 将板子基本信息传
递给内核,其余的由内核处理。这样的接口不够灵活,硬件发生变化就需要重新定制编译烧
写引导代码和内核,而且也不再适应于现在的内核。为了适应内核的发展及嵌入式PowerPC
平台的千变万化,吸收标准Open Firmware 的优点,U-Boot 引入了扁平设备树FDT 这样的
动态接口,使用一个单独的FDT blob(二进制大对象,是一个可以存储二进制文件的容器)
存储传递给内核的参数[3]。一些确定信息,例如cache 大小、中断路由等直接由设备树提供,
而其他的信息,例如eTSEC 的MAC 地址、频率、PCI 总线数目等由U-Boot 在运行时修改。
U-Boot 使用扁平设备树取代了bd_t,而且也不再保证对bd_t 的后向兼容。

2 设备树概念
简单的说,设备树是一种描述硬件配置的树形数据结构,有且仅有一个根节点[4]。它包
含了有关CPU、物理内存、总线、串口、PHY 以及其他外围设备信息等。该树继承了Open
Firmware IEEE 1275 设备树的定义。操作系统能够在启动时对此结构进行语法分析,以此配
置内核,加载相应的驱动。

3 设备树存储格式
U-Boot 需要将设备树在内存中的存储地址传给内核。该树主要由三大部分组成:头
(Header)、结构块(Structure block)、字符串块(Strings block)。设备树在内存中的存
储布局图1 如下:
图1 设备树存储格式图
Fig1 The layout of a DT block

3.1 头(header)
头主要描述设备树的基本信息,如设备树魔数标志、设备树块大小、结构块的偏移地址
等,其具体结构boot_param_header 如下。这个结构中的值都是以大端模式表示,并且偏移
地址是相对于设备树头的起始地址计算的。

3.2 结构块(structure block)
扁平设备树结构块是线性化的树形结构,和字符串块一起组成了设备树的主体,以节点
形式保存目标板的设备信息。在结构块中,节点起始标志为常值宏OF_DT_BEGIN_NODE,
节点结束标志为宏OF_DT_END_NODE;子节点定义在节点结束标志前。一个节点可以概
括为以OF_DT_BEGIN_NODE 开始,包括节点路径、属性列表、子节点列表,最后以
OF_DT_END_NODE 结束的序列,每一个子节点自身也是类似的结构。

3.3 字符串块(Strings block)
为了节省空间,将一些属性名,尤其是那些重复冗余出现的属性名,提取出来单独存放
到字符串块。这个块中包含了很多有结束标志的属性名字符串。在设备树的结构块中存储了
这些字符串的偏移地址,这样可以很容易地查找到属性名字符串。字符串块的引入节省了嵌
入式系统较为紧张的存储空间。

4 设备树源码DTS 表示
设备树源码文件(.dts)以可读可编辑的文本形式描述系统硬件配置设备树,支持C/C++
方式的注释,该结构有一个唯一的根节点“/”,每个节点都有自己的名字并可以包含多个
子节点。设备树的数据格式遵循了Open Firmware IEEE standard 1275。本文只简述设备树的
数据布局及语法,Linux 板级支持包开发者应该详细参考IEEE 1275 标准[5]及其他文献[2] [4]。
为了说明,首先给出基于PowerPC MPC8349E 处理器的最小系统的设备树源码示例。
可以看到,这个设备树中有很多节点,每个节点都指定了节点单元名称。每一个属性后面都
给出相应的值。以双引号引出的内容为ASCII 字符串,以尖括号给出的是32 位的16 进制
值。这个树结构是启动Linux 内核所需节点和属性简化后的集合,包括了根节点的基本模式
信息、CPU 和物理内存布局,它还包括通过/chosen 节点传递给内核的命令行参数信息。

/ {
model = "MPC8349EMITX";
compatible = "MPC8349EMITX", "MPC834xMITX", "MPC83xxMITX";
\#address-cells = ; /* 32bit address */
\#size-cells = ; /* 4GB size */
cpus {
\#address-cells = ;
\#size-cells = ;
PowerPC,8349@0 {
device_type = "cpu";
reg = ;
d-cache-line-size = ; /* 32 Bytes */
i-cache-line-size = ;
d-cache-size = ; /* L1 dcache, 32K */
i-cache-size = ;
timebase-frequency = ; /* from bootloader */
bus-frequency = ;
clock-frequency = ;
};
};
memory {
device_type = "memory";
reg = ; /* 256MB */
};
chosen {
name = "chosen";
bootargs = "root=/dev/ram rw console=ttyS0,115200";
linux,stdout-path = "/soc8349@e0000000/serial@4500";
};
};

4.1 根节点
设备树的起始点称之为根节点”/”。属性model 指明了目标板平台或模块的名称,属性
compatible 值指明和目标板为同一系列的兼容的开发板名称。对于大多数32 位平台,属性
#address-cells 和#size-cells 的值一般为1。

4.2 CPU 节点
/cpus 节点是根节点的子节点,对于系统中的每一个CPU,都有相应的节点。/cpus 节点
没有必须指明的属性,但指明#address-cells = 和 #size-cells = 是个好习惯,这同时指
明了每个CPU 节点的reg 属性格式,方便为物理CPU 编号。

此节点应包含板上每个CPU 的属性。CPU 名称一般写作PowerPC,,例如
Freescale 会使用PowerPC,8349 来描述本文的MPC8349E 处理器。CPU 节点的单元名应该是
cpu@0 的格式,此节点一般要指定device_type(固定为”cpu”),一级数据/指令缓存的表项
大小,一级数据/指令缓存的大小,核心、总线时钟频率等。在上面的示例中通过系统引导
代码动态填写时钟频率相关项。

4.3 系统内存节点
此节点用于描述目标板上物理内存范围,一般称作/memory 节点,可以有一个或多个。
当有多个节点时,需要后跟单元地址予以区分;只有一个单元地址时,可以不写单元地址,
默认为0。

此节点包含板上物理内存的属性,一般要指定device_type(固定为”memory”)和reg
属性。其中reg 的属性值以的形式给出,如上示例中目标板内存起始
地址为0,大小为256M 字节。

4.4 /chosen 节点
这个节点有一点特殊。通常,这里由Open Firmware 存放可变的环境信息,例如参数,
默认输入输出设备。
这个节点中一般指定bootargs 及linux,stdout-path 属性值。bootargs 属性设置为传递给内
核命令行的参数字符串。linux,stdout-path 常常为标准终端设备的节点路径名,内核会以此作
为默认终端。

U-Boot 在1.3.0 版本后添加了对扁平设备树FDT 的支持,U-Boot 加载Linux 内核、
Ramdisk 文件系统(如果使用的话)和设备树二进制镜像到物理内存之后,在启动执行Linux
内核之前,它会修改设备树二进制文件。它会填充必要的信息到设备树中,例如MAC 地址、
PCI 总线数目等。U-Boot 也会填写设备树文件中的“/chosen”节点,包含了诸如串口、根
设备(Ramdisk、硬盘或NFS 启动)等相关信息。

4.5 片上系统SOC 节点
此节点用来描述片上系统SOC,如果处理器是SOC,则此节点必须存在。顶级SOC 节
点包含的信息对此SOC 上的所有设备可见。节点名应该包含此SOC 的单元地址,即此SOC
内存映射寄存器的基址。SOC 节点名以/soc的形式命名,例如MPC8349 的SOC
节点是”soc8349″。

在属性中应该指定device_type(固定为”soc”)、ranges、bus-frequency 等属性。ranges
属性值以的形式指定。SOC 节点还包含目标板使用的每个
SOC 设备子节点,应该在设备树中尽可能详细地描述此SOC 上的外围设备。如下给出带有
看门狗设备的SOC 节点DTS 示例。

soc8349@e0000000 {
\#address-cells = ;
\#size-cells = ;
device_type = "soc";
compatible = "simple-bus";
ranges = ; /* size 1MB */
reg = ;
bus-frequency = ; /* from bootloader */
{
device_type = "watchdog";
compatible = "mpc83xx_wdt";
reg = ; /* offset: 0x200 */
};
};

4.6 其他设备节点
分级节点用来描述系统上的总线和设备,类似物理总线拓扑,能很方便的描述设备间的
关系。对于系统上的每个总线和设备,在设备树中都有其节点。对于这些设备属性的描述和
定义请详细参考IEEE 1275 标准及本文参考文献[2]。

设备树的中断系统稍显复杂,设备节点利用interrupt-parent 和interrupts 属性描述到中
断控制器的中断连接。其中interrupt-parent 属性值为中断控制器节点的指针,#interrupts 属
性值描述可触发的中断信号,其值格式与中断控制器的interrupt-cells 属性值有关。一般
#interrupt-cells 属性值为2,interrupts 属性就对应为一对描述硬件中断号和中断触发方式的
十六进制值。

5 扁平设备树编译
根据嵌入式板的设备信息写设备树源码文件(.dts)通常比较简单,但是手写二进制的
扁平设备树(.dtb)就显得比较复杂了。设备树编译器dtc 就是用来根据设备树源码的文本
文件生成设备树二进制镜像的。dtc 编译器会对输入文件进行语法和语义检查,并根据Linux
内核的要求检查各节点及属性,将设备树源码文件(.dts)编译二进制文件(.dtb),以保证
内核能正常启动。dtc 编译器的使用方法如下所示[6]:
dtc [ -I dts ] [ -O dtb ] [ -o opt_file ] [ -V opt_version ] ipt_file
2.6.25 版本之后的内核源码已经包含了dtc 编译器。在配置编译内核时选中
CONFIG_DTC,会自动生成设备树编译器dtc。将编写的目标板设备树文件mpc8349emitx.dts
放到内核源码的arch/powerpc/boot/dts/目录下,利用内核Makefile 生成blob 的简单规则,使
用以下命令亦可完成设备树的dtc 编译:
$ make mpc8349emitx.dtb

6 U-Boot 相关设置说明
为使 U-Boot 支持设备树,需要在板子配置头文件中设置一系列宏变量。如本文在

MPC8349E 处理器目标板中移植的U-Boot 配置如下:
/* pass open firmware flat tree */
\#define CONFIG_OF_LIBFDT 1
\#undef CONFIG_OF_FLAT_TREE
\#define CONFIG_OF_BOARD_SETUP 1
\#define CONFIG_OF_HAS_BD_T 1
\#define CONFIG_OF_HAS_UBOOT_ENV 1
启动引导代码U-Boot 在完成自己的工作之后,会加载Linux 内核,并将扁平设备树的
地址传递给内核,其代码形式如下:
\#if defined(CONFIG_OF_FLAT_TREE) || defined(CONFIG_OF_LIBFDT)
if (of_flat_tree) { /* device tree; boot new style */
/*
\* Linux Kernel Parameters (passing device tree):
\* r3: pointer to the fdt, followed by the board info data
\* r4: physical pointer to the kernel itself
\* r5: NULL
\* r6: NULL
\* r7: NULL
*/
(*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0);
/* does not return */
}
\#endif

arch/powerpc 内核的入口有且只有一个,入口点为内核镜像的起始。此入口支持两种调
用方式,一种是支持Open Firmware 启动,另一种对于没有OF 的引导代码,需要使用扁平
设备树块,如上示例代码。寄存器r3 保存指向设备树的物理地址指针,寄存器r4 保存为内
核在物理内存中的地址,r5 为NULL。其中的隐含意思为:假设开启了mmu,那么这个mmu
的映射关系是1:1 的映射,即虚拟地址和物理地址是相同的。

7 Linux 内核对设备树的解析
扁平设备树描述了目标板平台中的设备树信息。每个设备都有一个节点来描述其信息,
每个节点又可以有子节点及其相应的属性。内核源码中include/linux/of.h 及drivers/of/base.c
等文件中提供了一些Open Firmware API,通过这些API,内核及设备驱动可以查找到相应
的设备节点,读取其属性值,利用这些信息正确地初始化和驱动硬件。

图2 内核及驱动对扁平设备树的解析
Fig2 Interaction from kernel and drivers with the FDT blob

8 结论
通过本文,你应该对Linux设备树dts移植有了一个基本的了解,它是一种描述和传递硬件配置信息的有效方式,可以适应嵌入式Linux系统的多样化需求。当然,设备树也不是一成不变的,它需要根据具体的硬件平台和内核版本进行定制和修改。总之,设备树是Linux系统中不可或缺的一个组件,值得你深入学习和掌握。

以上是Linux设备树dts移植:如何描述和传递硬件配置信息的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:良许Linux教程网。如有侵权,请联系admin@php.cn删除
比较和对比Linux和Windows的安全模型。比较和对比Linux和Windows的安全模型。Apr 24, 2025 am 12:03 AM

Linux和Windows的安全模型各有优势。Linux提供灵活性和可定制性,通过用户权限、文件系统权限和SELinux/AppArmor实现安全。Windows则注重用户友好性,依赖WindowsDefender、UAC、防火墙和BitLocker保障安全。

Linux和Windows之间的硬件兼容性有何不同?Linux和Windows之间的硬件兼容性有何不同?Apr 23, 2025 am 12:15 AM

Linux和Windows在硬件兼容性上不同:Windows有广泛的驱动程序支持,Linux依赖社区和厂商。解决Linux兼容性问题可通过手动编译驱动,如克隆RTL8188EU驱动仓库、编译和安装;Windows用户需管理驱动程序以优化性能。

Linux和Windows之间虚拟化支持有哪些差异?Linux和Windows之间虚拟化支持有哪些差异?Apr 22, 2025 pm 06:09 PM

Linux和Windows在虚拟化支持上的主要区别在于:1)Linux提供KVM和Xen,性能和灵活性突出,适合高定制环境;2)Windows通过Hyper-V支持虚拟化,界面友好,与Microsoft生态系统紧密集成,适合依赖Microsoft软件的企业。

Linux系统管理员的主要任务是什么?Linux系统管理员的主要任务是什么?Apr 19, 2025 am 12:23 AM

Linux系统管理员的主要任务包括系统监控与性能调优、用户管理、软件包管理、安全管理与备份、故障排查与解决、性能优化与最佳实践。1.使用top、htop等工具监控系统性能,并进行调优。2.通过useradd等命令管理用户账户和权限。3.利用apt、yum管理软件包,确保系统更新和安全。4.配置防火墙、监控日志、进行数据备份以确保系统安全。5.通过日志分析和工具使用进行故障排查和解决。6.优化内核参数和应用配置,遵循最佳实践提升系统性能和稳定性。

很难学习Linux吗?很难学习Linux吗?Apr 18, 2025 am 12:23 AM

学习Linux并不难。1.Linux是一个开源操作系统,基于Unix,广泛应用于服务器、嵌入式系统和个人电脑。2.理解文件系统和权限管理是关键,文件系统是层次化的,权限包括读、写和执行。3.包管理系统如apt和dnf使得软件管理方便。4.进程管理通过ps和top命令实现。5.从基本命令如mkdir、cd、touch和nano开始学习,再尝试高级用法如shell脚本和文本处理。6.常见错误如权限问题可以通过sudo和chmod解决。7.性能优化建议包括使用htop监控资源、清理不必要文件和使用sy

Linux管理员的薪水是多少?Linux管理员的薪水是多少?Apr 17, 2025 am 12:24 AM

Linux管理员的平均年薪在美国为75,000至95,000美元,欧洲为40,000至60,000欧元。提升薪资可以通过:1.持续学习新技术,如云计算和容器技术;2.积累项目经验并建立Portfolio;3.建立职业网络,拓展人脉。

Linux的主要目的是什么?Linux的主要目的是什么?Apr 16, 2025 am 12:19 AM

Linux的主要用途包括:1.服务器操作系统,2.嵌入式系统,3.桌面操作系统,4.开发和测试环境。Linux在这些领域表现出色,提供了稳定性、安全性和高效的开发工具。

互联网在Linux上运行吗?互联网在Linux上运行吗?Apr 14, 2025 am 12:03 AM

互联网运行不依赖单一操作系统,但Linux在其中扮演重要角色。Linux广泛应用于服务器和网络设备,因其稳定性、安全性和可扩展性受欢迎。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中