系统未建立
分类: LINUX
2013-12-17 10:09:57
原文地址:epapr编译出的dtb文件结构解析 作者:yaanhyy
摘要:
本文分析powerpc架构的系统启动时需要用的到固件协议。它是联系boot初始化和内核启动的枢纽。对于该协议的分析将会对powerpc_linux系统启动部分的架构有一个深入的理解。
正文:
Epapr是 embedded power architecture platform requirements的缩写。它首先由device tree scripts来对板级系统进行描述。之后通过device tree compiler编译为物理格式的二进制文件dtb。
device tree scripts是由一组描述特性来组成的。根据不同特性的处理器和外设,由这组描述特性可以灵活的组成一个对其的描述,在系统初始化时应用。
物理格式:
Dtb是经过编译得到的二进制文件,有的也称作fdt(flattened device tree),uboot启动时,会根据系统配置,修改其中一些需要有uboot设置的特性,比如cpu主频,总线频率等。而内核初始化阶段,则需要对dtb进行逐一的分析,得到系统配置特性,完成初始化。下边是dtb的总的框架:
头结构体:
可以看出dtb开始是一个头部结构体,格式如下:
struct fdt_header {
uint32_t magic;
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version;
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
};
其中:
magic为魔数,dtb定义为0xd00dfeed(big endian)。
Totalsize: dtb文件的总大小。
off_dt_struct:为struct block距离dtb文件头的偏移量(字节)
off_dt_strings:为string block距离dtb文件头的偏移量(字节)
off_mem_rsvmap:为memory reservation block距离dtb文件头的偏移量(字节)
version:版本号,目前uboot支持v16和v17。
last_comp_version:向上兼容的版本好,一般现在兼容至16.
boot_cpuid_phys:系统用于boot的cpu的物理id号,该值应该与dts描述中cpu的描述特性的reg中的值一致!
size_dt_strings:string block的大小
size_dt_struct: struct block的大小
memory reservation block的结构:
由一组下边结构的数组组成。
struct fdt_reserve_entry {
uint64_t address;
uint64_t size;
};
其中的address给出物理基址,size是这块区域的大小。这个保留区的表结束在address和size都为0的地方,因为该结构的最小单位为64位,8字节。因此memory reservation block的起始地址在dtb中为8字节对齐!
struct block的结构:
struct block描述了系统的结构和其中的参数。它又分为很多Node,每个node是由一组token组成的。整个block中的Node构成是一个线性结构。每个token是32位,4字节长,因此struct block的起始地址应该为4字节对齐。
下边来看看struct block中每个node的格式
每个Node开始于一个大端的32位token。有个token后边会附带一些参数。所有的token都需要4字节对齐。这就要求在某些token附带参数后补零来保证token的4字节对齐。下边是struct block中的各种token:
FDT_BEGIN_NODE(0x00000001)
这个token是node开始的标志。它之后会附带Node的unit name作为参数。Node的name被存储为0结束符的string。可能还会包含unit address。name后边可能会补零来保证token的32位对齐。这个token紧跟的下一个token不能为FDT_END
FDT_END_NODE(0x00000002)
FDT_END_NODE标记了一个Node的结束。这个token后边不带附加数据。所以它之后紧跟下一个token。但是不能为FDT_PROP。
FDT_PROP(0x00000003)
该token标记了node的一个性质描述的开始。
它之后附带的参数描述了Node的性质。这些参数的构成如下边的结构体:
struct {
uint32_t len;
uint32_t nameoff;
}
这个结构为32位大端存储。
Len给出了性质的参数长度,这个长度可能为0,代表无参数的性质。
Nameoff给出了该性质的名称在string block中的相对位置。性质的名称的存储为0结束的string.
这个结构之后给出了该性质的参数。它是一个长度为len字节的值。它需要补零来保证下一个token的开始为4字节对齐。该token之后不能跟fdt_end这个token.
FDT_NOP (0x00000004)
这个token被解析程序直接跳过。这个token不带任何参数。直接跟下一个token。这个token的用处是在dtb的解析时,如果需要从原始的dtb中去除某个性质的话。就将该性质用NOP这个token来覆盖。
FDT_END (0x00000009)
该token标志整个struct block的结束。在一个dtb中只能有一个该token。
接下来具体了解了各个token的用法后,来分析一下struct block的结构。该结构是一个线性树!
子Node的FDT_BEGIN_NODE and FDT_END_NODE tokens是嵌套在它的父node的FDT_BEGIN_NODE and FDT_END_NODE tokens里的!
作为root的node也是这个线性书的根node。所有其他的node都嵌套其中!
节点的嵌套结构如下所示:
• (optionally) any number of FDT_NOP tokens
• FDT_BEGIN_NODE token
o The node’s name as a NULL-terminated string
o [zeroed padding bytes to align to a 4-byte boundary]
• For each property of the node:
o (optionally) any number of FDT_NOP tokens
o FDT_PROP token
property information as given in 7.4.1
[zeroed padding bytes to align to a 4-byte boundary]
• Representations of all child nodes in this format
• (optionally) any number of FDT_NOP tokens
• FDT_END_NODE token