设备树(一):DTS/DTB文件语法、格式

1.dts文件格式

(1) 语法:
Devicetree node格式:
[label:] node-name[@unit-address] {
    [properties definitions]
    [child nodes]
};

Property格式1:
[label:] property-name = value;

Property格式2(没有值):
[label:] property-name;

Property取值只有3种: 
arrays of cells(1个或多个32位数据, 64位数据使用2个32位数据表示), 
string(字符串), 
bytestring(1个或多个字节)

示例: 
a. Arrays of cells : cell就是一个32位的数据
interrupts = <17 0xc>;

b. 64bit数据使用2个cell来表示:
clock-frequency = <0x00000001 0x00000000>;

c. A null-terminated string (有结束符的字符串):
compatible = "simple-bus";

d. A bytestring(字节序列) :
local-mac-address = [00 00 12 34 56 78];  // 每个byte使用2个16进制数来表示
local-mac-address = [000012345678];       // 每个byte使用2个16进制数来表示

e. 可以是各种值的组合, 用逗号隔开:
compatible = "ns16550", "ns8250";
example = <0xf00f0000 19>, "a strange property format";


(2) 
DTS文件布局(layout):
/dts-v1/;
[memory reservations]    // 格式为: /memreserve/ 
; / { [property definitions] [child nodes] }; (3) 特殊的、默认的属性: a. 根节点: #address-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address) #size-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) compatible // 定义一系列的字符串, 用来指定内核中哪个machine_desc可以支持本设备 // 即这个板子兼容哪些平台 // uImage : smdk2410 smdk2440 mini2440 ==> machine_desc model // 咱这个板子是什么 // 比如有2款板子配置基本一致, 它们的compatible是一样的 // 那么就通过model来分辨这2款板子 b. /memory device_type = "memory"; reg // 用来指定内存的地址、大小 c. /chosen bootargs // 内核command line参数, 跟u-boot中设置的bootargs作用一样 d. /cpus /cpus节点下有1个或多个cpu子节点, cpu子节点中用reg属性用来标明自己是哪一个cpu 所以 /cpus 中有以下2个属性: #address-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述地址(address) #size-cells // 在它的子节点的reg属性中, 使用多少个u32整数来描述大小(size) // 必须设置为0 e. /cpus/cpu* device_type = "cpu"; reg // 表明自己是哪一个cpu (4) 引用其他节点: a. phandle : // 节点中的phandle属性, 它的取值必须是唯一的(不要跟其他的phandle值一样) pic@10000000 { phandle = <1>; interrupt-controller; }; another-device-node { interrupt-parent = <1>; // 使用phandle值为1来引用上述节点 }; b. label: PIC: pic@10000000 { interrupt-controller; }; another-device-node { interrupt-parent = <&PIC>; // 使用label来引用上述节点, // 使用lable时实际上也是使用phandle来引用, // 在编译dts文件为dtb文件时, 编译器dtc会在dtb中插入phandle属性 }; **节选自韦东山设备树详细分析**

2.DTB二进制文件格式

(1)dtb文件整体结构
设备树(一):DTS/DTB文件语法、格式_第1张图片
dtb文件为大端存储模式

struct ftd_header区域数据结构

struct fdt_header {
uint32_t magic; //dtb文件的固定开始数字 0xd00dfeed
uint32_t totalsize; //dtb文件的大小
uint32_t off_dt_struct; //structure block区域的地址偏移值,从文件开头计算
uint32_t off_dt_strings; //strings block区域的地址偏移值,从文件开头计算
uint32_t off_mem_rsvmap; //memory reservation block区域的地址偏移值,从文件开头计算
uint32_t version;
uint32_t last_comp_version;
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;  //structure block区域的字节数
uint32_t size_dt_struct; //strings block区域的字节数
};
memory reservation block区域数据结构

该区域信息描述了一块受保护的内存区域,该内存区域不用作一般内存使用
struct fdt_reserve_entry {
uint64_t address; //开始地址
uint64_t size; //大小
};
struct block区域,存放设备树信息主体,该区域4字节对其

0x00000001 //FDT_BEGIN_NODE,表示一个note节点开始
xxxxxxxxx  //节点名字,例如 chosen {bootargs = "xxxx";}; 节点名字为chosen
0x00000003 //FDT_PROP,表示一个属性开始
struct {
uint32_t len; //属性值长度
uint32_t nameoff; //属性名在strings block区域的偏移值
}
xxxxxxxxx //属性的具体内容
0x00000002 //FDT_END_NODE,表示一个note节点结束
0x00000009 //FDT_END,表示struct block区域结束

0x00000004 //FDT_NOP,特殊数据,解析设备树时将被忽略,如果要从dtb去除莫个note或者属性,可以用他覆盖该note或者属性,
                                                    //这样就不用移动dtb文件中其他数据了
strings block //存放struct block中用到的属性名,可能这些属性名重复率很高,这样节省空间。
                           //该区域的字符串简单地拼接在一起,没有字节对其。

官方文档:https://www.devicetree.org/specifications/
内核文档:Documentation/devicetree/booting-without-of.txt

tips:
1.反编译dtb文件
kernel目录下执行
./scripts/dtc/dtc -I dtb   -O dts    -o dest.dts    source.dtb

2.vim 查看二进制文件
参考:https://blog.csdn.net/chenqiai0/article/details/8537832
1). vim -b xxxx.dtb  加上-b参数,以二进制打开
2). :%!xxd -r

如有错误欢迎指正

你可能感兴趣的:(kernel)