Home 设备树简介
Post
Cancel

设备树简介

设备树介绍

设备树机制最初是Open Firmware固件接口标准的一部分,即Open Firmware Device Tree,是由Open Firmware创建的, 现在一般简称Devicetree (DT)。从概念上讲,它定义了一组通用的用法约定,称为“bindings”,用于定义数据在树中的展现方式, 以展现具体的硬件特征,如数据总线、中断线、GPIO 连接和外围设备。后来,因为一些原因,又进一步创建了 Flattened Device Tree (FDT),它可以作为二进制的blob传递给内核,而并不依赖Open Firmware,相当于是独立出来了。 现在的一些引导程序如U-Boot都支持传递设备树二进制文件(dtb),最初是在PowerPC上发展的,后来在很多CPU架构上都推广开了。

Open Firmware是一套计算机固件的接口标准,起源于Sun Microsystems,最初被称为OpenBoot, 定位上相当于开源的BIOS,但BIOS是没有标准化的,这个Open Firmware是有标准化定义的。 Open Firmware有使用在PowerPC,Sun,IBM,还有ARM中。

设备树只是一个描述硬件的数据结构,它提供了一种描述语言,用于将硬件配置和Linux内核中的驱动程序分离。根据传递到内核的数据结构 (dtb,device tree blob)来加载对应驱动,即让设备支持成为数据驱动的,而不是每台机器的硬编码。通过数据驱动的方式, 内核中的平台设置可以减少代码重复,更轻松地使用单个内核映像支持多种硬件。虽然设备树只是一种描述语言,但是内核中肯定还有 相关的设备树相关代码,来设置和解析设备树,匹配驱动等。这样,内核才是真正支持设备树,arm架构的设备树支持大约是3.10版本的内核 开始支持的。

设备树的三个主要目的:

  1. platform identification
  2. runtime configuration
  3. device population

Platform Identification

平台标识,即指示硬件平台名称。在设备树中,在最外层使用 compatible属性表示,属性包含一个以机器的确切名称开头的字符串排序列表, 后跟一个可选的兼容板列表,从最兼容到最不兼容。字符串的匹配是完全匹配的方式。示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
/ {
        model = "Xunlong Orange Pi PC";
        compatible = "xunlong,orangepi-pc", "allwinner,sun8i-h3";
        
        ...
};

/ {
        model = "V2P-CA9";
        compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";

        ...
};

如果一个平台有了一些改动或升级,即使改动很小,那么,这时的设备树肯定会发生一点变化。尽管原本的设备树大部分的都能兼容新版的机器,但是, 在逻辑上就是两个机器平台,所以设备树要求你应当建立一个新的设备树文件来具体匹配更新后的机器,尽管这两个版本可能针对很相似。不过,实际实现中 一般都可通过代码包含来避免代码重复等问题,比如:sun8i-h3-orangepi-pc.dtssun8i-h3-orangepi-pc-plus.dts,这两个开发板 是比较相近的,后者是前者的升级,具体实现中,后者其实没有重写,而是先 include 了前者,然后在对一些改动的地方进行 override 重写 覆盖。在逻辑上,就很合理的实现了两个机器平台的设备树,既有共性,又有特性。通常一个系列相关的都会这么实现,公共部分加覆盖部分。

runtime configuration

由于设备树的基本机制是将数据传递到内核,因此,它也被用于传递运行时和配置数据,例如内核启动参数 和 initrd 映像的位置等。 这类运行时配置都包含在 /chosen节点中。示例:

1
2
3
4
5
6
7
8
9
10
11
12
chosen {
        bootargs = "console=ttyS0,115200 loglevel=8";
        initrd-start = <0xc8000000>;
        initrd-end = <0xc8200000>;
};

// xilinx zynqmp

chosen {
                bootargs = "earlycon clk_ignore_unused";
                stdout-path = "serial0:115200n8";
};

不过,需要注意,在设备树中使用 chosen 指定的启动参数,优先级没有命令行传递的高,如果有在命令行传递了内核启动参数,这里的chosen里的启动参数 会被忽略。这个设备树里面传递的运行时配置是在kernel启动时,初始化配置设备树时解析的。

device population

设备生成,设备树本身是描述硬件的结构语言,而内核中一般使用C语言结构体来表示硬件,所以内核处理设备树时,会解析设备树节点,并将其转换为内核中 的设备结构体,这样就实现了设备树节点到内核中设备结构体的转换,内核就“获得”了相对应设备硬件细节。

因为设备树中并不是只有设备描述节点,也有其他辅助节点。通常,带 ”compatible“属性的一般就是设备了,如果是在设备树的根部, 内核会分配并注册一个platform_device,如果是挂在某总线上,内核就分配并注册一个符合对应总线的设备结构体,如PCI,I2C,SPI,USB等。

工具

dtc,dtc工具即 device tree compiler,可以用来编译和反编译设备树文件。可以手动安装

1
2
3
sudo apt install device-tree-compiler

dtc -h  # 查看帮助

一般,在内核源码目录中会自带一个,在 kernel_src_path/scripts/dtc/dtc,是一样使用的。

设备树规范

设备树源文件中的一些节点名称规范,一些标准属性等,都可以参考 devicetree-specification-v0.4-rc1.pdf

如基本的标准属性,compatible,model,phandle,status,#address-cells and #size-cells,reg,ranges等等,都可以参考该pdf。

参考

Open Firmware and Devicetree
DeviceTree Kernel API
Device Tree Usage
Devicetree Specification

This post is licensed under CC BY 4.0 by the author.