DTB文件格式如图【图片摘自https://blog.csdn.net/cc289123557/article/details/51782449】

Device Tree源文件的结构分为header、fill_area、dt_struct及dt_string四个区域。
Device Tree文件结构以struct fdt_header、struct fdt_node_header及struct fdt_property三个结构体描述。
节点(node)信息使用struct fdt_node_header结构体描述。

struct fdt_node_header {fdt32_t tag;char name[0];
};

tag是标识node的起始结束等信息的标志位,name指向node名称的首地址
tag的取值:

#define FDT_BEGIN_NODE   0x1     /* Start node: full name */
#define FDT_END_NODE    0x2     /* End node */
#define FDT_PROP          0x3       /* Property: name off, size, content */
#define FDT_NOP     0x4     /* nop */
#define FDT_END     0x9

FDT_BEGIN_NODE和FDT_END_NODE标识node节点的起始和结束,FDT_PROP标识node节点下面的属性起始符,FDT_END标识Device Tree的结束标识符。
描述属性采用struct fdt_property描述,tag标识是属性,取值为FDT_PROP;len为属性值的长度(包括‘\0’,单位:字节);nameoff为属性名称存储位置相对于off_dt_strings的偏移地址。

struct fdt_property {fdt32_t tag;fdt32_t len;fdt32_t nameoff;char data[0];
};

可参考内核的Booting-without-of.txt描述,主要内容如下:

 a) ATAGS interface.  Minimal information is passed from firmware to the kernel with a tagged list of predefined parameters.r0 : 0r1 : 机器码r2 : tag参数列表在系统ram中的物理地址
b) Entry with a flattened device-tree block.  Firmware loads the physical address of the flattened device tree block (dtb) into r2,r1 is not used, but it is considered good practice to use a valid machine number as described in Documentation/arm/Booting.r0 : 0r1 : Valid machine type number.  When using a device tree, a single machine type number will often be assigned torepresent a class or family of SoCs.r2 : physical pointer to the device-tree block(defined in chapter II) in RAM.  Device tree can be located anywhere in system RAM, but it should be aligned on a 64 bitboundary.The kernel will differentiate between ATAGS and device tree booting by reading the memory pointed to by r2 and looking for either the flattened device tree block magic value (0xd00dfeed) or the ATAG_CORE value at offset 0x4 from r2 (0x54410001).

II - The DT block format

