一、什么是设备树(Device Tree)
它是一种描述硬件资源的数据结构,可以通过 bootloader 将它传给内核,内核(Kernal)使用它对硬件进行初始化,好处是使得内核和硬件资源描述相对独立,不需要太多的硬编码。
二、设备树的相关名词
DTS(Device Tree Source):.dts文件是一种ASCII文本对Device Tree的描述,位于linux-x.xx/arch/arm64/boot/dts目录下。
DTC(Device Tree Compiler):DTC为编译工具,它可以将.dts文件编译成.dtb 文件,DTC 的源码位于 linux-x.xx/scripts/dtc目录下。
DTB(Device Tree Blob):DTC编译.dts 生成的二进制文件(.dtb)(实际上是字节码),bootloader 在加载内核时,也会同时把.dtb加载到内存,后面传递给内核使用。
三、DTS 文件格式
/** Device Tree Source for OMAP2 SoC** Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/** This file is licensed under the terms of the GNU General Public License* version 2. This program is licensed "as is" without any warranty of any* kind, whether express or implied.*//include/ "skeleton.dtsi" /*需要引用的dts*// {compatible = "ti,omap2430", "ti,omap2420", "ti,omap2";aliases {serial0 = &uart1;serial1 = &uart2;serial2 = &uart3;};cpus {cpu@0 {compatible = "arm,arm1136jf-s";};};soc {compatible = "ti,omap-infra";mpu {compatible = "ti,omap2-mpu";ti,hwmods = "mpu";};};ocp {compatible = "simple-bus";#address-cells = <1>;#size-cells = <1>;ranges;ti,hwmods = "l3_main";intc: interrupt-controller@1 {compatible = "ti,omap2-intc";interrupt-controller;#interrupt-cells = <1>;};uart1: serial@4806a000 {compatible = "ti,omap2-uart";ti,hwmods = "uart1";clock-frequency = <48000000>;};uart2: serial@4806c000 {compatible = "ti,omap2-uart";ti,hwmods = "uart2";clock-frequency = <48000000>;};uart3: serial@4806e000 {compatible = "ti,omap2-uart";ti,hwmods = "uart3";clock-frequency = <48000000>;};};};
“/“ 为 root 节点,在一个. dts 文件中,有且仅有一个 root 节点,/include/ "skeleton.dtsi"和C代码中的 include 头文件的作用差不多,也就是把/include/ "skeleton.dtsi"定义的 device tree 节点包含到 omap2.dtsi 中,虽然omap2.dtsi文件中也会有一个 “/“,但是 dtc 编译时,会把它们合并成一个。
/** Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License version 2 as* published by the Free Software Foundation.*//dts-v1/; /*dts的版本*//include/ "omap4.dtsi" /*需要引用的dts*// {model = "TI OMAP4 PandaBoard";compatible = "ti,omap4-panda", "ti,omap4430", "ti,omap4";memory {device_type = "memory";reg = <0x80000000 0x40000000>; /* 1 GB */};};
1)aliases node
aliases {serial0 = &uart0;serial1 = &uart1;serial2 = &uart2;};
aliases 节点定义了一些别名。为何要定义这个 node 呢?因为 Device tree 是树状结构,当要引用一个 node 的时候要指明相对于 root node 的 full path。例如
uart1: serial@4806a000 {compatible = "ti,omap2-uart";ti,hwmods = "uart1";clock-frequency = <48000000>;};
serial1 = &uart1 所以 serial1就是 serial@4806a000 的一个别名,uart1是一个 lable,也是 serial@4806a000,使用 lable 需要在前面加上 & 。例如
&uart1 {status = "okay";};
就是把serial@4806a000节点里面的 status 属性改成 okay
2)memory node
memory {device_type = "memory";reg = <0x80000000 0x40000000>; /* 1 GB */};
对于 memory node,device_type 必须为 memory,memory device node 是所有设备树文件的必备节点,它定义了系统物理内存的 layout。
reg 描述了 memory-mapped IO register 的 offset 和 length。对于 memory node,定义了该 memory 的起始地址和长度,这里的0x80000000是起始地址,0x40000000是内存的大小(长度)。
#address-cells = <1>;#size-cells = <1>;
为什么是 0 0x40000000 表示起始地址,因为 root 节点 #address-cells = <2>; 表示用两个 cell (32 位),同样的 #size-cells = <2> 表示用两个 cell (32 位)。
每个 node 用节点名字(node name)标识,节点名字的格式是 node-name@unit-address。如果该 node 没有 reg 属性,那么该节点名字中必须不能包括 @和 unit-address。unit-address 的具体格式是和设备挂在那个 bus 上相关。
所以上面 memory 的描述是,起始地址是 0x 80000000
3)chosen node
34 chosen {35 stdout-path = "serial0:921600n8";36 };
chosen node 主要用来描述由系统指定的 runtime parameter,它并没有描述任何硬件设备节点信息。原先通过 tag list 传递的一些 linux kernel 运行的参数,可以通过 chosen 节点来传递。如 command line 可以通过 bootargs 这个 property 来传递。如果存在 chosen node,它的 parent 节点必须为 “/” 根节点。
四、DTB文件格式
1、dtb文件结构


