引言
这篇文章将会走进一个在我开撸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
再来一些小细节
dtb和dtbo文件是同一种东西
- 编译出来的dtb和dtbo文件的编码格式是完全一致的,它们仅仅只是后缀不一样
可以懒得编译dtbo
- 众所周知,开启
CONFIG_BUILD_ARM64_DT_OVERLAY
后,编译体系会编译dtb和dtbo,并将dtb打包进入内核(dtbo就没用了。。),那么,我能不能节省一点cpu,不编译dtbo呢?
可以的,只需要以编译dtb的方式(也就是老的,只编译dtb的方式),dtb-y+=进dtbo对应的base即可 - 但是,你以为就这么简单么?
CONFIG_BUILD_ARM64_DT_OVERLAY
的作用并不止于控制dtbo的编译,它还会控制dtc是否编译kernel dtb的symbol nodes,没有这些symbol nodes,dtbo将无法正常对kernel dtb进行覆盖(导致开机fastboot
https://source.android.com/devices/architecture/dto/compile - 所以,如果要懒得编译dtbo,该怎么做?
你可以选择保持CONFIG_BUILD_ARM64_DT_OVERLAY
为打开状态,然后把对应dtbo-y
的东西全部改成dtb-y += <base>.dtb
你也可以像我一样操作。。
https://github.com/xzr467706992/android_kernel_oneplus_sm8250/commit/88c940c190fa1a9fdf573127ec4e5ce1ea687ac1
https://github.com/xzr467706992/android_kernel_oneplus_sm8250/commit/205f3dddb51691604dc3c17e3575da00c211470a
https://github.com/xzr467706992/android_kernel_oneplus_sm8250/commit/adf606df4eb2734e5ee7849094bcd94790f09590
一加和高通都TM是憨批- 上方我已经陈述了睾贵的溯源理论,也就是include的概念那么请问一加和高通工程师为什么要同时把kona.dtb kona-v2.dtb kona-v2.1.dtb作为base呢?https://github.com/OnePlusOSS/android_kernel_oneplus_sm8250/blob/cad09e061ef6cf689a4a1e54d27562e0f042236a/arch/arm64/boot/dts/vendor/qcom/Makefile#L32很显然,发行版的865就是kona-v2.1,而kona-v2.1.dts在溯源下已经include了kona和kona-v2独立编译kona和kona-v2完全就是多此一举你tm是不是闲的蛋疼,看boot分区太大了得多往里面装点东西??测试:删除kona和kona-v2,一切正常(不知道是我理解有误还是高通和一加都是憨批)
据说没了这个,在内核放在ROM里一起跑的时候无法正常开机
一点点猜想?
上一楼已经阐述了CONFIG_BUILD_ARM64_DT_OVERLAY
对于kernel dtb的作用那么现在还存在一个疑点,那就是关闭CONFIG_BUILD_ARM64_DT_OVERLAY
后开机直接fastboot的原因,究竟是dtbo无法正常覆盖造成报错,还是无法合并造成的dtb不完整?如果是无法合并造成dtb不完整,这是否意味着我们可以通过不编译symbol nodes来屏蔽dtbo分区?
在小米的内核源码中,我们可以看到这个奇怪的else逻辑https://github.com/LineageOS/android_kernel_xiaomi_sdm845/blob/f69c1100e2ce60e91f5ccae56ad4f9e1974f0fdc/arch/arm64/boot/dts/qcom/Makefile#L69
它是负责CONFIG_BUILD_ARM64_DT_OVERLAY
关闭情况下的kernel dtb编译可以看到,它将原来属于dtbo的部分全部编译为了kernel dtb??
这是不是在暗示用这种方式使dtbo分区不加载的可行性?
皮猪:有些机子不用dtbo,所以还留着
但是845平台真的还有不用dtbo的机子么?
有没有人来实验下?
皮猪:小米的845只有mix3用了dtbo
小8测试,照样开机fastboot,看来是覆盖出错导致的,无法用这种思路屏蔽dtbo分区
皮猪:还是可以把dtbo全部编译进kernel,实现wipe掉dtbo分区照样开机的
(但是还要保持CONFIG_BUILD_ARM64_DT_OVERLAY
的开启状态
(如果不wipe掉dtbo分区 kernel dtb会被覆盖
两年半后的几个修正:
内核 Image 与 dtb 的关系发生了变化 的 原因,不是一加的特性,而是 boot header v2 的特性。
在 boot header v1 中,dtb 是 append 在 kernel image 后面的,而到了 v2 ,它有了独立的存放位置。
https://source.android.com/docs/core/architecture/bootloader/boot-image-header
出现上面的现象,很大程度是因为 anykernel / magiskboot 的解包方式,magiskboot 会将 v1 header 解包为 appended dtb ,但将 v2 header 解包为独立的 dtb 文件,打包时也是同理,这才有了上面的现象。
屏蔽 DTBO 是可行的,但其依赖于 bootloader 的“隐藏功能”,需要特定的 boardid 才能激活
https://github.com/kdrag0n/proton_zf6/commit/fe8cfc78ed7a087ca4ac519ffa4e1e5f227dbd20
实测,即使和 ROM 一起编译,移除掉 kona.dtsi 和 kona-v2.dtsi 也不会影响开机,高通和一加确实是憨批。