点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!
4.2.2 Linux解析DTS/DTB流程
为什么要分析Linux解析DTS/DTB流程?因为物理中断号与Linux中断号的映射和open firmware device tree息息相关。
DTS(Device Tree Source)是一种人类可读的文本文件,但是对内核解析和使用并不友好。DTB(Device Tree Blob)是DTS文件经过编译后的二进制形式,是内核可以直接解析的紧凑数据结构。内核在启动时读取并解析DTB文件,构建内存中的设备树结构。内核对DTB的处理,归纳为两个阶段:发现与展开。
- 发现
根据Documentation/arm64/booting.txt,在跳转到内核之前,必须把DTB在内存中的物理地址存入X0寄存器。
经过如下preserve_boot_args和__primary_switched两个过程后,DTB的物理地址存入了变量__fdt_pointer。
arch/arm64/kernel/head.S:
preserve_boot_args:
mov x21, x0 // x21=FDT
__primary_switched:
str_l x21, __fdt_pointer, x5 // Save FDT pointer
setup_machine_fdt(__fdt_pointer)函数的入参就是上面得到的__fdt_pointer即DTB物理地址。setup_machine_fdt的主要任务是检查和验证设备树,确保传递给内核的DTB是有效的。
必须指出的是,上图中的设备树的虚拟地址dt_virt,在setup_machine_fdt->early_init_dt_scan->early_init_dt_verify调用过程中,会赋值给全局指针initial_boot_params。后续对DTB进行访问时,总是直接访问DTB虚拟地址initial_boot_params而不是DTB物理地址__fdt_pointer。
- 展开
展开的要点就是扁平化的二进制形式的DTB,展开成用struct device_node描述的树形结构。在Linux内核中,struct device_node代表设备树中的一个具体节点,这些节点可以是根节点、总线、设备或者其他类型的节点。
include/linux/of.h: struct device_node { const char *name; // 节点名 const char *type; // 节点类型 phandle phandle; // 该节点的唯一标识符 struct property *properties; // 属性列表 struct property *deadprops; // 已删除的属性列表 struct device_node *parent; // 父节点 struct device_node *child; // 第一个子节点 struct device_node *sibling; // 下一个兄弟节点 /* 这里省略了一些字段 */ }; |
unflatten_device_tree调用__unflatten_device_tree,传入的是DTB虚拟地址initial_boot_prarms,最终得到一颗用struct device_node描述的树,of_root指向树的头节点。
__unflatten_device_tree调用unflatten_dt_nodes,unflatten_dt_nodes遍历DTB,循环调用 populate_node 来创建和初始化 struct device_node 结构体,对成员name和type进行填充,并利用其成员parent/child/sibling形成树形结构。
小结一下,DTB物理地址通过X0传入内核,存入变量__fdt_pointer,而后完成地址映射并把DTB虚拟地址存入变量initial_boot_prarms,最后DTB展开为struct device_node设备树,头指针为of_root。通过访问of_root,即可遍历整个设备树,找到某个struct device_node节点,获取节点的属性。内核定义了很多API来方便的访问设备树,例如of_find_node_by_path("/chosen")可以根据路径来找到对应的struct device_node节点。
点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-CSDN博客
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!