1) Header
---------The kernel is passed the physical address pointing to an area of memory that is roughly described in include/linux/of_fdt.h by the structure boot_param_header:
struct boot_param_header { u32     magic;                  /* magic word OF_DT_HEADER */u32     totalsize;              /* total size of DT block */u32     off_dt_struct;          /* offset to structure */u32     off_dt_strings;         /* offset to strings */u32     off_mem_rsvmap;         /* offset to memory reserve map*/ u32     version;                /* format version */u32     last_comp_version;      /* last compatible version *//* version 2 fields below */u32     boot_cpuid_phys;        /* Which physical CPU id we're booting on */ /* version 3 fields below */u32     size_dt_strings;        /* size of the strings block *//* version 17 fields below */u32    size_dt_struct;     /* size of the DT structure block */ };
So the typical layout of a DT block (though the various parts don't need to be in that order) looks like this (addresses go from top to bottom):base -> |  struct boot_param_header  |------------------------------|      (alignment gap) (*)   |------------------------------|      memory reserve map    |------------------------------|      (alignment gap)       |------------------------------|                            ||    device-tree structure   ||                            |------------------------------|      (alignment gap)       |------------------------------|                            ||     device-tree strings    ||                            |-----> ------------------------------||--- (base + totalsize)

This device-tree itself is separated in two different blocks, a structure block and a strings block. Both need to be aligned to a 4 byte boundary.
It’s basically a tree of nodes, each node having two or more named properties. A property can have a value or not.
a “unit name” that is used to differentiate nodes with the same name at the same level, it is usually made of the node names, the “@” sign, and a “unit address”, which definition is specific to the bus type the node sits on.
Every node which actually represents an actual device (that is, a node which isn’t only a virtual “container” for more nodes, like “/cpus” is) is also required to have a “compatible” property indicating the specific hardware and an optional list of devices it is fully backwards compatible with.
“OF_DT_BEGIN_NODE” token starts a new node,
“OF_DT_END_NODE” ends that node definition.
The tree has to be “finished” with a OF_DT_END token

Here's the basic structure of a single node:* token OF_DT_BEGIN_NODE (that is 0x00000001)* for version 1 to 3, this is the node full path as a zero terminated string, starting with "/". For version 16 and later,this is the node unit name only (or an empty string for theroot node)* [align gap to next 4 bytes boundary]* for each property:* token OF_DT_PROP (that is 0x00000003)* 32-bit value of property value size in bytes (or 0 if no value)* 32-bit value of offset in string block of property name* property value data if any* [align gap to next 4 bytes boundary]* [child nodes if any]* token OF_DT_END_NODE (that is 0x00000002)
So the node content can be summarized as a start token, a full path, a list of properties, a list of child nodes, and an end token. Every child node is a full node structure itself as defined above.
  1. Device tree “strings” block
    In order to save space, property names, which are generally redundant, are stored separately in the “strings” block. This block is simply the whole bunch of zero terminated strings for all property names concatenated together. The device-tree property definitions in the structure block will contain offset values from the beginning of the strings block.
1.  unflatten_device_tree解析
void __init unflatten_device_tree(void)
{__unflatten_device_tree(initial_boot_params, NULL, &of_root,early_init_dt_alloc_memory_arch, false);   //@1/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */of_alias_scan(early_init_dt_alloc_memory_arch);      //@2unittest_unflatten_overlay_base();
}

@1: 解析设备树dtb,保存在of_root,指向保存device_nod结构体的指针数组。

//在unflatten_dt_nodes函数中
struct device_node *nps[FDT_MAX_DEPTH];if (!dryrun && nodepp && !*nodepp)*nodepp = nps[depth+1];

@2:
获取指向别名节点的指针of_aliases
获取指向chosen节点的指针

在void __init setup_arch(char **cmdline_p)的最后,
if (mdesc->init_early)
mdesc->init_early();
而 mdesc来自于
mdesc = setup_machine_fdt(__atags_pointer);

  1. machine_desc解析
/*** setup_machine_fdt - Machine setup when an dtb was passed to the kernel* @dt:       virtual address pointer to dt blob** If a dtb was passed to the kernel, then use it to choose the correct* machine_desc and to setup the system.*/
const struct machine_desc * __init setup_machine_fdt(void *dt)
{const struct machine_desc *mdesc;unsigned long dt_root;if (!early_init_dt_scan(dt))return NULL;mdesc = of_flat_dt_match_machine(NULL, arch_get_next_mach);        //@1if (!mdesc)machine_halt();dt_root = of_get_flat_dt_root();arc_set_early_base_baud(dt_root);return mdesc;
}

@1:

 dt_root = of_get_flat_dt_root();while ((data = get_next_compat(&compat))) {score = of_flat_dt_match(dt_root, compat);if (score > 0 && score < best_score) {best_data = data;best_score = score;}}
static const void * __init arch_get_next_mach(const char *const **match)
{static const struct machine_desc *mdesc = __arch_info_begin;const struct machine_desc *m = mdesc;if (m >= __arch_info_end)return NULL;mdesc++;*match = m->dt_compat;return m;
}

在vmlinux.lds.S中
.init.arch.info : {
__arch_info_begin = .;
*(.arch.info.init)
__arch_info_end = .;
}
系统编译的machine_desc在这个段中.

.init.arch.info段中依次读取内核编译进去的machine_desc的描述,可能多个。见DT_MACHINE_START定义处,dt_compat定义在上面紧邻处。与uboot命令行传递来的设备树dtb的root根节点的compatible,若匹配上,则接着运行,否则停止运行,machine_halt();

machine_desc来自于:
设备树根节点的compatible属性列出了一系列的字符串,
表示它兼容的单板名,从"最兼容"到次之

内核中有多个machine_desc,其中有dt_compat成员, 它指向一个字符串数组, 里面表示该machine_desc支持哪些单板
S5pv210.c
static char const *const s5pv210_dt_compat[] __initconst = {
“samsung,s5pc110”,
“samsung,s5pv210”,
NULL 必须以null结尾,他们程序依次判断结束
};

DT_MACHINE_START(S5PV210_DT, “Samsung S5PC110/S5PV210-based board”)
.dt_compat = s5pv210_dt_compat,
.map_io = s5pv210_dt_map_io,
.restart = s5pv210_dt_restart,
.init_late = s5pv210_dt_init_late,
MACHINE_END

#define DT_MACHINE_START(_name, _namestr)
static const struct machine_desc _mach_desc##_name
__used
attribute((section(".arch.info.init"))) = {
.nr = ~0,
.name = _namestr,

内核小碎碎-第四集 解析dtb相关推荐

  1. Windows x64内核学习笔记(四)—— 9-9-9-9-12分页

    Windows x64内核学习笔记(四)-- 9-9-9-9-12分页 前言 9-9-9-9-12分页 实验一:线性地址转物理地址 页表基址 定位基址 PTE to PXE 实验二:通过页表基址定位各 ...

  2. 四库全书总目提要 卷一百八十四 集部三十七

    四库全书总目提要 卷一百八十四 集部三十七 2011年08月02日 ○别集类存目十一 △<湖海集>·十三卷(山东巡抚采进本) 国朝孔尚任撰.尚任有<节序同风录>,已著录.尚任官 ...

  3. Ada 程序设计语言(The Ada Programming Language)[第四集]

    Ada 程序设计语言(The Ada Programming Language)[第四集]- - 第6章 子程序(Subprogram) 6.1 概述 (Overview) 一个程序是由一个或更多的子 ...

  4. Android多媒体之GLES2战记第四集--移形换影

    视野限制了人对这个宇宙的认知,但没有视野,人将会一无所知 上集说到勇者坠入黑暗之渊,凭借对世界的认知构建出了世界系 到此为止,OpenGL的世界观已经映入脑海,新手十二副本已经通过 接下来等待他们的将 ...

  5. 支付宝支付 第四集:配置类的定义和注入

    支付宝支付 第四集:配置类的定义和注入 一.代码 目录结构 application-dev.yml # 支付宝支付参数配置 alipay:app_id: 公司支付宝的APPIDmerchant_pri ...

  6. Redis第四集:redis的基本知识说明

    Redis第四集:redis的基本知识说明 一.内容 默认16个数据库,类似数组下标从零开始,初始默认使用零号库 Select命令切换数据库 127.0.0.1:6379> select 7 O ...

  7. Apache POI和EasyExcel 第四集:Apache POI的Excel基本读取(分为03版的xls、07版的xlsx)

    Apache POI和EasyExcel 第四集:Apache POI的Excel基本读取(分为03版的xls.07版的xlsx) 一.资源 一个十分好用的日期类型处理包,和Java8搭配使用非常好 ...

  8. R语言入门第四集 实验三:数据可视化

    R语言入门第四集 实验三:数据可视化 一.资源 [R语言]R语言数据可视化--东北大学大数据班R实训第三次作业 在r中rowsums_R语言初级教程(15): 矩阵(下篇) R语言环境变量的设置 环境 ...

  9. Linux入门第四集!Jar包的入门、使用、部署!怎么打Jar包?

    Linux入门第四集!Jar包的入门.使用.部署!怎么打Jar包? 一.首先要确保JDK8已经安装成功 Linux入门第三集!JDK8的Linux版本资源分享!jdk-8u301-linux-x64. ...

最新文章

  1. docker环境下指定jvm参数
  2. mysql编写函数 求1 n 偶数之和,编写求1 2 3 - n的函数.在main函数中调用该函数
  3. 先思再行 闭着眼睛编程
  4. Java中的注解 Annotations
  5. 安装Kubernetes V1.18.2
  6. 体验QQ2011Beta3带来的变化和惊喜
  7. L2-039 清点代码库 (25 分)-PAT 团体程序设计天梯赛 GPLT
  8. cmake相关:sudo make install后的卸载
  9. Android App Architecture使用详解
  10. Executors介绍
  11. 项目启动会注意事项-甲方
  12. VSCODE快速添加到鼠标右键菜单
  13. hbase与hadoop版本兼容问题,强烈谴责hadoop生态圈耦合性
  14. 开拓者队医当选年度最佳 球迷:罗伊情何以堪
  15. Duplicate entry '127' for key 'PRIMARY'
  16. 2021夏令营全记录·厦大信院SE
  17. 30 行Python代码实现蚂蚁森林自动收能量(附送源码)
  18. 网络存储技术Windows server 2012 (项目二十二 远程异地灾备中心的部署)
  19. 远程登录多用户同时访问Win7系统远程桌面
  20. 常见web应用防护软件下载2021

热门文章

  1. 移动端微信里打开H5页面,页面字体放大
  2. flask-socketio实现的网页聊天室(一)
  3. java 一行行读取文件_Java中按行读取文件
  4. 张果老能是鸿蒙时期一蝙蝠,历史书中张果老的故事,一只蝙蝠的传奇
  5. 3个案例讲清如何构建“What-if分析”,教你轻松玩转动态参数
  6. 微信快捷回复怎么设置?
  7. word文档表格中插入图片设置
  8. 业务系统如何集成工作流引擎?
  9. 百慕大三角新奇神秘事件
  10. 我对移动支付的看法_对移动支付的看法作文_作文写作问答 - 归教作文网