A week ago, from what was originally started as some minor smartphone hacking, I started going down the rabbit-hole of PostmarketOS porting.

Bootloader unlock

If you take a pass at the previous post, you’ll notice that I tried all sorts of things to unlock a bootloader, despair that followed and almost giving up. The following methods all failed on me:

  1. Windows: Official MiUnlock
  2. Linux:
    1. Canny1913/miunlock
    2. RohitVerma882/termux-miunlock
    3. XiaomiToolV2
    4. bkerler/mtkclient

I think my issues were from a broken fastboot. I was almost about to give-up and try something else, until ultimately through RohitVerma882/termux-unlock I managed to get a 512 byte token. I tried writing this directly onto devinfo partition which failed, but taking a closer look at the issue comments #1 and #2, I realized that I was writing to the beginning instead of the end.

So, I quickly scripted a program in C, and wrote a binary to be copied as-is to the devinfo partition, flashed it using mtkclient and, to my surprise… it unlocked!

Never did I think a day will come when I start writing one-off tools in C, of all languages.

PostmarketOS

The previous post touched parts of building the operating-system using the OEM kernel adapted to PostmarketOS (which runs AlpineLinux) and Alpine’s packages. This build-install-image process does not require the original device to be a host, it could have been done on my laptop, or even GitHub CI (x86_64) cross-compiling into the target architecture (armv7). A successful build via pmbootstrap lead ends at the following instructions:

Flashing Information

$ pmbootstrap flasher flash_rootfs
#  Flashes the generated rootfs image to your device:
#
#  ws/chroot_native/home/pmos/rootfs/xiaomi-cereus.img
#  (NOTE: This file has a partition table, which contains /boot and /
#  subpartitions. That way we don't need to change the partition layout on your
#  device.)
#
$ pmbootstrap flasher flash_kernel
#  Flashes the kernel + initramfs to your device:
#
#  /ws/chroot_rootfs_xiaomi-cereus/boot

Since my fastboot was broken and I did not trust it enough, I chose to continue the flashing process with mtkclient.

$ pmbootstrap flasher flash_rootfs 
# [22:15:03] (native) flash rootfs image
# [22:15:05] (native) install mtkclient android-tools
# MTK Flash/Exploit Client V1.6.3 (c) B.Kerler 2018-2023
# ...
# Progress: |██████████████████████████████████████████████████| 100.0% Write (Sector 0x240000 of 0x240000, ) 8.75 MB/s.50 MB/sB/s
# Wrote /home/pmos/rootfs/xiaomi-cereus.img to sector 9797632 with sector count 112224223.
# [22:17:08] NOTE: chroot is still active (use 'pmbootstrap shutdown' as necessary)
# [22:17:08] DONE!

$ pmbootstrap flasher flash_kernel
# [22:17:12] (rootfs_xiaomi-cereus) install device-xiaomi-cereus
# [22:17:20] (rootfs_xiaomi-cereus) install postmarketos-mkinitfs
# [22:17:23] (rootfs_xiaomi-cereus) mkinitfs xiaomi-cereus
# [22:17:26] WARNING: config-xiaomi-cereus.armv7 isn't configured properly (postmarketOS), run 'pmbootstrap kconfig check' for details!
# [22:17:26] (native) flash kernel xiaomi-cereus
# [22:17:27] (native) install mtkclient android-tools
# MTK Flash/Exploit Client V1.6.3 (c) B.Kerler 2018-2023
# ....
# Progress: |██████████████████████████████████████████████████| 100.0% Write (Sector 0x503C of 0x503C, ) 0.58 MB/s
# Wrote /mnt/rootfs_xiaomi-cereus/boot/boot.img to sector 1065984 with sector count 131072.
# [22:17:29] You will get an IP automatically assigned to your USB interface shortly.
# [22:17:29] Then you can connect to your device using ssh after pmOS has booted:
# [22:17:29] ssh jerin@172.16.42.1
# [22:17:29] NOTE: If you enabled full disk encryption, you should make sure that osk-sdl has been properly configured for your device
# [22:17:29] NOTE: chroot is still active (use 'pmbootstrap shutdown' as necessary)
# [22:17:29] DONE!

