当前位置:网站首页>设备树——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的转换图
边栏推荐
- In 2022, the latest eight Chongqing construction members (electrical construction workers) simulation question bank and answers
- MYSQL二阶段提交
- RTL8762DK RTC (5)
- Rasa 3.x Study Series - Rasa - Issues 4918 Study Notes
- An open source and easy-to-use flowchart drawing tool drawio
- Rainbow share | how to use moving targets defense technology to guard against the unknown
- ECCV2022 Workshop | Multi-Object Tracking and Segmentation in Complex Environments
- RTL8762DK uses DebugAnalyzer (four)
- 你需要知道的 TCP 四次挥手
- Application of integrated stepper motor in UAV automatic airport
猜你喜欢
【 】 today in history: on July 31, "brains in vats" the birth of the participant;The father of wi-fi was born;USB 3.1 standard
北京突然宣布,元宇宙重大消息
RTL8762DK WDG (six)
RTL8762DK PWM (seven)
Cmake introductory study notes
RTL8762DK WDG(六)
MYSQL query interception optimization analysis
RTL8762DK UART(二)
Summary of MVCC
【数据分析】基于matlab GUI学生成绩管理系统【含Matlab源码 1981期】
随机推荐
ROS2系列知识(4): 理解【服务】的概念
Introduction to the five data types of Redis
Introduction to machine learning how to?
/usr/sbin/vmware-authdlauncher: error while loading shared libraries: libssl.so.1.0.2*Solution
【历史上的今天】7 月 31 日:“缸中之脑”的提出者诞生;Wi-Fi 之父出生;USB 3.1 标准发布
【数据分析】基于matlab GUI学生成绩管理系统【含Matlab源码 1981期】
Key Points Estimation and Point Instance
ECCV2022 Workshop | Multi-Object Tracking and Segmentation in Complex Environments
Team of Professor Chen Jianyu of Tsinghua University | Contact Safety Reinforcement Learning Framework Based on Contact-rich Robot Operation
Web3.0:构建 NFT 市场(一)
ECCV2022 Workshop | 复杂环境中的多目标跟踪和分割
qlib量化源码分析:qlib/qlib/contrib/model/gbdt.py
STK8321 I2C(昇佳-加速度传感器)示例
/usr/sbin/vmware-authdlauncher: error while loading shared libraries: libssl.so.1.0.2*解决办法
Js replication
JVM面试题总结(持续更新中)
What practical projects can machine learning beginners learn?
RTL8762DK RTC (5)
JQESAP系统里的胖接口Fat interface
pycaret source code analysis: download dataset\Lib\site-packages\pycaret\datasets.py