在安卓手机上安装 Linux 系统 :小米 8 SE
最近看到了这个视频 成功把ubuntu桌面版装到了手机上 BV1WjKfzMEG5,我就想到我还有一台闲置的小米 8 SE,就想尝试一下。
UP主也是个大好人,写了而一篇很详细的教程说明如何制作:将Ubuntu安装到安卓手机(OnePlus6T)中
我大概整理了一下,文件是这样分布的:
flowchart TD
kernel --> boot{boot.img}
device-tree[Device Tree, aka DTB] --> boot
initrd[Init RAM Disk, aka InitRD] --> boot
cmd(cmdline) --inject--> boot
通过mkbootimg工具打包boot.img,打包的时候传入偏移量、cmdline等参数。刷入手机的boot分区,并清空dtbo分区,强制设备从boot中加载设备树。
bootloader会加载boot.img,并引导启动linux内核启动,linux内核会加载initrd(一个很小的ram disk,就是一堆shell脚本。其会从cmdline中获取参数,引导启动最终的rootfs)。
于是我立刻就按照教程操作了:
第一天失败的尝试
首先,我逛了一圈postmarket os,很可惜,小米 8 SE 没有任何维护,不能直接套用上面的教程(主要问题还是没有设备树)。
但是我找到了一个很接近的设备 小米9 Lite 。毕竟都是同一个SOC,并且还是一家公司的,应该不会有太大的差异。
这两款设备都是相同的SOC 高通骁龙710 https://wiki.postmarketos.org/wiki/Qualcomm_Snapdragon_710_(SDM710)
根据网页上的描述,我找到了其主线linux 内核:https://gitlab.com/sdm670-mainline/linux 多亏了sdm845生态的繁荣,让处于同一代架构的sdm710也吃上了残羹,不然可能根本找不到可用的主线内核。
我急忙将linux, initrd 克隆到本地,开始编译。分析原厂boot.img获得偏移量参数。然后新内核以及设备树打包成boot.img。
为了偷懒,我写了一个脚本来干这个事情,在pwd下放置initrd(我用的sdm845仓库里面的,这个是通用的)、压缩内核、设备树:
1 | cd initrd/ |
然而不出意外,根本启不动。

小插曲: 到了晚上,我实在弄不出来了,就把这活丢给openclaw(minimax 2.5)。结果openclaw给我了一个不到3M的boot.img,能用就有鬼了
有点苗头的第二天
当我再次点开小米9 Lite 的介绍页时,末尾的uboot吸引了我
EFI booting using U-Boot is also possible with our tauchgang repo. See section below for details.
我急忙根据作者的guide编译uboot,但是编译失败,提示找不到设备树文件。仔细一看,发现作者的patch还没有合并进主线,因此手动应用了patch:https://gitlab.postmarketos.org/tauchgang/u-boot/-/merge_requests/1#note_535204
当我将编译好的uboot镜像烧录到手机上时,本来不抱任何希望地,却发现uboot居然显示了ui,虽然全是报错。但这已经是非常大的一步了,至少能显示了。

不难发现,报错主要集中在UFS设备的问题上。我急忙去找到了小米8SE第三方ROM维护者的内核仓库:https://github.com/Rocky7842/android_kernel_xiaomi_sdm710
尝试移植设备树(安卓内核和通用内核在设备树上有细微差别,不能直接用),当然,这个问题就交给AI去做了,但一连弄了几个小时,花了6$ Token,也没能解决这个问题。好几款AI都认为是UFS的通道数设置不正确,我决定上网搜索相关设备详情。——结果让我大吃一惊:这款手机用的根本不是UFS,粮厂竟然偷工减料地在当时的中端机上使用eMMC!
当然,UFS报错的问题也算解决了:移除UFS相关代码,启用eMMC0(internal)支持,移除eMMC1(sdcard)。
uboot成功点亮,并且通过USB串口(115200 频率)链接电脑,能正常使用uboot shell。

不知道为什么,如果电脑中安装了安卓驱动,windows就会认为其是bootloader interface,不显示COM口。将安卓驱动卸载后,windows才会将其显示为串口设备。
可以通过uboot来启动linux系统,但我看着有点麻烦,不如直接打包内核在boot中省心,就将uboot告一段落了。
启动系统与奇怪的错误
uboot与linux kernel有很深的渊源,通过将uboot设备树中的修改应用在内核设备树中,成功让linux显示出了一点点画面,虽然很快就死掉了。

但这也很不错了,至少内核能显示出一点画面了。
由于上述提到的Mi 9 Lite已经能成功启动,我就打算拿Mi 9 Lite对应的kernel config去编译试试。追寻dev的提交细节,我在这里找到了对应的kernel config: https://gitlab.postmarketos.org/postmarketOS/pmaports/-/tree/master/device/community/linux-postmarketos-qcom-sdm670?ref_type=heads
使用了这个kernel config (config-postmarketos-qcom-sdm670.aarch64),成功让内核存活地更久了:

分析log,发现内核都开始启动init进程了,内核初始化都已经结束了。那么这就很有可能是init脚本的问题了,我让ai分析了一下,说我的init脚本不支持GUID指定功能,也就是不能指定rootfs分区的GUID。于是我就改成了传统的指定rootfs设备:/dev/mmcblk0p79 (对应system分区)
当然,我提前往system分区写入了rootfs(我偷懒直接用的一加6T作者提供的无GUI版本),也是成功进入了系统。
我本来想使用userdata(mmcblk0p81)分区的,赖何fastboot总会在这个过程中卡住
后来发现是分区格式不匹配导致的,userdata默认采用f2fs格式,当然也就无法刷入ext4格式的镜像。
接下来,我尝试刷入GUI版本的系统,发现system分区大小只有3G,非常小。为了不破坏分区大小,我只能选择将rootfs刷入userdata分区。我本想打包一个f2fs格式的镜像,但是我的wsl内核不支持f2fs文件系统,我转念一想能不能将userdata格式化为ext4格式,发现还很简单:
1 | fastboot format userdata:ext4 |
因此就很容易将超过3G的rootfs刷入userdata分区了,同时修改boot.img中的cmdline参数,指定rootfs设备为/dev/mmcblk0p81。


Bug
但是截至目前,还有很多东西不工作:
USB
根据SOC页面的描述,当前供电存在缺陷,需要手动切换host模式并使用带有供电的hub才能用。
Mode switching is possible if done manually:
echo device > /sys/kernel/debug/usb/a600000.usb/mode for Gadget mode (default)
echo host > /sys/kernel/debug/usb/a600000.usb/mode for host mode
Automatic switching currently doesn't work. If you pipe "auto" into sysfs, your device will be stuck in a loop of switching between modes.
PMIC is missing logic to enable power output, so host mode works only with powered devices (such as hubs or docks).
Only USB2.0 speeds have been tested due to vendors cheaping out.
我直接在init脚本中执行了运行在host模式的命令,也使用了带有供电的hub,但是我始终没能让USB工作。
触摸屏
看了下安卓那边的设备树,这块设备采用的是意法半导体的触控(st,fts),参考了安卓设备树与其他使用了这家触控芯片的linux设备树,并且在内核中启用了驱动CONFIG_TOUCHSCREEN_STMFTS=y,也没能正常将触摸屏驱动起来。
使用同一触控的linux设备树就非常干净:
1 | &hsi2c_5 { |
相比而言,安卓设备树就夹带了很多私货:
1 | &qupv3_se9_i2c { |
这两个bug结合在一起,使得我几乎没有任何输入设备,无法操控手机(音量键、电源键还是能用的)





