Since the last post about running postmarketOS Linux on iPhone 7, I was finally able to mount and run larger and persistent system images from the iPhone system memory. Therefore I used the same technique Corellium was using in their Android build for the iPhone 7. Further, ephemeral write support for postmarketOS is achieved by using OverlayFS.

As you can see in the image above, the Linux distribution is now able to launch every sort of graphical window manager, for example Weston.

Now if you want to try this on your own phone, here’s a complete new step by step guide which should work on most Linux desktops.

Preparing postmarketOS image


Let’s start with compiling the base image using the postmarketOS utility pmbootstrap.

pmbootstrap init
# Work path [/home/onny/.local/var/pmbootstrap]
# Vendor: qemu
# Device codename: aarch64
# Kernel: virt
# User interface: weston
pmbootstrap install

During the initialization, you can leave most of the variables as they are. As an example we’re choosing Weston as the user interface. After installation we have to change a configuration and run the install process again.

pmbootstrap chroot -r
# vi /etc/xdg/weston/weston.ini # change one variable
# [...]
# backend=fbdev-backend.so
# [...]
pmbootstrap install

We have to extract the initramfs and add our custom filesystem mounting procedure into the init script.

pmbootstrap initfs extract
[...]
mount_root-partition

/bin/mkdir -p /mnt/apfs /mnt/ro /mnt/rw
/bin/mount -t apfs -o ro,relatime,vol=5 /dev/nvme0n1p1 /mnt/apfs
/sbin/losetup /dev/loop0 /mnt/apfs/qemu-aarch64.img -o 60817408 -r
/bin/mount -t ext4 -o ro /dev/loop0 /mnt/ro
/bin/mount -t tmpfs tmpfs /mnt/rw
/bin/mkdir -p /mnt/rw/data /mnt/rw/work
/bin/mkdir -p /sysroot
/bin/mount -t overlay -o lowerdir=/mnt/ro,upperdir=/mnt/rw/data,workdir=/mnt/rw/work overlay /sysroot

init="/sbin/init"
[...]

There are two variables in the code snippet above. First there is the parameter vol=5 which specifies the target APFS volume we’ll create later on. If you already created more custom volumes on your phone, this value is probably higher. Secondly losetup specifies an offset -o 60817408 which represents the offset in bytes for the ext4 system partition inside the image. You can calculate this offset by multiplying sector size and start sector using fdisk.

Recompress the initramfs for the kernel.

cd ~/.local/var/pmbootstrap/chroot_rootfs_qemu-aarch64/tmp/initfs-extracted/
sh -c "find . | cpio  --quiet -o -H newc | gzip -9 > /tmp/ramdisk.cpio.gz"

Compiling the kernel with custom ramdisk


The following part is similar to the old guide but this time we’re using the initramfs image of pmbootstrap directly.

pacman -S aarch64-linux-gnu-gcc 
cd /tmp
git clone https://github.com/corellium/linux-sandcastle.git
cd linux-sandcastle
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
make hx_h9p_defconfig
cp /tmp/ramdisk.cpio.gz .
make -j4
./dtbpack.sh
lzma -z --stdout arch/arm64/boot/Image > arch/arm64/boot/Image.lzma

Flashing system image and kernel


Be careful, the following steps are considered safe to use but this is still experimental and could brick your phone. Use it at your own risk!

This is not “flashing” in the traditional sense but now we’re going to use the bootrom exploit checkra1n to gain ssh root access on the phone. Put your phone into DFU mode and run following command:

checkra1n -cE
iproxy 2222 222 # leave this running while accessing via ssh
sshpass -p "alpine" ssh -p2222 root@localhost

Inside the iPhone root shell, we’re going to create a new APFS volume and mounting it. You have to do these steps only once, just remount the partition if you want to delete or overwrite the existing system image.

newfs_apfs -A -v postmarketOS -e /dev/disk0s1
mkdir -p /tmp/mnt
mount -t apfs /dev/disk0s1s6 /tmp/mnt

The volume /dev/disk0s1s6 should be the new “postmarketOS” volume. You can check this with /System/Library/Filesystems/apfs.fs/apfs.util -p /dev/disk0s1s6.

Now we can transfer the system image inside the new volume using scp.

sshpass -p "alpine"  scp -P2222 -v ~/.local/var/pmbootstrap/chroot_native/home/pmos/rootfs/qemu-aarch64.img root@localhost:/tmp/mnt/

After that, unmount the partition on the iPhone and put it back into DFU mode. The following commands will run the Linux kernel and trigger the boot process up into our graphical user session :)

cd /tmp
git clone https://github.com/corellium/projectsandcastle
cd projectsandcastle/loader
make
checkra1n -cpE
./load-linux ../../linux-sandcastle/arch/arm64/boot/Image.lzma ../../linux-sandcastle/dtbpack

If you want to reboot into your postmarketOS system, you jsut have to rerun the last two commands. Changes made while running the system will be lost on reboot and are not yet persistent.

Shell access via USB serial


Since all this is in development state, it is convenient to have serial/shell access to the running system. Therefore you should add CONFIG_USB_G_SERIAL to the kernel configuration and append following line the the inittab file on the postmarketOS target root filesystem.

ttyGS0::respawn:/sbin/getty -n -l /bin/sh ttyGS0 9600 linux

During the next boot you’ll be able to access your phone, for example with minicom, at /dev/ttyACM0.

To be continued


From here on it should be easy to enable Bluetooth and Wifi since it is already implemented by Corellium into their custom Kernel.

Drop me a mail if you have further question or want to support this project.

Update 21/07: This post got featured on the postmarketOS podcast episode 7 (archive).

💬 Are you interested in our work or have some questions? Join us in our public Signal chat pi crew 👋
🪙 If you like our work or want to supprot us, you can donate MobileCoins to our address.