Past Phone + Present Power: Kernel 6.8 & Debian 13 on Redmi 2
August 26th, 2024

[Fun.001] 2024.03

红米 2

一台 2015 年初发布的手机,售价 699 元,2024 年居然还没有被遗忘?

红米 2 外观
红米 2 外观

硬实力上,红米 2 在当时就不突出。它是闻泰科技 ODM 的产品,从设计到制造都由闻泰完成,配备高通骁龙 410 SoC (MSM8916) ,1GB 运行内存,8GB 存储,4.7 寸 720P 屏幕 (312 ppi) 。MSM8916 采用 28 nm 工艺,CPU 为 4 核 1.2 GHz ARM Cortex-A53,上市之初定位便是中低端,与 2023 年的骁龙旗舰相比性能就只有可怜的 1/10 不到了。作为手机,红米 2 在 2024 年早已没有实用价值,大量红米 2 在闲鱼上的售价仅在 50-100 元之间。

骁龙 410 (msm8916)
骁龙 410 (msm8916)

软实力它却很强。红米 2 有非常丰富的第三方 Android 刷机包,出厂搭载 Android 4.4 的它能刷到 Android 10 的 Lineage OS 17.1 (Kernel Version 3.10) 。当它的性能已经不足以支撑在 Android 中多做什么时,它还可以运行接近最新主线的 Linux Kernel 和 Debian, Ubuntu 等正儿八经的 Linux 发行版。可能是得益于高通官方基于 MSM8916 推出了支持 Ubuntu Linux 的 DragonBoard 410c 开发板,也得益于后续开源社区和组织的努力,MSM8916的主线内核功能已经比较完善,UART、USB、Storage (eMMC/SD card) 、WiFi/Bluetooth、GPU、Display (需要 panel 驱动)、Audio、Buttons、Vibration、Modem (SMS, voice calls with audio, mobile data) 等都得到了支持。

DragonBoard 410c
DragonBoard 410c

有了完善的 Linux 支持之后,红米 2 作为一个嵌入式 Linux 开发平台瞬间焕发新生。如果应用于只需要极少的 IO,不需要丰富的总线接口,需要利用 USB、 无线通信,甚至还恰好比较需要屏幕交互的场景,相比购买树莓派、香橙派等 Linux 开发板,手机运行 Linux 方案变得性价比极高。因此可以看到红米 2 仍具有很强的生命力,B 站上拿红米 2 做 Klipper 3D 打印上位机的案例非常丰富。同为 MSM8916 SoC 的一些低价随身 WiFi 也纷纷被装上 Linux 做小服务器。

制作过程

调试

没有 console log 将是调试的噩梦,能通过串口看 bootloader 和 kernel 的输出非常要紧,否则在屏幕没有成功点亮前就成了黑箱,没有排查空间。而红米 2 有完整的点位图和原理图可看,甚至预留了串口 TP,调试便完全不成问题了。

原理图中的串口TP
原理图中的串口TP
点位图中的串口TP
点位图中的串口TP
实物上的TP
实物上的TP

lk2nd

lk2nd 是为高通 SoC 开发的基于 Little Kernel 的二级引导程序,可以方便地引导 Linux 启动。而它本身伪装成了 Android 的 boot.img 文件,使得不必改动设备原本 bootloader 就能启动。lk2nd 提供了 fastboot 兼容,可以在电脑用 fastboot 命令实现方便的分区烧写。并且和 u-boot 类似,起到“兜底”的作用,不用担心烧进坏的镜像就彻底变砖。

项目地址:msm8916-mainline/lk2nd: Custom bootloader for Qualcomm MSM8916/MSM8226/MSM8974/... devices (github.com)

我们直接利用 Release 的 0.15.0 版本 lk2nd-msm8916.img 在原厂 fastboot 中通过以下命令刷入 lk2nd,开机时亮屏后按音量下键可以进入 lk2nd 的 fastboot。

fastboot flash:raw boot lk2nd-msm8916.img
开发者将 lk2nd 运行在各种设备上
开发者将 lk2nd 运行在各种设备上

运行lk2nd后,烧写便可以使用下面的命令:

fastboot flash boot boot.img
fastboot flash userdata rootfs.img

内核

msm8916-mainline/linux 获取内核,直接编译即可

