Linux 驱动之设备树
dtb 数据解析
内核启动阶段获得 dtb 位置指针
以 arm64 为例,内核启动如下:
1 | __HEAD |
在开启 UEFI 支持时,add x13, x18, #0x16 这个 code 实际上是为了满足 EFI 格式的”MZ”头。如果使用 UEFI 来启动 kernel, 会识别出来并走 UEFI 启动的流程,如果是普通的启动过程如使用 uboot 的 booti 进行引导,那么第一条指令就是一条 dummy 指令,第二条就跳转到 stext 运行了。
x0 寄存器保存的是 dtb 里 blob 块的物理地址,x0 寄存器内容由 uboot 设置,uboot 将 dtb 地址传递给内核,跳转到 stext,如下:
1 | ENTRY(stext) |
arm64 linux 寄存器规定如下:
x0 = physical address of device tree blob (dtb) in system RAM.
x1 = 0 (reserved for future use)
x2 = 0 (reserved for future use)
x3 = 0 (reserved for future use)
将 dtb 的物理地址保存在 x21 寄存器中。
__inval_cache_range 这个函数用来 invalidate 指定区域的 cache。如果指定内存区域有跨越 cacheline, 那么对两边跨越了 cacheline 的地址使用的 clean + invalidate, 对于中间区域可以直接 invalidate 不用写回内存,从而加快 invalidate 速度。
调用__primary_switch 如下:
1 | __primary_switch: |
调用__primary_switched 函数:
1 | __primary_switched: |
通过 str_l x21, __fdt_pointer, x5 这句将 dtb 的地址保存在__fdt_pointer 指针里,以便后续内核可以找到 dtb 并解析设备树文件。
关于 linux 启动过程可以参考下图:原图

dtb 解析过程
start_kernel 阶段会处理 dtb 文件生成 device_node 结构体以及他们之间的组织关系。整体的调用逻辑如下:原图

下面以一个简单的设备树为例:
1 | / { |
该设备树经过 populate_node() 解析处理后,结构体关系如下:
1 | - /节点: |
device_node 与 device 绑定
kernel 会为设备树 root 节点下所有带’compatible’ 属性的节点都分配并注册一个 platform_device;另外,如果某节点的’compatible’ 符合某些 matches 条件,则会为该节点下所有带’compatible’ 属性的子节点(child)也分配并注册一个 platform_device。
整体调用流程如下图所示:原图

至此,为所有设备树中所有符合条件的 node 都创建了 platform_device 结构体,node 下描述的资源也解析到了 platform_device 中,并通过 dev 成员将该 node 描述的设备加入了统一设备模型。
补充:标签是标记节点的方法,可以用唯一的名称来标识节点,在 dt 编译器编译过程中,dt 编译器将该名称转换为唯一的 32 位值,之后可以使用标签引用节点,因为标签对于节点是唯一的。phandle 是与节点相关联的 32 位值,用于唯一标识该节点,以便可以从另一个节点属性引用该节点。为了在查找节点时不遍历整个树,引入别名的概念,在 dt 中,别名可以看作是节点的快速查找表,即一个节点的索引
参考文献
https://zhuanlan.zhihu.com/p/141623370
https://zhuanlan.zhihu.com/p/143092868
http://gngshn.github.io/
http://www.wowotech.net/sort/device_model
《Linux 设备驱动开发》
[[LinuxDriverPWM]]
[[LinuxDriverSPI]]
[[LinuxDriverRTC]]
[[LinuxDriverCCF]]
[[LinuxDriverIIC]]
[[LinuxDriverTips]]
[[LinuxDriverV4L2]]
[[LinuxDriverGPIO]]
[[LinuxDriverInput]]
[[LinuxDriverRegmap]]
[[LinuxDriverPinctrl]]
[[LinuxDriverRegulator]]
[[LinuxDriverDeviceTree]]
[[LinuxDriverFileSystem]]
[[LinuxDriverBaseDMA-API]]
[[LinuxDriverDeviceModule]]
[[LinuxDriverBaseDeviceIO]]
