Linux设备树解析

1. Device Tree简介

Linus Torvalds在2011年3月17日的ARM Linux邮件列表宣称“this whole ARM thing is a fucking pain in the ass”,引发ARM Linux社区的地震,随后ARM社区进行了一系列的重大修正。在过去的ARM Linux中,arch/arm/plat-xxx和arch/arm/mach-xxx中充斥着大量的垃圾代码,相当多数的代码只是在描述板级细节,而这些板级细节对于内核来讲,不过是垃圾,如板上的platform设备、resource、i2c_board_info、spi_board_info以及各种硬件的platform_data。 社区必须改变这种局面,于是PowerPC等其他体系架构下已经使用的Flattened Device Tree(FDT)进入ARM社区的视野。Device Tree是一种描述硬件的数据结构,它起源于OpenFirmware(OF)。在Linux2.6中,ARM架构的板极硬件细节过多地被硬编码在arch/arm/plat-xxx和arch/arm/mach-xxx,采用Device Tree后,许多硬件的细节可以直接透过它传递给Linux,而不再需要在kernel中进行大量的冗余编码。

Device Tree由一系列被命名的结点(node)和属性(property)组成,而结点本身可包含子结点。所谓属性,其实就是成对出现的name和value。在Device Tree中,可描述的信息包括(原先这些信息大多被hard code到kernel中):

  • CPU的数量和类别
  • 内存基地址和大小
  • 总线和桥
  • 外设连接
  • 中断控制器和中断使用情况
  • GPIO控制器和GPIO使用情况

它基本上就是画一棵电路板上CPU、总线、设备组成的树,Bootloader会将这棵树传递给内核,然后内核可以识别这棵树,并根据它展开出Linux内核中的platform_device、i2c_client、spi_device等设备。这些设备用到的内存、IRQ等资源,也被传递给了kernel,kernel会将这些资源绑定给展开的相应的设备。

2. Device Tree编译

Device Tree文件的格式为dts,包含的头文件格式为dtsi,dts文件是一种人可以看懂的编码格式。但是uboot和linux不能直接识别,他们只能识别二进制文件,所以需要把dts文件编译成dtb文件。dtb文件是一种可以被kernel和uboot识别的二进制文件。把dts编译成dtb文件的工具是dtc。Linux源码目录下scripts/dtc目录包含dtc工具的源码。在Linux的scripts/dtc目录下除了提供dtc工具外,也可以自己安装dtc工具,linux下执行:sudo apt-get install device-tree-compiler安装dtc工具。其中还提供了一个fdtdump的工具,可以反编译dtb文件。dts和dtb文件的转换如图1所示。
dtc工具的使用方法是:dtc –I dts –O dtb –o xxx.dtb xxx.dts,即可生成dts文件对应的dtb文件了。
图1 dts和dtb文件转换

3. Device Tree头信息

fdtdump工具使用,Linux终端执行ftddump –h,输出以下信息:
fdtdump -h
Usage: fdtdump [options]
Options: -[dshV]
-d, –debug Dump debug information while decoding the file
-s, –scan Scan for an embedded fdt in file
-h, –help Print this help and exit
-V, –version Print version and exit
本文采用s5pv21_smc.dtb文件为例说明fdtdump工具的使用。Linux终端执行fdtdump –sd s5pv21_smc.dtb > s5pv21_smc.txt,打开s5pv21_smc.txt文件,部分输出信息如下所示:
// magic: 0xd00dfeed
// totalsize: 0xce4 (3300)
// off_dt_struct: 0x38
// off_dt_strings: 0xc34
// off_mem_rsvmap: 0x28
// version: 17
// last_comp_version: 16
// boot_cpuid_phys: 0x0
// size_dt_strings: 0xb0
// size_dt_struct: 0xbfc
以上信息便是Device Tree文件头信息,存储在dtb文件的开头部分。在Linux内核中使用struct fdt_header结构体描述。struct fdt_header结构体定义在scripts\dtc\libfdt\fdt.h文件中。