export CROSS_COMPILE=aarch64-linux-gnu-
export ARCH=arm64
make msm8916_defconfig
make menuconfig
make -j8
make deb-pkg

编译完成后会生成3部分的文件:

  1. arch/arm64/boot/Image.gz 压缩后的内核映像

  2. arch/arm64/boot/dts/qcom/msm8916-wingtech-wt88047.dtb 设备树 dtb,后续需要附在内核映像后

  3. ../linux-headers-6.7.4-msm8916-dirty_6.7.4-6_arm64.deb 和 ../linux-image-6.7.4-msm8916-dirty_6.7.4-6_arm64.deb 内核头文件和内核的 deb 包,后续需要在根文件系统中安装

将设备树 dtb,附在内核映像后

cat Image.gz msm8916-wingtech-wt88047.dtb > kernel-dtb

Debian rootfs

首先尝试利用 debootstrap 创建一个 debian 的根文件系统。由于制作所用主机为 amd64 架构,而目标设备为 arm64 架构,需要利用 debootstrap 的 —foreign 选项,并准备 qemu-aarch64-static 用于模拟 arm64 指令集。

apt-get install debootstrap qemu-user-static binfmt-support
debootstrap --arch arm64 --foreign bookworm rootfs http://mirrors.tuna.tsinghua.edu.cn/debian
cp -a /usr/bin/qemu-aarch64-static rootfs/usr/bin/qemu-aarch64-static

然后 chroot 进入刚刚制作的根文件系统,完成 debootstrap 的第二阶段、安装 kernel-image 和 kernel-header,并自由定制自己的根文件系统

mount --bind /dev rootfs/dev
mount --bind /dev/pts rootfs/dev/pts
mount --bind /proc rootfs/proc
chroot rootfs bash

/debootstrap/debootstrap --second-stage
dpkg-reconfigure locales
dpkg -i *.deb #事先拷进来的linux-headers和linux-image
apt update
apt install usbutils network-manager sudo fdisk vim nano openssh-server iputils-ping wget curl iproute2 dialog locales kmod zip unzip u-boot-tools initramfs-tools net-tools htop screenfetch phosh
adduser debian
exit

在安装新 Linux 内核包时,包管理器会调用 update-initramfs 来生成与新内核匹配的 initrd.img 文件,initrd 包含一个临时的根文件系统,运行在内存中负责初始化系统并切换到最终的根文件系统。我们需要拷贝位于 /boot 目录下的 initrd.img-xxx 文件制作进 boot.img中。

打包 rootfs.img

umount rootfs/dev/pts
umount rootfs/dev 
umount rootfs/proc
dd if=/dev/zero of=rootfs.ext4 bs=1M count=4096
mkfs.ext4 rootfs.ext4
mkdir /mnt/rootfs_dd
mount rootfs.ext4 /mnt/rootfs_dd
cp -a rootfs/. /mnt/rootfs_dd/
sync
umount /mnt/rootfs_dd/
img2simg rootfs.ext4 rootfs.img # convert to sparse image

打包 boot.img。在 kernel cmdline 中,通过 UUID 指定 rootfs 分区较为保险,UUID可以通过file mkfs.ext4命令查看

mkbootimg --base 0x80000000 \
        --kernel_offset 0x00080000 \
        --ramdisk_offset 0x02000000 \
        --tags_offset 0x01e00000 \
        --pagesize 2048 \
        --second_offset 0x00f00000 \
        --ramdisk initrd.img \
        --cmdline "earlycon console=tty0 console=ttyMSM0,115200 root=UUID=b0167571-46ab-432c-9923-46772affcb75 rw loglevel=7"\
        --kernel kernel-dtb -o boot.img
运行 debian
运行 debian

Mobian rootfs

自制的 debian rootfs 可以启动,但图形界面中缺少的东西实在太多,因此转向修改其他机型的 mobian rootfs。mobian 官网下载目前前最新的镜像,得到 mobian-qcom-phosh-20240211.rootfs.img,主要安装上 linux-headers 和 linux-image 即可。

