前段时间偶然得到一部战损版一加6T,屏幕严重老化(怀疑是抖音水军使用)。

众所周知,一加手机对bootloader锁的限制非常宽松,于是我产生了对它爆改的想法。但是刷安卓感觉起来又有点无聊,遂尝试直接上Linux。

效果图
串口控制台

如果你手上刚好也有一台一加6T,可以点这里下载镜像刷着玩。初始密码为1234。

前置知识

安卓系统启动流程

  1. 上电当设备上电时,硬件会进行初始化。
  2. Bootloader硬件初始化、内存映射、加载内核、传递启动参数……
  3. Linux内核
  4. init进程启动

要使Bootloader引导Linux,主要就是要替换第3步和第4步。将安卓的Linux内核替换,最终唤起根文件系统中的init(systemd),从而进入Linux。

对于一加6T

Linux主线内核对部分设备有支持,而且PostMarketOS(一款移动平台的Linux发行版)对一加6T有相当完善的支持,因此可以以此为基础,制作用于刷机的镜像。

制作boot镜像

环境准备

我这里使用amd64版Ubuntu进行交叉编译,因此需要事先准备交叉编译环境。可以参考:

sudo apt install build-essential openssl pkg-config libssl-dev libncurses5-dev pkg-config minizip libelf-dev flex bison  libc6-dev libidn11-dev rsync bc liblz4-tool  
sudo apt install gcc-aarch64-linux-gnu dpkg dpkg-dev git debhelper

后续制作rootfs所需环境:

sudo apt install arch-install-scripts qemu-user-static  android-platform-system-core mkbootimg

编译内核

下载内核源码以及配置文件

PostMarketOS的wiki站中,可以找到sdm845(一加6T所使用的CPU)的主线支持,下载其中的Linux内核源码以及配置文件。

#内核源码
git clone --branch sdm845-6.16-rc2-4 --depth 1 https://gitlab.com/sdm845-mainline/linux.git
mv linux linux-sdm845-6.16-rc2-4
#配置文件
wget https://cloud.athbe.cn/f/D3Uq/sdm845.config

下载脚本对配置文件进行处理,使用处理后的配置进行编译才能生成所需要的格式。

wget https://cloud.athbe.cn/f/2MTG/check.sh
sudo chmod +x check.sh
./check.sh sdm845.config -w
mv sdm845.config linux-sdm845-6.16-rc2-4/.config #将处理结果覆盖默认配置

编辑配置。

cd linux-sdm845-6.16-rc2-4
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig

找到Device Drivers > USB support > USB Gadget Support > USB Gadget precomposed configurations > Serial Gadget (with CDC ACM and CDC OBEX support)将其设置为<*>

启用此选项后,可以实现当手机通过USB连接电脑,通过串行端口进入控制台。

退出menuconfig,开始编译

编译内核

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc)

这个过程可能会有点长,编译完成后,arch/arm64/boot下会生成vmlinuz,这是压缩后的内核,是我们所需的格式,捞出备用。

生成boot镜像

我们已经有了Linux内核,为了正常启动,还需要一个.dtb设备树文件。可以直接从pmOS的boot镜像中提取。

这里直接使用我提取的设备树。

mkdir mkboot && cd mkboot
wget https://cloud.athbe.cn/f/WEhm/OnePlus6T.dtb

将编译生成的vmlinuz复制到此目录。

cp ../linux-sdm845-6.16-rc2-4/arch/arm64/boot/vmlinuz .

vmlinuzOnePlus6T.dtb组合为一个文件,供后续使用。

cat vmlinuz OnePlus6T.dtb > kernel-dtb

Linux内核启动后,会首先唤起initrd中的init,因此我们还需要一个initrd

直接使用GitLab仓库中的生成工具。

git clone https://gitlab.com/sdm845-mainline/initrd.git
cd initrd
./build.sh
mv initrd.cpio.gz ..
cd ..

现在所需的文件已经准备完毕,但是还缺一些启动参数。可以通过解包pmOS的boot镜像获取。

下面通过解包得到的参数制作boot镜像

mkbootimg \
	--base 0x00000000 \
	--kernel_offset 0x00008000 \
	--ramdisk_offset 0x01000000 \
	--tags_offset 0x00000100 \
	--pagesize 4096 \
	--second_offset 0x00f00000 \
	--ramdisk initrd.cpio.gz \
	--cmdline "earlycon=tty0 earlyprintk root=/dev/sda17 rootfstype=ext4 rootwait=10 loglevel=3 debug rw splash" \
	--kernel kernel-dtb \
	-o boot.img

其中root为根文件系统所处的分区,对于一加6T,一般为/dev/sda17,其它设备可以通过blkid查询分区的UUID作为参数。

命令执行完毕后,得到boot.img,捞出备用。

制作rootfs

创建根文件系统

下载ubuntu-base,可以下载任意版本,这里选择了25.04

wget https://cdimage.ubuntu.com/ubuntu-base/releases/25.04/release/ubuntu-base-25.04-base-arm64.tar.gz

生成磁盘镜像并格式化为ext4,用于储存rootfs。

dd if=/dev/zero of=ubuntu.img bs=1G count=10 #分配了10G,实际上不需要这么多
mkfs.ext4 ubuntu.img
mkdir ubuntu
sudo mount ubuntu.img ubuntu
cd ubuntu
sudo tar -xpvf ../ubuntu-base-25.04-base-arm64.tar.gz

