当前位置:网站首页>设备树——dtb格式到struct device node结构体的转换
设备树——dtb格式到struct device node结构体的转换
2022-08-01 01:18:00 【正在起飞的蜗牛】
1、参考资料
2、struct device_node结构体
struct device_node {
const char *name; //节点的名字
const char *type; //device_type属性的值
phandle phandle; //对应该节点的phandle属性
const char *full_name; //节点的名字, node-name[@unit-address]从“/”开始的,表示该node的full path
struct fwnode_handle fwnode;
struct property *properties; // 节点的属性
struct property *deadprops; /* removed properties 如果需要删除某些属性,kernel并非真的删除,而是挂入到deadprops的列表 */
struct device_node *parent; // 节点的父亲
struct device_node *child; // 节点的孩子(子节点)
struct device_node *sibling; // 节点的兄弟(同级节点)
#if defined(CONFIG_OF_KOBJ) // 在sys文件系统表示
struct kobject kobj;
#endif
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
3、struct property结构体
struct property {
char *name; //属性名字
int length; //value的长度
void *value; //属性值
struct property *next; //指向统一节点的下一个属性
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
struct bin_attribute attr;
#endif
};
4、转换过程的函数调用关系
unflatten_device_tree() //解析dtb格式成struct device node结构体
__unflatten_device_tree()
unflatten_dt_nodes() //计算解析出的struct device node结构体所需要的内存大小
dt_alloc() //申请上面计算出来的需要的内存
unflatten_dt_nodes() //将dtb数据解析成device node结构体,保存在上面申请的内存中
of_alias_scan() //处理aliases节点,根据节点的别名找到对应节点并保存到aliases_lookup链表中
5、__unflatten_device_tree()函数
5.1、函数调用
__unflatten_device_tree(initial_boot_params, NULL, &of_root,early_init_dt_alloc_memory_arch, false);
| 传参 | 含义 |
|---|---|
| initial_boot_params | dtb数据的所在地址 |
| of_root | 保存将来解析的struct device_node结构体的根节点 |
| early_init_dt_alloc_memory_arch | 用于申请内存的函数 |
| false | 觉得是否设置根节点的OF_DETACHED标志 |
5.2、函数源码
__unflatten_device_tree(initial_boot_params, NULL, &of_root,
early_init_dt_alloc_memory_arch, false);
static void *__unflatten_device_tree(const void *blob,
struct device_node *dad,
struct device_node **mynodes,
void *(*dt_alloc)(u64 size, u64 align),
bool detached)
{
int size;
void *mem;
pr_debug(" -> unflatten_device_tree()\n");
if (!blob) {
pr_debug("No device tree pointer\n");
return NULL;
}
//打印dtb的相关信息
pr_debug("Unflattening device tree:\n");
pr_debug("magic: %08x\n", fdt_magic(blob));
pr_debug("size: %08x\n", fdt_totalsize(blob));
pr_debug("version: %08x\n", fdt_version(blob));
//校验dtb的数据头
if (fdt_check_header(blob)) {
pr_err("Invalid device tree blob header\n");
return NULL;
}
/* 第一次调用:计算解析出的struct device_node结构体所占内存大小 */
size = unflatten_dt_nodes(blob, NULL, dad, NULL);
if (size < 0)
return NULL;
//将内存大小4字节对齐
size = ALIGN(size, 4);
pr_debug(" size is %d, allocating...\n", size);
/* 申请解析设备树dtb数据需要的内存 */
mem = dt_alloc(size + 4, __alignof__(struct device_node));
if (!mem)
return NULL;
memset(mem, 0, size);
//将申请内存空间的下一个地址处赋值为0xdeadbeef
*(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
pr_debug(" unflattening %p...\n", mem);
/* 第二次调用:解析dtb数据成device node结构体,保存在上面申请的内存中*/
unflatten_dt_nodes(blob, mem, dad, mynodes);
//检查解析的device_node结构体所占内存是否越界
if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warning("End of tree marker overwritten: %08x\n",
be32_to_cpup(mem + size));
if (detached && mynodes) {
of_node_set_flag(*mynodes, OF_DETACHED);
pr_debug("unflattened tree is detached\n");
}
pr_debug(" <- unflatten_device_tree()\n");
return mem;
}
(1)unflatten_dt_nodes()会被调用两次,传参不同该函数会有不同的功能;第一次是计算所需内存大小,第二次是真正解析dtb数据成device_node格式;
(2)of_root变量保存的是根节点对应的struct device_node结构体;
6、struct device_node *of_root变量
(1)无论是dtb格式还是struct device_node格式,里面表达的数据是没变的,只是组织形式不同,解析的方法就不同。dtb格式和struct device_node格式都有专门的解析函数,dtb格式下是需要知道dtb数据所在内存地址,struct device_node格式是需要知道根节点的struct device_node结构体;
(2)of_root就是保存的根节点的struct device_node结构体,后续解析设备树的信息就是利用of_root根节点和专门的解析函数即可;
7、struct device_node格式下如何解析出信息
7.1、相关文件和操作函数
(1)在struct device_node格式下内核提供相关的操作函数,具体查看"drivers/of/base.c"文件;
(2)我们调用相关的函数,可以通过节点路径、节点名字、父节点等方式去查找需要的device_node结构体;
7.2、of_alias_scan()函数
void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
{
struct property *pp;
//通过节点的路径查看aliases节点
of_aliases = of_find_node_by_path("/aliases");
//通过节点的路径查看chosen节点
of_chosen = of_find_node_by_path("/chosen");
if (of_chosen == NULL)
of_chosen = of_find_node_by_path("/[email protected]");
if (of_chosen) {
/* linux,stdout-path and /aliases/stdout are for legacy compatibility */
const char *name = of_get_property(of_chosen, "stdout-path", NULL);
if (!name)
name = of_get_property(of_chosen, "linux,stdout-path", NULL);
if (IS_ENABLED(CONFIG_PPC) && !name)
name = of_get_property(of_aliases, "stdout", NULL);
if (name)
of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
}
if (!of_aliases)
return;
for_each_property_of_node(of_aliases, pp) {
const char *start = pp->name;
const char *end = start + strlen(start);
struct device_node *np;
struct alias_prop *ap;
int id, len;
/* Skip those we do not want to proceed */
if (!strcmp(pp->name, "name") ||
!strcmp(pp->name, "phandle") ||
!strcmp(pp->name, "linux,phandle"))
continue;
np = of_find_node_by_path(pp->value);
if (!np)
continue;
······
}
}
(1)of_alias_scan()函数主要是处理aliases节点,处理节点的别名,方便后续访问;
(2)查找aliases节点对应的device_node结构体就是通过绝对路径进行查找;
(3)of_find_node_by_path( )函数内部会根据of_root节点进行查找,of_root节点就是根节点;
8、dts示例源码
/dts-v1/;
/memreserve/ 0x4ff00000 0x100000;
/ {
model = "YIC System SMDKV210 based on S5PV210";
compatible = "yic,smdkv210", "samsung,s5pv210";
#address-cells = <1>;
#size-cells = <1>;
chosen {
bootargs = "console=ttySAC2,115200n8 root=/dev/nfs nfsroot=192.168.0.101:/home/run/work/rootfs/";
};
[email protected]30000000 {
device_type = "memory";
reg = <0x30000000 0x20000000>;
};
};
9、dts文件和struct device_node的转换图

边栏推荐
- Chinese version of Pylint inspection rules
- leetcode:1562. 查找大小为 M 的最新分组【模拟 + 端点记录 + 范围合并】
- Unity3D study notes 10 - texture array
- MYSQL-批量插入数据
- MYSQL Classic Interview Questions
- VPGNet
- /usr/sbin/vmware-authdlauncher: error while loading shared libraries: libssl.so.1.0.2*Solution
- Matlab/ArcGIS processing GPM global monthly precipitation data
- how to edit the table of contents of an epub ebook
- Academicians of the two academies speak bluntly: Don't be superstitious about academicians
猜你喜欢

机器学习初学者可以学哪些实战项目?

RTL8762DK PWM(七)

Team of Professor Chen Jianyu of Tsinghua University | Contact Safety Reinforcement Learning Framework Based on Contact-rich Robot Operation

Matlab/Arcgis processing nc data

Beijing suddenly announced that yuan universe big news

Carefully summarize thirteen suggestions to help you create more suitable MySQL indexes

Introduction to the five data types of Redis

SC7A20 (Silan Micro-Accelerometer) Example

Rainbow share | how to use moving targets defense technology to guard against the unknown

Key Points Estimation and Point Instance
随机推荐
MYSQL-Batch insert data
MYSQL-批量插入数据
设计消息队列存储消息数据的MySQL表格
WebApi 打个Attribute 统一处理异常
Classes and Objects: Above
Modern Enterprise Architecture Framework 1
WebApi hits an Attribute to handle exceptions uniformly
leetcode:1648. 销售价值减少的颜色球【二分找边界】
MYSQL master-slave replication
【密码学/密码分析】基于TMTO的密码分析方法
现代企业架构框架1
/usr/sbin/vmware-authdlauncher: error while loading shared libraries: libssl.so.1.0.2*解决办法
Compose原理-视图和数据双向绑定的原理
Luogu P3373: 线段树
Nmap Operation Manual - Full Version
Design the message queue storage MySQL form of message data
RTL8762DK PWM(七)
Introduction to machine learning how to?
WeChat applet page syntax
ECCV2022 Workshop | Multi-Object Tracking and Segmentation in Complex Environments