当前位置:网站首页>设备树——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的转换图

边栏推荐
猜你喜欢

声称AI存在意识,谷歌工程师遭解雇:违反保密协议

微信小程序之小程序页面语法

Summary of JVM interview questions (continuously updated)

RTL8762DK UART(二)

leetcode:1648. 销售价值减少的颜色球【二分找边界】

Kyoto University: Masaki Waga | Dynamic Masking for Reinforcement Learning in Black Box Environments

RTL8762DK uses DebugAnalyzer (four)

WeChat applet page syntax

RTL8762DK PWM (seven)

机器学习应该如何入门?
随机推荐
Key Points Estimation and Point Instance
RTL8762DK WDG (six)
Basic implementation of vector
RTL8762DK RTC (5)
ROS2系列知识(4): 理解【服务】的概念
考研备考方案
gateway gateway cross domain
Force buckle 2326, 197
sqlserver无法远程连接
High dimensional Gaussian distribution basics
Google "Cloud Developer Quick Checklist"; Tsinghua 3D Human Body Dataset; SenseTime "Universal Vision Framework" open class; Web3 Minimalist Getting Started Guide; Free Books for Efficient Deep Learni
leetcode: 1648. Color ball with decreasing sales value [Boundary find by two points]
Nmap 操作手册 - 完整版
Nmap Operation Manual - Full Version
Binary tree traversal non-recursive program -- using stack to simulate system stack
pycaret source code analysis: download dataset\Lib\site-packages\pycaret\datasets.py
机器学习初学者可以学哪些实战项目?
Notes on how to use zeno
/usr/sbin/vmware-authdlauncher: error while loading shared libraries: libssl.so.1.0.2*Solution
TCP协议详解