simg2img mobian-qcom-phosh-20240211.rootfs.img  mobian-rootfs.img
mount mobian-rootfs.img /mnt/rootfs_dd/
sudo mount --bind /proc /mnt/rootfs_dd/proc
sudo mount --bind /dev /mnt/rootfs_dd/dev
sudo mount --bind /dev/pts /mnt/rootfs_dd/dev/pts
sudo mount --bind /sys /mnt/rootfs_dd/sys
cp linux-headers-6.7.4-msm8916-dirty_6.7.4-6_arm64.deb /mnt/rootfs_dd/tmp/
cp linux-image-6.7.4-msm8916-dirty_6.7.4-6_arm64.deb /mnt/rootfs_dd/tmp/
sudo chroot /mnt/rootfs_dd/
dpkg-reconfigure locales
apt remove qcom-support
dpkg -l | grep -E "linux-headers|linux-image" |awk '{print $2}'|xargs dpkg -P
cd /tmp
dpkg -i *.deb
exit

同样的流程打包 rootfs.img 和 boot.img,烧录即可。

启动后会发现无线不工作,还有屏幕不显示 GUI 但有终端显示的问题。究其原因是缺少了私有的 firmware, 这个部分也容易解决,从其他同机型 rootfs 镜像中直接拷贝即可。GPU Firmware 文件为 a300_pm4.fw 和 a300_pfp.fw, 无线部分有一系列 .mbn 文件和 .bxx 文件。启动后,网络和 GUI 也得以工作。

运行 mobian
运行 mobian

真正的主线

msm8916-mainline/linux 这份内核虽然很接近主线,却还不是真正的主线内核 torvalds/linux, 有很多没有合并到主线的修改,版本也略有落后。那么 torvalds/linux 能否跑起来呢,有问题的话能否自行解决修复呢。

通过 git 镜像获取,并安装一些必要的包

git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git
git checkout v6.8.0
apt update
apt install -y gcc make gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu libncurses5-dev build-essential pkg-config libc6-dev bison flex libelf-dev  lz4 qemu-user-static bc libssl-dev debhelper

主线的内核有 wt88047 的设备树,首先尝试根据msm8916-mainline/linux项目的 msm8916_defconfig 配置内核,编译出一份内核,尝试启动,发现串口能够进入终端,但是屏幕没有正常显示。通过对比 msm8916-mainline/linux 与同版本的 torvalds/linux 之间差距,除了大量的设备树 dts 文件添加与修改,还主要包含了:

  • 显示面板驱动 drm/panel 添加与修改

  • drm 和 dsi 部分关于启用禁用逻辑的调整

  • touchscreen, pmic 等外围设备的驱动添加

  • 高通 SoC 外设驱动和配置调整,包括 qdsp6, memshare, cpuidle等

着重添加好面板驱动和显示部分的逻辑,编译内核,用此内核启动后便可以正常看到phosh界面了。

6.8.0-rc6 内核运行
6.8.0-rc6 内核运行

总结

在前人的努力下,在红米 2 上跑起一个比较新的 Linux 系统变得异常轻松,离主线非常近,一切驱动、设备树、config 都已经就绪,只要编译就行,甚至连报错都不带报的。

手机SoC的快速迭代实在让人感叹,手机芯片性能已经远甩开嵌入式 Linux 开发中常用的芯片。一个 RK3399 就传了多少年,才有了 RK3588,另外即使是最新的树莓派性能也差强人意,对比一下飞速进步的手机芯片,仿佛不在一个世界。开源的力量也令人倾佩,手机厂商对于手机系统的更新精力有限,老机型没有新机型更新积极几乎必然。更别提支持周期结束之后,不负优化、计划报废就不错了。这在商业上无可厚非。但这也使得手机即使性能硬实力没有太落后,也很难不提早迎来生命的终结。而开源和社区的力量似乎提供了一条让手机发挥更大价值的道路,就如红米 2、一加 6T 等至今依然活跃的老机型,不仅作为手机的生命周期得到延长,甚至还开拓了更加广阔的应用场景,这何尝不是一种更高级的“环保”呢。好兆头是,以往芯片公司们常常将资料藏着掖着,而似乎一些公司已在开源方面有了一些动作,骁龙 845、865 等处理器都有了较好的主线内核支持,FOSDEM 2024 中也提到 Linaro 对于高通新旗舰芯片主线支持得越来越快,开放的美好未来似乎就在眼前。

参考资料

Subscribe to Lithiumee
Receive the latest updates directly to your inbox.
Nft graphic
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.
More from Lithiumee

Skeleton

Skeleton

Skeleton