配置chroot环境

cd ..
sudo mount --bind /dev ubuntu/dev
sudo mount -t devpts devpts ubuntu/dev/pts -o gid=5,mode=620
sudo mount -t proc proc ubuntu/proc
sudo mount -t sysfs sysfs ubuntu/sys
sudo mount -t tmpfs tmpfs ubuntu/run

sudo rm -rf ubuntu/etc/resolv.conf && sudo cp /etc/resolv.conf ubuntu/etc/

sudo chroot ubuntu

基础系统配置

apt update
apt install ca-certificates dialog locales nano apt-utils -y
nano /etc/apt/sources.list  #换为国内镜像源,加快下载速度
apt update
apt upgrade -y

#生成本地化
locale-gen en_US.UTF-8
locale-gen zh_CN.UTF-8

#设置设备名
echo 'OnePlus6T' > /etc/hostname

#安装必要软件包
apt install man-db sudo openssh-server net-tools network-manager iputils-ping bash-completion kmod busybox-initramfs cpio initramfs-tools initramfs-tools-bin initramfs-tools-core linux-base netplan.io git wget ntp systemd-resolved --no-install-recommends -y

exit

安装内核模块

sudo make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-  INSTALL_MOD_PATH=~/ubuntu modules_install

sudo make ARCH=arm64 INSTALL_PATH=~/ubuntu/boot install

安装固件

这里我直接使用了从PostMarketOS的/lib/firmware中获取的固件。

wget https://cloud.athbe.cn/f/6nSr/firmware.tar.gz
sudo tar -xzvf firmware.tar.gz
sudo mv firmware ubuntu/lib/

编辑配置

sudo chroot ubuntu
nano /usr/share/initramfs-tools/hooks/qcom-firmware

脚本内容

#!/bin/sh
set -e

PREREQS=""
case $1 in
    prereqs) echo "${PREREQS}"; exit 0;;
esac

. /usr/share/initramfs-tools/hook-functions

add_firmware qcom/sdm845/oneplus6/a630_zap.mbn
add_firmware qcom/sdm845/oneplus6/ipa_fws.mbn

添加执行权限

chmod +x /usr/share/initramfs-tools/hooks/qcom-firmware

安装qrtr/rmtfs/pd-mapper/tqftpserv

https://cloud.athbe.cn/f/mJuG/qrtr%2Ctqftpserv%2Crmtfs%2Cpd-mapper.zip

下载解压所有deb文件到rootfs的/root目录下。

cd ~
dpkg -i *.deb
apt --fix-broken install
systemctl enable qrtr-ns tqftpserv rmtfs pd-mapper

安装桌面环境

可以任选,这里我选了gnome。

apt install ubuntu-desktop -y

创建新用户

adduser athbe
usermod -aG sudo athbe
usermod -aG adm athbe
usermod -aG dialout athbe
usermod -aG cdrom athbe
usermod -aG floppy athbe
usermod -aG audio athbe
usermod -aG dip athbe
usermod -aG video athbe
usermod -aG plugdev athbe

激活声音

echo 'snd-soc-tfa98xx' > /etc/modules-load.d/snd-soc-tfa98xx.conf
cd
git clone https://gitlab.com/sdm845-mainline/alsa-ucm-conf.git -b op6-earpiece
cd /usr/share/alsa
rm -rf ucm*
cp -r ~/alsa-ucm-conf/ucm* .

rm -rf /root/alsa-ucm-conf
apt-mark hold alsa-ucm-conf

几个实用服务

串口控制台

下载脚本并复制到/usr/local/bin

wget https://cloud.athbe.cn/f/7BHR/ttygs0-console.sh
chmod +x ttygs0-console.sh
mv ttygs0-console.sh /usr/local/bin/
nano /etc/systemd/system/oneplus6t-console.service

编辑服务配置。

[Unit]
Description=OnePlus6T USB Console Service
After=syslog.target
After=systemd-modules-load.service
After=systemd-udevd.service
Wants=systemd-modules-load.service
Wants=systemd-udevd.service

[Service]
Type=simple
ExecStart=/usr/local/bin/ttygs0-console.sh
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=oneplus6t-console

[Install]
WantedBy=multi-user.target

防止关机崩溃

nano /etc/systemd/system/shutdown-modem.service

内容如下。

[Unit]
Description=Poweroff modem remoteproc to prevent wlan fw crash
DefaultDependencies=no
Before=shutdown.target

[Service]
Type=oneshot
# remoteproc2 is always the modem on SDM845
ExecStart=echo stop | tee /sys/class/remoteproc/remoteproc*/state

[Install]
WantedBy=shutdown.target

启动时分配MAC地址,以使蓝牙可用

git clone https://gitlab.postmarketos.org/postmarketOS/bootmac.git
cd bootmac
mv bootmac /usr/bin/
mv bootmac-bluetooth.service /etc/systemd/system/

启用服务

systemctl enable oneplus6t-console.service shutdown-modem.service bootmac-bluetooth.service

清理缓存并退出

cat /dev/null > ~/.bash_history && history -c
exit

生成镜像

sudo umount ubuntu/{run,sys,proc,dev/pts,dev} ubuntu
img2simg ubuntu.img rootfs.img