引言

这篇文章将会走进一个在我开撸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

一加和高通都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会被覆盖