Booting

The expectation is that an SSH-daemon would be available to connect via a network enabled through the USB-cable. Instructions for this were also given.

SSH daemon information

# SSH daemon is enabled (disable with --no-sshd).
# Login as 'jerin' with the password given during installation.

After flashing the built PostmarketOS image this time, and the phone started booting with the PostmarketOS bootsplash.

Loading… bootsplash. (hung)

Loading… bootsplash. (hung)

Eventually I figured I only had the bootsplash logo, with no Desktop Environment (DE). The frozen screen points to something is wrong underneath. The standard check is to go look at lsusb and dmesg.

$ lsusb
# Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
# Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
# Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
# Bus 001 Device 003: ID 06cb:00bd Synaptics, Inc. Prometheus MIS Touch Fingerprint Reader
# Bus 001 Device 002: ID 13d3:56bb IMC Networks Integrated Camera
# Bus 001 Device 074: ID 18d1:d001 Google Inc. Nexus 4 (fastboot)
# Bus 001 Device 004: ID 8087:0aaa Intel Corp. Bluetooth 9460/9560 Jefferson Peak (JfP)
# Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ dmesg 
# [26685.693978] usb 1-3: new high-speed USB device number 74 using xhci_hcd
# [26685.836233] usb 1-3: New USB device found, idVendor=18d1, idProduct=d001, bcdDevice= 4.09
# [26685.836249] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
# [26685.836254] usb 1-3: Product: Xiaomi Redmi 6
# [26685.836258] usb 1-3: Manufacturer: Xiaomi
# [26685.836261] usb 1-3: SerialNumber: postmarketOS

Since SerialNumber: postmarketOS appeared, this meant the device had booted. However, my laptop’s kernel was failing to detect it as a USB tethering device.

USB Ethernet troubles

For some reason, my laptop was not recognizing it as an RNDIS host. RNDIS host is a term associated with when a phone is connected to the computer and internet and the computer uses internet via phone - a more popular term is USB Tethering. Except in our case, there was no internet, this was just a local network from the phone so that we could drop into an SSH shell within the phone.

Initially I thought this issue was due to me manipulating udev rules for mtkclient. However, I noticed RNDIS recognition was working on my Desktop (linux-6.4.x) but not on my Laptop (linux-6.1.x-lts). The ArchLinux channel suggested upgrading kernel, which I did - and things were working from my laptop.

$ dmesg (truncated)
# [26685.693978] usb 1-3: new high-speed USB device number 74 using xhci_hcd
# [26685.836233] usb 1-3: New USB device found, idVendor=18d1, idProduct=d001, bcdDevice= 4.09
# [26685.836249] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
# [26685.836254] usb 1-3: Product: Xiaomi Redmi 6
# [26685.836258] usb 1-3: Manufacturer: Xiaomi
# [26685.836261] usb 1-3: SerialNumber: postmarketOS
# [26685.840481] rndis_host 1-3:1.0 usb0: register 'rndis_host' at usb-0000:00:14.0-3, RNDIS device, c6:1a:27:dd:a2:dc
# [26686.514605] rndis_host 1-3:1.0 enp0s20f0u3: renamed from usb0

While the issue and fix appears trivial, it took me a while to figure out the simple fix - some time went down the drain. Initially I was suspecting postmarketOS machinery failure as well.

Console

With USB network connectivity between the devices, I could now SSH into the phone.

$ ssh jerin@172.16.42.1
# Welcome to postmarketOS! o/
# 
# This distribution is based on Alpine Linux.
# First time using postmarketOS? Make sure to read the cheatsheet in the wiki:
# 
# -> https://postmarketos.org/cheatsheet
# 
# You may change this message by editing /etc/motd.
# xiaomi-cereus:~$ 

