【设备树笔记整理3】设备树的规范(dts和dtb)

1 dts 文件格式

1.1 DTS文件布局(layout):

cpp 复制代码
/dts-v1/;
[memory reservations] 
/ {
    [property definitions]
    [child nodes]
};

(1)第一行表示当前设备树文件的版本

(2)第二行用来定义保留的内存区域,该区域不给内核使用,例如:

cpp 复制代码
/memresersve/  0x33000000  0x10000

(3)第三行的 "/" 定义根节点

(4)根节点中包含根节点属性(property definitions)和子节点(child nodes)

注意\]: 大括号和属性都要在结尾处加 ";" ### 1.2 节点属性格式 (1)Property格式2(没有值): ```cpp [label:] property-name; ``` (2)Property格式1: ```cpp [label:] property-name = value; ``` (3)Property取值有3种情况: ① arrays of cells(1个或多个32位数据, 64位数据使用2个32位数据表示) 示例1:Arrays of cells : cell就是一个32位的数据 ```cpp interrupts = <17 0xc>; ``` 示例2:64bit数据使用2个cell来表示: ```cpp clock-frequency = <0x00000001 0x00000000>; ``` ② string(字符串) 示例:A null-terminated string (有结束符的字符串): ```cpp compatible = "simple-bus"; ``` ③ bytestring(1个或多个字节) 示例:A bytestring(字节序列) : ```cpp local-mac-address = [00 00 12 34 56 78]; // 每个byte使用2个16进制数来表示 local-mac-address = [000012345678]; // 每个byte使用2个16进制数来表示(空格可以省略) ``` \[补充\]: Property的取值还可以是各种值的组合(该用法不常见), 用逗号隔开: ```cpp compatible = "ns16550", "ns8250"; example = <0xf00f0000 19>, "a strange property format"; ``` ### 1.3 设备节点的格式 Devicetree node格式: ```cpp [label:] node-name[@unit-address] { [properties definitions] [child nodes] }; ``` ### 1.4 特殊的、默认的属性 (1)根结点的属性 ```cpp #address-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address) #size-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) compatible // 定义一系列的字符串, 用来指定内核中哪个machine_desc可以支持本设备 // 即这个板子兼容哪些平台 // uImage : smdk2410 smdk2440 mini2440 ==> machine_desc model // 咱这个板子是什么 // 比如有2款板子配置基本一致, 它们的compatible是一样的 // 那么就通过model来分辨这2款板子 ``` \[补充\]: 关于 #address-cells 和 #size-cells ```cpp / { model = "SMDK24440"; compatible = "samsung,smdk2440"; #address-cells = <1>; #size-cells = <1>; memory@30000000 { device_type = "memory"; reg = <0x30000000 0x4000000>; }; } ``` 由于#address-cells和#size-cells的值都为1,所以上述例子reg的值中0x30000000表示地址,而0x4000000就表示地址的长度。已知#address-cells和#size-cells,reg可以区分多组地址段: ```cpp / { model = "SMDK24440"; compatible = "samsung,smdk2440"; #address-cells = <1>; #size-cells = <1>; memory@30000000 { device_type = "memory"; reg = <0x30000000 0x4000000 0 4096>; }; } ``` 上述例子中的reg表示两组数据,第一组是地址为0x30000000,长度为0x4000000的地址段;而第二组数据是地址为0,长度为4096的地址段。 (2)/memory 结点 ```cpp device_type = "memory"; reg // 用来指定内存的地址、大小 ``` (3)/chosen 结点 ```cpp bootargs // 内核command line参数, 跟u-boot中设置的bootargs作用一样 ``` (4)/cpus 结点 /cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu 所以 /cpus 中有以下2个属性: ```cpp #address-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address) #size-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) // 必须设置为0 ``` (5)/cpus/cpu\* 结点(多个cpu中的每个cpu结点) ```cpp device_type = "cpu"; reg // 表明自己是哪一个cpu ``` ### 1.5 引用其他节点 (1)phandle : // 节点中的phandle属性, 它的取值必须是唯一的(不要跟其他的phandle值一样) ```cpp pic@10000000 { phandle = <1>; interrupt-controller; }; another-device-node { interrupt-parent = <1>; // 使用phandle值为1来引用上述节点 }; ``` (2)label: ```cpp PIC: pic@10000000 { interrupt-controller; }; another-device-node { interrupt-parent = <&PIC>; // 使用label来引用上述节点, // 使用lable时实际上也是使用phandle来引用, // 在编译dts文件为dtb文件时, 编译器dtc会在dtb中插入phandle属性 }; ``` ### 1.6 dtsi 文件 dtsi文件的格式和dts文件的格式一样,可以将公共的部分放到dtsi文件,并让dts文件包含该dtsi文件。在dts中包含dtsi文件的方法: ```cpp #include "jz2440.dtsi" ``` 下面举两个dtsi文件相关的例子: (1)示例1:覆盖结点 ① 文件:jz2440.dtsi ```cpp /dtsi-v1/; / { model = "SMDK24440"; compatible = "samsung,smdk2440"; #address-cells = <1>; #size-cells = <1>; memory@30000000 { device_type = "memory"; reg = <0x30000000 0x4000000>; }; /* cpus { cpu { compatible = "arm,arm926ej-s"; }; }; */ chosen { bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200"; }; led { compatible = "jz2440_led"; reg = <5>; }; }; ``` ② 文件:mytree.dts ```cpp /dts-v1/; #include "jz2440.dtsi" / { led { reg = <6>; }; }; ``` \[说明\]: 在mytree.dts中包含jz2440.dtsi文件,然后按照jz2440.dtsi中led的结点路径,重写led结点,并修改其reg属性为6。这样在最终编译生成的dtb文件中,led的reg属性就为6。也就是说在dts文件中可以覆盖dtsi文件的结点和属性。 (2)示例2:标签引用 ① 文件:jz2440.dtsi ```cpp /dtsi-v1/; / { model = "SMDK24440"; compatible = "samsung,smdk2440"; #address-cells = <1>; #size-cells = <1>; memory@30000000 { device_type = "memory"; reg = <0x30000000 0x4000000>; }; /* cpus { cpu { compatible = "arm,arm926ej-s"; }; }; */ chosen { bootargs = "noinitrd root=/dev/mtdblock4 rw init=/linuxrc console=ttySAC0,115200"; }; LED: led { compatible = "jz2440_led"; reg = <5>; }; }; ``` ② 文件:mytree.dts ```cpp /dts-v1/; #include "jz2440.dtsi" &LED { reg = <5>; }; ``` \[说明\]: 依旧让mytree.dts中包含jz2440.dtsi文件。但是这里通过led结点的标签LED来引用该结点,注意通过标签引用结点时不要从根路径开始写结点,否则会报错。 (3)dtc工具 * dtc其实就是device-tree-compiler,也就是设备树文件dts的编译器。 * dtc可以将dts和dtsi文件编译成dtb二进制文件,也可以将dtb文件反编译成dts文件。 * dtc工具在Linux内核的scripts/dtc目录下,因此需要编译完内核源码后才会生成。 ## 2 dtb 文件格式 ### 2.1 dtb文件的布局 ```cpp ------------------------------ base -> | struct boot_param_header | ------------------------------ | (alignment gap) (*) | ------------------------------ | memory reserve map | ------------------------------ | (alignment gap) | ------------------------------ | | | device-tree structure | | | ------------------------------ | (alignment gap) | ------------------------------ | | | device-tree strings | | | -----> ------------------------------ | | --- (base + totalsize) ``` ### 2.2 dtb二进制文件的分析 ![](https://file.jishuzhan.net/article/1689558386691018754/ef4b11ce3f5441b48e263048a41aa680.png) ![](https://file.jishuzhan.net/article/1689558386691018754/d04df305bbbf49fb9a756f8f4370a338.png) ### 2.3 dtb文件采用大端存储模式 (1)大端存储模式和小端存储模式 ![](https://file.jishuzhan.net/article/1689558386691018754/2391b6639b48420eb1c30daef0376ce9.png) (2)补充 大端模式和小端模式是针对数值存储来说的,字符串存储则没有该规则。例如字符串"ab","b"总是存储在比"a"高的地址中。 ### 2.4 查看二进制文件的工具 * UltraEdit * Free-Hex-Editor-Neo ## 3 参考 (1)官方文档: [Specifications - DeviceTree](https://www.devicetree.org/specifications/ "Specifications - DeviceTree") (2)内核文档1: Documentation/devicetree/usage-model.txt (3)内核文档2: Documentation/devicetree/booting-without-of.txt

相关推荐
小白探索世界欧耶!~8 分钟前
【踩坑】GitHub Actions 运行的 Linux 环境中,文件名是大小写敏感的
linux·运维·服务器·前端·vue.js·笔记·github
lyingcloud10 分钟前
debian系统中文输入法失效解决
linux·运维·debian
whoarethenext26 分钟前
基于libevent写一个服务器(附带源码)
linux·运维·服务器·c++·后端
master cat1 小时前
Ubuntu下载火狐浏览器
linux·ubuntu·腾讯云
zyx没烦恼1 小时前
Linux 多线程
linux·运维·服务器·开发语言·c++
Tanner_SL1 小时前
Linux笔记之Ubuntu系统设置自动登录tty1界面
linux·笔记·ubuntu
落笔太慌张~1 小时前
Linux系统(Ubuntu和树莓派)的远程操作练习
linux·运维·ubuntu
CZIDC1 小时前
Linux系统安全-开发中注意哪些操作系统安全
linux·安全·系统安全
czhc11400756631 小时前
LINUX 5 vim cat zip unzip
linux·编辑器·vim
明灯L2 小时前
《深度剖析 Linux 权限管理:从基础到进阶,解锁系统安全密钥》
linux·运维·全网最全权限管理·小白0基础