dtb文件上篇博客中已经分析过了,接下来分析一些特殊情况,将dts文件编译成dtb文件之后再用fdtdump反编译出来,对比两个文件看看有什么差异。

  用指令fdtdump test.dtb > dump.txt 将test.dtb文件反编译成test.txt文件,fdtdump指令可以加参数的,可以输入fdtdump –h查看支持的参数,如输入fdtdump -sd test.dtb > dump.txt的话生成的dump.txt文件中就会包含很多调试信息。

  接下来通过一些案例,对比源文件和反编译后的文件,来了解一些特殊情况是怎么编译的:

  注:反编译后的文件包含了文件头信息,为了方便查看,

案例一

原文件:

1 /dts-v1/;
2 / {
3     property = [01 02 03 04];
4 };

 

反编译文件:

1 /dts-v1/;
2 / {
3     property = <0x01020304>;
4 };

 

分析:

原先的property = [01 02 03 04];变成了property = <0x01020304>;其实是一样的。

 

案例二

原文件:

1 /dts-v1/;
2 / {
3     property = <&label>;
4     
5     label: node {
6     
7     };
8 };

 

反编译文件(偷个懒,在之后的反编译文件中去掉了/des-v1/这一行):

1 / {
2     property = <0x00000001>;
3     node {
4         linux,phandle = <0x00000001>;
5         phandle = <0x00000001>;
6     };
7 };

 

分析:

如果属性值中某一项用尖括号包含了,其值引用了某个节点,那么其值变成了一个32位数,被引用的节点会多出linux,phandle和phandle两个属性,这两个属性的值是两个相同的32位数,这个数和引用它的数是相等的。

 

案例三

原文件:

 1 /dts-v1/;
 2 / {
 3 
 4     property = <&label1>;
 5     property2 = <&label2>;
 6     property3 = <&label1>;
 7 
 8     label1: node {
 9     
10     };
11     
12     label2: node2 {
13     
14     };
15 };

 

反编译文件:

 1 / {
 2     property = <0x00000001>;
 3     property2 = <0x00000002>;
 4     property3 = <0x00000001>;
 5     node {
 6         linux,phandle = <0x00000001>;
 7         phandle = <0x00000001>;
 8     };
 9     node2 {
10         linux,phandle = <0x00000002>;
11         phandle = <0x00000002>;
12     };
13 };

 

分析:

不同的被引用的节点phandle值会从1开始递增,引用相同的节点其phandle值相等。

 

案例四

原文件:

 1 /dts-v1/;
 2 / {
 3 
 4     property = <1>;
 5     property2 = <&label>;
 6 
 7     label: node {
 8     
 9     };
10 };

 

反编译文件:

1 / {
2     property = <0x00000001>;
3     property2 = <0x00000001>;
4     node {
5         linux,phandle = <0x00000001>;
6         phandle = <0x00000001>;
7     };
8 };

 

分析:

这个案例中,property的值就设定为1,property2的值引用了node节点,我以为生成的phandle值会避开1这个值,结果竟然还是1,那这样property和property2两个属性不就没法区分了吗,将原文件改为如下:

 1 /dts-v1/;
 2 / {
 3 
 4     property = <&label>;
 5     property2 = <&label>;
 6 
 7     label: node {
 8     
 9     };
10 };

反编译出来的文件与 property = <1>;的文件一样,那这样就有问题了呀,内核怎么区分这个属性值是一个引用还是这就是它的值呢?

 

案例五

原文件:

 1 /dts-v1/;
 2 / {
 3 
 4     property = &grandson;
 5     label: node {
 6         child-node {
 7             grandson: grandson-node {
 8             
 9             };
10         };
11     };
12 };

 

反编译文件:

1 / {
2     property = "/node/child-node/grandson-node";
3     node {
4         child-node {
5             grandson-node {
6             };
7         };
8     };
9 };

 

分析:

如果某个属性的值直接就引用某个节点(不带尖括号),那么相当于传入的属性值是一个字符串,这个字符串表示的是被引用的节点的路径

 

案例六

原文件:

1 /dts-v1/;
2 / {
3 
4     property = <&label 1 2>;
5     label: node {
6 
7     };
8 };

 

反编译文件:

1 / {
2     property = <0x00000001 0x6e6f6465 0x00000009>;
3     node {
4         linux,phandle = <0x00000001>;
5         phandle = <0x00000001>;
6     };
7 };

 

分析:

这个结果可真是把我吓坏了,我赶紧用winhex打开dtb文件,一看:

 

见选中处,发现并没有什么问题,这么说那就是fdtdump工具有问题了,又经过几次测试发现当属性的值是一个32位数组(尖括号里面不止一个数)的时候,fdtfump工具就会出问题。

 

 

案例七

原文件:

 1 /dts-v1/;
 2 / {
 3 
 4     property = <1>;
 5     property2 = <2>;
 6     label: node {
 7 
 8     };
 9 };
10 
11 / {
12     property2 = "hello";
13     property3 = <3>;
14 };

 

反编译文件:

1 / {
2     property = <0x00000001>;
3     property2 = "hello";
4     property3 = <0x00000003>;
5     node {
6     };
7 };

 

分析:

后面写的根节点可以认为是对前面根节点的解释或修改,不同的属性会直接加进去,相同的属性会被重写。同样的也可以对其他节点进行重写,但是一定要在最外层路径上用引用的方式重写,下面列出一些错误的重写方式:

1. 同一节点下有两个相同的子节点

 1 /dts-v1/;
 2 / {
 3     node {
 4 
 5     };
 6     
 7     node {
 8     
 9     };
10 };

2. 引用没放在最外层

 1 /dts-v1/;
 2 / {
 3     label:node {
 4 
 5     };
 6     
 7     &label {
 8         property = "hello";
 9     };
10 };

 

下面这种写法才是合法的:

 1 /dts-v1/;
 2 / {
 3     label:node {
 4 
 5     };
 6 };
 7 
 8 &label {
 9     property = "hello";
10 };

 

反编译结果:

1 / {
2     node {
3         property = "hello";
4     };
5 };

 

案例八

原文件:

1 /dts-v1/;
2 / {
3     node@0 {
4 
5     };
6 };

 

二进制文件:

 

 节点名带地址的形式编译器并没有将节点名和地址分开处理,而是将它们当成一个整体算作节点名(当这并不意味着节点名加地址没用)。

另外还发现一个现象,就是FDT_NOP这个标签从来都没有出现过。是不是说正常编译器编译的文件中不会带有这个标志。

 

到这里基本上设备树文件已经算是吃透了,唯一不解的地方就是案例四,接下来要进内核分析一下内核是怎么做的了。