2、fdt_header
struct fdt_header {uint32_t magic; /* magic word FDT_MAGIC */uint32_t totalsize; /* total size of DT block */uint32_t off_dt_struct; /* offset to structure */uint32_t off_dt_strings; /* offset to strings */uint32_t off_mem_rsvmap; /* offset to memory reserve map */uint32_t version; /* format version */uint32_t last_comp_version; /* last compatible version *//* version 2 fields below */uint32_t boot_cpuid_phys; /* Which physical CPU id we'rebooting on *//* version 3 fields below */uint32_t size_dt_strings; /* size of the strings block *//* version 17 fields below */uint32_t size_dt_struct; /* size of the structure block */};
off_dt_struct 是到dt_struct 结构块的偏移量(相对于文件起始位置),off_dt_strings 是到dt_strings字符串块的偏移量(相对于文件起始位置),off_mem_rsvmap 是到memory reserve map 区域的偏移量(相对于文件起始位置)。头部一共40字节,即off_mem_rsvmap 的值为40。
3、memory reserve map
该区域保存的数据会4字节对齐
4、dt_struct
结构块里面保存了dts 里面描述的设备信息,和dts 里面写的内容一致,只不过转成了另一种数据格式。节点的开始和结束,属性的开始用下面定义的标识。
#define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */#define FDT_TAGSIZE sizeof(uint32_t)#define FDT_BEGIN_NODE 0x1 /* Start node: full name */#define FDT_END_NODE 0x2 /* End node */#define FDT_PROP 0x3 /* Property: content_size, name off(in_dt_string), content */#define FDT_NOP 0x4 /* nop */#define FDT_END 0x9
5、off_dt_strings
字符串块 保存的是dts中属性的名字,因为在不同的节点中会用到相同的属性名,为了减少保存重复的属性名字符串,所以把它们放在字符串块中,每个字符串是以\0为结束标识。
6、dtb文件生成与查看
使用dtc工具将dts转为dtb,命令如下:
mate@Vostro:~/Documents/.../arch/arm/boot/dts$ dtc -I dts omap4-panda.dts -O dtb -o omap4-panda.dtb#或mate@Vostro:~/Documents/.../arch/arm/boot/dts$ dtc -I dts -O dtb omap4-panda.dts -o omap4-panda.dtb
使用二进制文件查看工具hexdump查看编译后的dtb文件,如下:
mate@Vostro:~/Documents/linux-A3352W-4G-SPI-CAN-GPIO-IIC_20210622/linux-A3352W-4G-SPI-CAN-GPIO-IIC/arch/arm/boot/dts$ hexdump -C omap4-panda.dtb00000000 d0 0d fe ed 00 00 06 3c 00 00 00 48 00 00 05 80 |.......<...H....|00000010 00 00 00 28 00 00 00 11 00 00 00 10 00 00 00 00 |...(............|00000020 00 00 00 bc 00 00 05 38 00 00 00 00 9d 00 00 00 |.......8........|00000030 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|00000040 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 |................|00000050 00 00 00 03 00 00 00 04 00 00 00 00 00 00 00 01 |................|00000060 00 00 00 03 00 00 00 04 00 00 00 0f 00 00 00 01 |................|00000070 00 00 00 03 00 00 00 24 00 00 00 1b 74 69 2c 6f |.......$....ti,o|00000080 6d 61 70 34 2d 70 61 6e 64 61 00 74 69 2c 6f 6d |map4-panda.ti,om|00000090 61 70 34 34 33 30 00 74 69 2c 6f 6d 61 70 34 00 |ap4430.ti,omap4.|000000a0 00 00 00 03 00 00 00 04 00 00 00 26 00 00 00 01 |...........&....|000000b0 00 00 00 03 00 00 00 14 00 00 00 37 54 49 20 4f |...........7TI O|000000c0 4d 41 50 34 20 50 61 6e 64 61 42 6f 61 72 64 00 |MAP4 PandaBoard.|000000d0 00 00 00 01 63 68 6f 73 65 6e 00 00 00 00 00 02 |....chosen......|000000e0 00 00 00 01 61 6c 69 61 73 65 73 00 00 00 00 03 |....aliases.....|000000f0 00 00 00 17 00 00 00 3d 2f 6f 63 70 2f 73 65 72 |.......=/ocp/ser|00000100 69 61 6c 40 30 78 34 38 30 36 61 30 30 30 00 00 |ial@0x4806a000..|00000110 00 00 00 03 00 00 00 17 00 00 00 45 2f 6f 63 70 |...........E/ocp|00000120 2f 73 65 72 69 61 6c 40 30 78 34 38 30 36 63 30 |/serial@0x4806c0|00000130 30 30 00 00 00 00 00 03 00 00 00 17 00 00 00 4d |00.............M|00000140 2f 6f 63 70 2f 73 65 72 69 61 6c 40 30 78 34 38 |/ocp/serial@0x48|00000150 30 32 30 30 30 30 00 00 00 00 00 03 00 00 00 17 |020000..........|00000160 00 00 00 55 2f 6f 63 70 2f 73 65 72 69 61 6c 40 |...U/ocp/serial@|00000170 30 78 34 38 30 36 65 30 30 30 00 00 00 00 00 02 |0x4806e000......|00000180 00 00 00 01 6d 65 6d 6f 72 79 00 00 00 00 00 03 |....memory......|00000190 00 00 00 07 00 00 00 5d 6d 65 6d 6f 72 79 00 00 |.......]memory..|000001a0 00 00 00 03 00 00 00 08 00 00 00 69 80 00 00 00 |...........i....|000001b0 40 00 00 00 00 00 00 02 00 00 00 01 63 70 75 73 |@...........cpus|000001c0 00 00 00 00 00 00 00 01 63 70 75 40 30 00 00 00 |........cpu@0...|000001d0 00 00 00 03 00 00 00 0e 00 00 00 1b 61 72 6d 2c |............arm,|000001e0 63 6f 72 74 65 78 2d 61 39 00 00 00 00 00 00 02 |cortex-a9.......|000001f0 00 00 00 01 63 70 75 40 31 00 00 00 00 00 00 03 |....cpu@1.......|00000200 00 00 00 0e 00 00 00 1b 61 72 6d 2c 63 6f 72 74 |........arm,cort|00000210 65 78 2d 61 39 00 00 00 00 00 00 02 00 00 00 02 |ex-a9...........|00000220 00 00 00 01 73 6f 63 00 00 00 00 03 00 00 00 0e |....soc.........|00000230 00 00 00 1b 74 69 2c 6f 6d 61 70 2d 69 6e 66 72 |....ti,omap-infr|00000240 61 00 00 00 00 00 00 01 6d 70 75 00 00 00 00 03 |a.......mpu.....|00000250 00 00 00 0d 00 00 00 1b 74 69 2c 6f 6d 61 70 34 |........ti,omap4|00000260 2d 6d 70 75 00 00 00 00 00 00 00 03 00 00 00 04 |-mpu............|00000270 00 00 00 6d 6d 70 75 00 00 00 00 02 00 00 00 01 |...mmpu.........|00000280 64 73 70 00 00 00 00 03 00 00 00 0d 00 00 00 1b |dsp.............|00000290 74 69 2c 6f 6d 61 70 33 2d 63 36 34 00 00 00 00 |ti,omap3-c64....|000002a0 00 00 00 03 00 00 00 04 00 00 00 6d 64 73 70 00 |...........mdsp.|000002b0 00 00 00 02 00 00 00 01 69 76 61 00 00 00 00 03 |........iva.....|000002c0 00 00 00 09 00 00 00 1b 74 69 2c 69 76 61 68 64 |........ti,ivahd|000002d0 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00 6d |...............m|000002e0 69 76 61 00 00 00 00 02 00 00 00 02 00 00 00 01 |iva.............|000002f0 6f 63 70 00 00 00 00 03 00 00 00 1b 00 00 00 1b |ocp.............|00000300 74 69 2c 6f 6d 61 70 34 2d 6c 33 2d 6e 6f 63 00 |ti,omap4-l3-noc.|00000310 73 69 6d 70 6c 65 2d 62 75 73 00 00 00 00 00 03 |simple-bus......|00000320 00 00 00 04 00 00 00 00 00 00 00 01 00 00 00 03 |................|00000330 00 00 00 04 00 00 00 0f 00 00 00 01 00 00 00 03 |................|00000340 00 00 00 00 00 00 00 77 00 00 00 03 00 00 00 1e |.......w........|00000350 00 00 00 6d 6c 33 5f 6d 61 69 6e 5f 31 00 6c 33 |...ml3_main_1.l3|00000360 5f 6d 61 69 6e 5f 32 00 6c 33 5f 6d 61 69 6e 5f |_main_2.l3_main_|00000370 33 00 00 00 00 00 00 01 69 6e 74 65 72 72 75 70 |3.......interrup|00000380 74 2d 63 6f 6e 74 72 6f 6c 6c 65 72 40 34 38 32 |t-controller@482|00000390 34 31 30 30 30 00 00 00 00 00 00 03 00 00 00 12 |41000...........|000003a0 00 00 00 1b 61 72 6d 2c 63 6f 72 74 65 78 2d 61 |....arm,cortex-a|000003b0 39 2d 67 69 63 00 00 00 00 00 00 03 00 00 00 00 |9-gic...........|000003c0 00 00 00 7e 00 00 00 03 00 00 00 04 00 00 00 93 |...~............|000003d0 00 00 00 01 00 00 00 03 00 00 00 10 00 00 00 69 |...............i|000003e0 48 24 10 00 00 00 10 00 48 24 01 00 00 00 01 00 |H$......H$......|000003f0 00 00 00 03 00 00 00 04 00 00 00 a4 00 00 00 01 |................|00000400 00 00 00 02 00 00 00 01 73 65 72 69 61 6c 40 30 |........serial@0|00000410 78 34 38 30 36 61 30 30 30 00 00 00 00 00 00 03 |x4806a000.......|00000420 00 00 00 0e 00 00 00 1b 74 69 2c 6f 6d 61 70 34 |........ti,omap4|00000430 2d 75 61 72 74 00 00 00 00 00 00 03 00 00 00 06 |-uart...........|00000440 00 00 00 6d 75 61 72 74 31 00 00 00 00 00 00 03 |...muart1.......|00000450 00 00 00 04 00 00 00 ac 02 dc 6c 00 00 00 00 02 |..........l.....|00000460 00 00 00 01 73 65 72 69 61 6c 40 30 78 34 38 30 |....serial@0x480|00000470 36 63 30 30 30 00 00 00 00 00 00 03 00 00 00 0e |6c000...........|00000480 00 00 00 1b 74 69 2c 6f 6d 61 70 34 2d 75 61 72 |....ti,omap4-uar|00000490 74 00 00 00 00 00 00 03 00 00 00 06 00 00 00 6d |t..............m|000004a0 75 61 72 74 32 00 00 00 00 00 00 03 00 00 00 04 |uart2...........|000004b0 00 00 00 ac 02 dc 6c 00 00 00 00 02 00 00 00 01 |......l.........|000004c0 73 65 72 69 61 6c 40 30 78 34 38 30 32 30 30 30 |serial@0x4802000|000004d0 30 00 00 00 00 00 00 03 00 00 00 0e 00 00 00 1b |0...............|000004e0 74 69 2c 6f 6d 61 70 34 2d 75 61 72 74 00 00 00 |ti,omap4-uart...|000004f0 00 00 00 03 00 00 00 06 00 00 00 6d 75 61 72 74 |...........muart|00000500 33 00 00 00 00 00 00 03 00 00 00 04 00 00 00 ac |3...............|00000510 02 dc 6c 00 00 00 00 02 00 00 00 01 73 65 72 69 |..l.........seri|00000520 61 6c 40 30 78 34 38 30 36 65 30 30 30 00 00 00 |al@0x4806e000...|00000530 00 00 00 03 00 00 00 0e 00 00 00 1b 74 69 2c 6f |............ti,o|00000540 6d 61 70 34 2d 75 61 72 74 00 00 00 00 00 00 03 |map4-uart.......|00000550 00 00 00 06 00 00 00 6d 75 61 72 74 34 00 00 00 |.......muart4...|00000560 00 00 00 03 00 00 00 04 00 00 00 ac 02 dc 6c 00 |..............l.|00000570 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 09 |................|00000580 23 61 64 64 72 65 73 73 2d 63 65 6c 6c 73 00 23 |#address-cells.#|00000590 73 69 7a 65 2d 63 65 6c 6c 73 00 63 6f 6d 70 61 |size-cells.compa|000005a0 74 69 62 6c 65 00 69 6e 74 65 72 72 75 70 74 2d |tible.interrupt-|000005b0 70 61 72 65 6e 74 00 6d 6f 64 65 6c 00 73 65 72 |parent.model.ser|000005c0 69 61 6c 30 00 73 65 72 69 61 6c 31 00 73 65 72 |ial0.serial1.ser|000005d0 69 61 6c 32 00 73 65 72 69 61 6c 33 00 64 65 76 |ial2.serial3.dev|000005e0 69 63 65 5f 74 79 70 65 00 72 65 67 00 74 69 2c |ice_type.reg.ti,|000005f0 68 77 6d 6f 64 73 00 72 61 6e 67 65 73 00 69 6e |hwmods.ranges.in|00000600 74 65 72 72 75 70 74 2d 63 6f 6e 74 72 6f 6c 6c |terrupt-controll|00000610 65 72 00 23 69 6e 74 65 72 72 75 70 74 2d 63 65 |er.#interrupt-ce|00000620 6c 6c 73 00 70 68 61 6e 64 6c 65 00 63 6c 6f 63 |lls.phandle.cloc|00000630 6b 2d 66 72 65 71 75 65 6e 63 79 00 |k-frequency.|0000063c
五、实例分析(根据dtb文件结构)
1、fdt_header
struct fdt_header {uint32_t magic; /* magic word FDT_MAGIC */uint32_t totalsize; /* total size of DT block */uint32_t off_dt_struct; /* offset to structure */uint32_t off_dt_strings; /* offset to strings */uint32_t off_mem_rsvmap; /* offset to memory reserve map */uint32_t version; /* format version */uint32_t last_comp_version; /* last compatible version *//* version 2 fields below */uint32_t boot_cpuid_phys; /* Which physical CPU id we'rebooting on *//* version 3 fields below */uint32_t size_dt_strings; /* size of the strings block *//* version 17 fields below */uint32_t size_dt_struct; /* size of the structure block */};
00000000 d0 0d fe ed 00 00 06 3c 00 00 00 48 00 00 05 80/*magic_num*/ /*total = 1596*/ /*off_struct = 72*/ /*off_str = 1408*/00000010 00 00 00 28 00 00 00 11 00 00 00 10 00 00 00 00/*off_rsvmap = 40*/ /*version = 17*/ /*last_comp = 16*/ /*boot_cpuid = 0*/00000020 00 00 00 bc 00 00 05 38/*size_str = 188*/ /*size_dt_struct = 1336*/
2、memory reserve map
00000020 ----------------------- 00 00 00 00 9d 00 00 00 |.......8........|00000030 00 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |................|00000040 00 00 00 00 00 00 00 00
3、dt_struct
(节点、属性等四字节对齐)
①:标志一个节点的开始(0x01,四字节对齐);
②:节点的名称(memory,四字节对齐);
③:标志一个属性的开始;
④:属性内容的长度(sizeof(“memory”) = 7);
⑤:属性名称在dt_string中的偏移量(偏移93字节:device_type);
⑥:属性的内容(memory,四字节对齐);
⑦:标志节点的结束(0x02,四字节对齐)。
#define FDT_BEGIN_NODE 0x1 /* Start node: full name */#define FDT_END_NODE 0x2 /* End node */#define FDT_PROP 0x3 /* Property: content_size, name off(in_dt_string), content */#define FDT_NOP 0x4 /* nop */#define FDT_END 0x9
4、dt_string
(字符串紧密排列,相当于属性名称的库。利用dt_struct中的属性名称偏移量检索,至“\0”截止)
00000580 23 61 64 64 72 65 73 73 2d 63 65 6c 6c 73 00 23 |#address-cells.#|00000590 73 69 7a 65 2d 63 65 6c 6c 73 00 63 6f 6d 70 61 |size-cells.compa|000005a0 74 69 62 6c 65 00 69 6e 74 65 72 72 75 70 74 2d |tible.interrupt-|000005b0 70 61 72 65 6e 74 00 6d 6f 64 65 6c 00 73 65 72 |parent.model.ser|000005c0 69 61 6c 30 00 73 65 72 69 61 6c 31 00 73 65 72 |ial0.serial1.ser|000005d0 69 61 6c 32 00 73 65 72 69 61 6c 33 00 64 65 76 |ial2.serial3.dev|000005e0 69 63 65 5f 74 79 70 65 00 72 65 67 00 74 69 2c |ice_type.reg.ti,|000005f0 68 77 6d 6f 64 73 00 72 61 6e 67 65 73 00 69 6e |hwmods.ranges.in|00000600 74 65 72 72 75 70 74 2d 63 6f 6e 74 72 6f 6c 6c |terrupt-controll|00000610 65 72 00 23 69 6e 74 65 72 72 75 70 74 2d 63 65 |er.#interrupt-ce|00000620 6c 6c 73 00 70 68 61 6e 64 6c 65 00 63 6c 6f 63 |lls.phandle.cloc|00000630 6b 2d 66 72 65 71 75 65 6e 63 79 00 |k-frequency.|
