引言
这篇文章将会走进一个在我开撸4.19之前迷惑了我很久的点,那就是kernel dtb与dtbo的关系
在这篇文章中,你将会了解到
- kernel dtb里装了什么
- dtbo里装了什么
- kernel dtb与dtbo之间的关系
- msm-4.19平台与以前平台在kernel dtb上的区别
简单科普
首先来了解一下什么是dt
此处的dt是kernel device tree的简称
基于arm平台的soc种类繁多,硬件资源和配置各不相同。这些平台硬件相关的信息在设备树出现之前,是在kernel/arch/arm/plat-xxx目录和kernel/arch/arm/mach-xxx目录下硬编码的。在kernel看来,这些硬件细节代码只不过是些垃圾,需要一套框架抽象出来,屏蔽这些硬件细节。设备树框架被提出用来统一arm平台硬件配置,屏蔽硬件细节。( 引自 https://blog.csdn.net/weixin_33850015/article/details/91871179 )
说白了,dt就是一堆设备特有的配置文件,它们的出现是为了使内核代码树变得干净一些(只留下适用于所有设备的部分,而将设备之间有区别的部分转移至dt)
dt在高通平台内核中的位置
- msm-3.18/msm-4.4 -> arch/arm/boot/dts/qcom
- msm-4.9/msm-4.14 -> arch/arm64/boot/dts/qcom
- msm-4.19 -> 不在内核树中
device tree语法
但是我还是简单说一下。。。dt主要由两种文件组成,分别是xx.dts和xx.dtsi,其中只有xx.dts文件才能生成对应的dtb/dtbo,dtsi文件是用来include的。
也就是说,一个dtb/dtbo文件中包含了
- 生成这个dtb/dtbo的dts文件内容
- 这个dts文件中include的dtsi文件内容
- 被include的dtsi文件中引用的其它dtsi文件内容
- 至于这里的include(引用),其实在生成dtb时你可以简单的理解为复制粘贴,也就是把那个文件的内容替换到include的位置((
还有一个非常关键的点,关系到dtbo的原理,那就是dt之间是可以互相覆盖的
比如1.dtsi引用了2.dtsi,那么1.dtsi就可以在include的下方重写2.dtsi中的节点
总结一下,编译dtb/dtbo的过程实际上先是一个合并+递归include的过程,其中谁距离dts文件越近,就具有越高的覆盖优先级,可以覆盖越多的节点而更难被别人覆盖
kernel dtb
dtb是device tree binary的简称
binary,顾名思义,就是可以被bootloader直接读取执行的内容
它们在开机启动在早期阶段由bootloader解码,传递给内核,从而帮助内核完成启动过程
- 在较老的平台上(msm-3.18 / msm-4.4),device tree只存在于boot分区中, 可以通过在Makefile中指定
dtb-y += <名称>.dtb
来编译对应的dtb文件(其中名称是指源dts的名称,也就是<名称>.dts)。这些文件将会被与内核的编译产物Image.xx连接,最终生成Image.xx-dtb,常见的有Image-dtb Image.gz-dtb Image.lz4-dtb等,而这个过程由CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE
控制。在这个选项被关闭后,编译也会生成dtb文件,但不会主动连接至内核镜像。
dtbo
dtbo是device tree binary overlay的简称
在msm-4.9平台上,dtbo横空出世(准确来说是出厂搭载安卓9的要求)。device tree被拆分到了两个地方,一个是boot分区中的老位置,另一个则是dtbo分区。谷歌做这件事的初衷在于:希望分离芯片厂商和手机厂商的修改,芯片厂商只修改内核中的dtb,而手机厂商只修改dtbo分区,这样能够井井有条((但是事实是手机厂商也还在改内核的dtb草
因此,就初衷而言,我们已经可以看出dtb和dtbo分区之间的关系
->加载kernel dtb
bootloader引导启动-> ->合并->传递给内核->内核启动
->加载dtbo分区
那么问题来了,谁的优先级更高呢?假如一个东西同时出现在dtb与dtbo中,谁会覆盖谁呢?
- 肯定是dtbo覆盖kernel dtb啊,不然它凭什么叫overlay…(((不过我并没有去验证(懒
在Makefile中,我们可以看到包含dtbo分区的设备的dt编译逻辑,和上方的旧平台有些许不同
我们可以通过dtbo-y += <名称>.dtbo
来编译dtbo文件(和上方的dtb一样,名称来自于源文件<名称>.dts)
但是,同时我们需要指定dtbo的base,也就是这个叠加层是基于哪个dtb进行叠加覆盖的
<名称>.dtbo-base := <名称2>.dtb
在这样配置之后,编译内核时,编译系统将会编译对应的dtbo和dtb,并将dtb打包进入内核(前提是开启CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE
),但是dtbo将会留在原处。厂商在编译系统时,dtbo文件是由编译系统的其他部分(非内核)处理并打包成为dtbo分区,生成dtbo镜像。
但是,我们依然可以在单跑内核时生成dtbo镜像。
我们需要摘下以下几个提交

(可以在此处找到 https://github.com/wloot/raphael/commits/shit?after=692f2b3a59549740e737eafe2c24d6dd7b184d2f+699&branch=shit )
一般情况下,厂商开源的内核源码中,都已经默认写好了dtbo编译的相关参数,但是没有打开关键的编译选项CONFIG_BUILD_ARM64_DT_OVERLAY
,至于原因,我想是和厂商们的编译系统有关系(编译系统似乎是独立编译kernel和dt的),而这也正是4.19内核的方向。
msm-4.19平台的重要更改
拆分device tree
现在,device tree不再作为内核源码的一部分,而转为不开源的bsp的一部分,当然,厂商为了方便,还是会把device tree丢回内核源码中(比如一加),又或者会作为额外仓库开源(小米)
内核Image与dtb的关系发生了变化
在老的平台上,内核编译系统是会生成Image.*-dtb的内核镜像与dtb二合一文件(默认也会开启CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE
)
但是现在,内核不再开启CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE
,默认编译裸Image,并且
单个裸Image使用Anykernel刷入可以正常开机
Image.xx-dtb使用Anykernel刷入也可正常开机,但是与Image连接的dtb无法被读取
- 如果想要覆盖kernel dtb,需要在Anykernel中放入Image和对应dtb文件(比如kona-v2.1.dtb)(当然,要重命名为dtb)
也就是说,现在Image和kernel dtb已经完全割裂,kernel dtb变成了不依附于Image的独立存在,强行将它们连接反而会导致dtb无法被正常读取的后果
所以,dtb和dtbo里到底装了什么?
- dtb中装有芯片级配置,比如gpu频率表,这就是为什么gpu超频卡刷包里面是个dtb文件的原因(用来替换kernel dtb)
- dtbo中装有厂商级的配置,比如屏幕、相机等,这就是为什么超刷新率改的是dtbo分区
具体,你可以去溯源,只需要追随着dts文件的include,就可以知道它们里面到底装了些什么。
以kona-v2.1(骁龙865)为例
包含以下内容
kona-v2.1.dts
kona-v2.1.dtsi
kona-v2.dtsi kona-v2.1-gpu.dtsi
kona.dtsi kona-v2-gpu.dtsi
msm-arm-smmu-kona.dtsi kona-pinctrl.dtsi kona-smp2p.dtsi kona-usb.dtsi kona-coresight.dtsi kona-sde.dtsi kona-sde-pll.dtsi msm-rdbg.dtsi kona-pm.dtsi kona-camera.dtsi kona-qupv3.dtsi kona-audio.dtsi kona-thermal.dtsi kona-vidc.dtsi kona-cvp.dtsi kona-npu.dtsi kona-gpu.dtsi msm-qvr-external.dtsi ipcc-test.dtsi