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

边栏推荐
- Rasa 3.x Learning Series - Using Lookup Tables to Improve Entity Extraction
- 网关gateway跨域
- Academicians of the two academies speak bluntly: Don't be superstitious about academicians
- how to edit the table of contents of an epub ebook
- 元宇宙改变人类工作模式的四种方式
- Daily practice of LeetCode - Circular linked list question (interview four consecutive questions)
- Kyoto University: Masaki Waga | Dynamic Masking for Reinforcement Learning in Black Box Environments
- OSF一分钟了解敏捷开发模式
- Web3.0: Building an NFT Market (1)
- 【Cryptography/Cryptanalysis】Cryptanalysis method based on TMTO
猜你喜欢

MYSQL查询截取优化分析

leetcode:1562. 查找大小为 M 的最新分组【模拟 + 端点记录 + 范围合并】
![leetcode: 1648. Color ball with decreasing sales value [Boundary find by two points]](/img/b9/7bd33bd981ace25e3bbfc7be9117ff.png)
leetcode: 1648. Color ball with decreasing sales value [Boundary find by two points]

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

Google engineer fired for claiming AI awareness: breach of nondisclosure agreement

两院院士直言:不要迷信院士

MYSQL Classic Interview Questions

leetcode:1648. 销售价值减少的颜色球【二分找边界】
![[Data analysis] Based on matlab GUI student achievement management system [including Matlab source code 1981]](/img/65/b84443b98c28d2728e9ae44b1294fb.jpg)
[Data analysis] Based on matlab GUI student achievement management system [including Matlab source code 1981]

MYSQL经典面试题
随机推荐
Cmake introductory study notes
从零造键盘的键盘超级喜欢,IT人最爱
MYSQL logical architecture
Chinese version of Pylint inspection rules
Introduction to the decision logic of WAASAP WebClient UI page labels
pycaret source code analysis: download dataset\Lib\site-packages\pycaret\datasets.py
MVCC总结
WebApi 打个Attribute 统一处理异常
The principle of virtual inheritance
网关gateway跨域
OSF一分钟了解敏捷开发模式
Compose principle - the view and the principle of two-way data binding
微信小程序之小程序页面语法
sqlserver无法远程连接
Compose原理-视图和数据双向绑定的原理
Blueprint: Yang Hui's Triangular Arrangement
RTL8762DK WDG(六)
ECCV2022 Workshop | 复杂环境中的多目标跟踪和分割
SC7A20(士兰微-加速度传感器)示例
/usr/sbin/vmware-authdlauncher: error while loading shared libraries: libssl.so.1.0.2*解决办法