I could pretty much use the compute on the device from here. A lot of hardware (telephony, WiFi, display) all were not working. This is only console UI, so I can try on thing or the other.

Display

Now that I had a shell that I could issue commands using the laptop, I went looking for logs that could provide a clue as to what is happening. To be honest, I wasn’t entirely sure if the boot process was working because the screen still appeared to be bootlooping. Toward this I managed to wander around using different test-probles like maximum-attention and debug-shell.

I tried some variations in DEs in the created images and flashing, out of which sxmo gave me a first draw before crashing and rebooting, consistently over and over again. Other DEs were just hung on a blank screen.

SXMO (Frozen display)

SXMO (Frozen display)

XFCE (Frozen display)

XFCE (Frozen display)

Eventually after doing things with OpenRC to enable and disable stuff, I ended up with first-draws for XFCE, and even some touch-interaction responses before hang. Since this was a first-draw problem searching would lead me to:

I was ignoring content despite the headline because msm (Qualcomm?), but this was actually generic. Applying the fix fixed my display problem.

Reverse Tethering

I hoped WiFi would work so I won’t have to stay tethered to the Laptop, but the WiFi situation is pretty bad. Reverse Tethering - in my case, using laptop’s connection by the phone through the tether was turning out to be the easy option.

On the phone (guest), the instructions are to issue the following.

route add default gw 172.16.42.2

# Make the above change permanent.
echo 'route add default gw 172.16.42.2' | sudo tee /etc/local.d/usb_internet.start
chmod +x /etc/local.d/usb_internet.start

# Manually add nameserver
echo nameserver 1.1.1.1 | sudo tee /etc/resolv.conf

The wiki suggests it’s possible to redirect output, but I had to issue sudo tee as user.

For my archlinux on laptop (host), I had to issue the following:

iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -s 172.16.42.0/24 -j ACCEPT
iptables -A POSTROUTING -t nat -j MASQUERADE -s 172.16.42.0/24
iptables-save 

Desktop Environment

With this, I had internet, and could try and swap out Desktop Environments without having to flash over and over again. One could use Category:Interfaces as a start-point. Quick status updates on these are:

  • GNOME Mobile: fail
  • KDE Plasma Mobile: fail
  • sxmo: Works, unusable.
  • XFCE4: Works, usable.

I haven’t tried much further, just trying out applications and other things on top with XFCE4 for now. I saw a few videos of patched GNOME Mobile shells, which appear nice, and also Phosh. There is an on-screen keyboard (bit ugly). Applications are running.

XFCE Screenshot (clean)

XFCE Screenshot (clean)

XFCE Screenshot (apps)

XFCE Screenshot (apps)

Thoughts and next steps

While android is still running Linux under the hood, pure Linux on the phone still has a long way to go. It’s really hard to support the fragmented space of devices, if I were to guess why. Most drivers for specialized hardware is in android userland and proprietary - to the point reverse engineering is the favourable option. It will be a while before Linux on the phone takes off. Even if it happens, it’s unlikely the ecosystem of apps that exists on Apple or Android or Windows can be matched.

I’m not sure if there’s much to gain by mainlining kernels for old phones at this stage, but poking in this space, contributing one or the other small patches at the bare minimum scratches an itch to hack and tinker. I have initialized a wiki-page for my phone - Xiaomi_Redmi_6_(xiaomi-cereus). I have the pmaports diff ready at jerinphilip/pmaports#1, and will slowly work towards getting the port into the main repository and in time hopefully further features working.

Acknowledgements

Two PostmarketOS developers/enthusiasts - @justsoup and @hexaheximal helped a lot during the course of porting. It’s unlikely I would have made progress as fast as I could without these two. I plan to contribute to some their efforts of mainlining MT6765 series of chips.