Kshim - 简介篇
本文最后更新于 2024年11月1日 下午
前情提要
搞过WOA-Project UEFI库的都知道,他们使用了一个叫Bootshim的东西,用来伪装Linux内核头部,并把UEFI FD拷贝到MemoryMap中的UEFI FD保留区域里面。
在前几年,Gustave Monce在SurfaceDuo1上面整了个花活->通过检测屏幕开合状态选择启动Linux内核(安卓)还是Windows,跳转代码写在UEFI的PrePei里面,uefi、bootshim和内核打包成一个kernel,如图:
据Gus所说,这样的打包方式会导致keymaster爆炸,因为实际的Linux内核被“移动”了,位置对不上,于是在几个月之后提出了第二版方案:SDKernelPatcher,
这个方案更改了打包和启动模式,将ShellCode插入到“安卓内核头部”的空闲空间中,并在ShellCode中判断屏幕开合状态,跳转到UEFI或者Linux,
于是我在今年年初的时候整了个复刻,使用C语言重构了Gus的Patcher,以便降低阅读难度和提高可移植性,项目为DualBootKernelPatcher,在Gus的Patcher中ShellCode以二进制编码,不方便阅读和后期修改,这里将ShellCode分离出来,直接使用汇编进行编程,稍微提高了一点可移植性。
于是,新的问题又来了:
1. Linux的头部空间毕竟大小有限,汇编也塞不了多少
2. 汇编难写的要死,有时候修问题修半天还是定位不到
3. 只能读取TLMM GPIO的状态,但是每个设备都有的音量键是PMIC GPIO,这就意味着设备必须要有一个使用TLMM GPIO的按键或者霍尔传感器之类的东西,这可就难办了,对于一加来说,三段式按键可以切换,对于部分小米还有AI键可以当切换键使,对于游戏掌机也是有很多按键可用切换,对于平板/旗舰机可以使用霍尔传感器检测盖子。。。但是,这也太不通用了,普通机器压根没办法做多启动切换吧。
所以,我打算对这个第二版方案进行一些改动,以大幅增加通用性,这个项目暂时命名为Kshim.
目的
Kshim的目的很简单,在启动的时候留出1s左右的时间显示图形界面,使用音量键、电源键、触摸屏、或者其他输入设备选择启动路径,且启动项可拓展,从而优雅的实现启动路径切换。
方案
打包方案
对第二版的打包方案做一点小小的修改:
主要改动:
- 将原来的ShellCode修改为KshimLoader,将Kshim放在安卓内核的后面,这样就可以解决头部空间不足的大小问题。
- UEFI FD 后面添加可拓展内核,从而增加可拓展性,其实第二版也可以做这个方案,懒得没做。
启动路径
ABL会从UFS/EMMC加载boot.img
并解包,把我们重新打包之后的FakeKernel
放在memorymap的kernel区域,再跳转过去启动
-> 由于内核的第一个跳转指令被修改,cpu开始执行KshimLoader,即一段ShellCode,
-> KshimLoader计算出Kshim地址并跳转到Kshim运行,
-> Kshim加载GPIO、BUS等外设驱动,启动GUI,等待用户输入,或等待超时默认值,启动Linux/Android或UEFI或2nd Kernel、3rd Kernel等。
释义
- ABL: Application Bootloader 高通的安卓内核加载器,运行在EL1,以非UEFI的方式加载内核,令人困惑。
- XBL: Extensible Bootloader 高通的可拓展启动加载器,其主要部分是UEFI。
- BootChain: 启动链条,一般用来描述系统是如何启动的。
- FakeKernel: 假内核,我这里用来指代被修改以欺骗ABL加载的安卓内核,即添加了ShellCode、UEFI之类的安卓内核。
- Memory Map: 内存映射表,UEFI里面需要用到,用来描述一段内存给谁用,什么属性,物理上的可用内存地址范围等等。