struct fdt_header {
    fdt32_t magic;               /* magic word FDT_MAGIC */
    fdt32_t totalsize;           /* total size of DT block */
    fdt32_t off_dt_struct;       /* offset to structure */
    fdt32_t off_dt_strings;      /* offset to strings */
    fdt32_t off_mem_rsvmap;      /* offset to memory reserve map */
    fdt32_t version;                 /* format version */
    fdt32_t last_comp_version;   /* last compatible version */

    /* version 2 fields below */
    fdt32_t boot_cpuid_phys;     /* Which physical CPU id we're booting on */
    /* version 3 fields below */
    fdt32_t size_dt_strings;     /* size of the strings block */

    /* version 17 fields below */
    fdt32_t size_dt_struct;      /* size of the structure block */
};

fdtdump工具的输出信息即是以上结构中每一个成员的值,struct fdt_header结构体包含了Device Tree的私有信息。例如: fdt_header.magic是fdt的魔数,固定值为0xd00dfeed,fdt_header.totalsize是fdt文件的大小。使用二进制工具打开s5pv21_smc.dtb验证。s5pv21_smc.dtb二进制文件头信息如图2所示。从图2中可以得到Device Tree的文件是以大端模式储存。并且,头部信息和fdtdump的输出信息一致。
图2 头信息

Device Tree中的节点信息举例如图3所示。
图3 设备树全景试图
上述.dts文件并没有什么真实的用途,但它基本表征了一个Device Tree源文件的结构。1个root结点”/”;root结点下面含一系列子结点,本例中为”node@0”和”node@1”;结点”node@0”下又含有一系列子结点,本例中为”child-node@0”;各结点都有一系列属性。这些属性可能为空,如” an-empty-property”;可能为字符串,如”a-string-property”;可能为字符串数组,如”a-string-list-property”;可能为Cells(由u32整数组成),如”second-child-property”,可能为二进制数,如”a-byte-data-property”。Device Tree源文件的结构分为header、fill_area、dt_struct及dt_string四个区域。header为头信息,fill_area为填充区域,填充数字0,dt_struct存储节点数值及名称相关信息,dt_string存储属性名。例如:a-string-property就存储在dt_string区,”A string”及node1就存储在dt_struct区域。
我们可以给一个设备节点添加lable,之后可以通过&lable的形式访问这个lable,这种引用是通过phandle(pointer handle)进行的。例如,图3中的node1就是一个lable,node@0的子节点child-node@0通过&node1引用node@1节点。像是这种phandle的节点,在经过DTC工具编译之后,&node1会变成一个特殊的整型数字n,假设n值为1,那么在node@1节点下自动生成两个属性,属性如下:
linux,phandle = <0x00000001>;
phandle = <0x00000001>;
node@0的子节点child-node@0中的a-reference-to-something = <&node1>会变成a-reference-to-something = < 0x00000001>。此处0x00000001就是一个phandle得值,每一个phandle都有一个独一无二的整型值,在后续kernel中通过这个特殊的数字间接找到引用的节点。通过查看fdtdump输出信息以及dtb二进制文件信息,得到struct fdt_header和文件结构之间的关系信息如所示。
图4 struct fdt_header和文件结构之间的关系

4. Device Tree文件结构

通过以上分析,可以得到Device Tree文件结构如图5所示。dtb的头部首先存放的是fdt_header的结构体信息,接着是填充区域,填充大小为off_dt_struct – sizeof(struct fdt_header),填充的值为0。接着就是struct fdt_property结构体的相关信息。最后是dt_string部分。
图5 Device Tree文件结构
Device Tree源文件的结构分为header、fill_area、dt_struct及dt_string四个区域。fill_area区域填充数值0。节点(node)信息使用struct fdt_node_header结构体描述。属性信息使用struct fdt_property结构体描述。各个结构体信息如下:

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值