Reproducible recipe and tooling that converts a screenless, battery-less General Mobile GM 8 motherboard (GM8_sprout) into an unattended 64-bit Alpine Linux compute node with USB RNDIS networking, root SSH, Qualcomm WCNSS Wi-Fi, working apk package management, and optional USB Ethernet support.
Because the board has no display and no battery (powered at 4.2 V via a bench supply on the battery terminals), all unlocking, partition surgery, and recovery are performed headlessly over Qualcomm EDL (9008), fastboot, USB, and SSH.
The Alpine userland runs on the downstream 3.18 kernel using a system-as-root layout on system_a, while the stock Android 9 image is preserved untouched on system_b as an instant A/B rollback fallback.
Hardware Specifications
| Component | Specification | Details |
|---|---|---|
| Model | General Mobile GM 8 (GM8_sprout) |
Android One A/B partition scheme (no vbmeta) |
| SoC | Qualcomm MSM8940 (Snapdragon 435) | Octa-core ARM Cortex-A53 (aarch64) |
| RAM & Storage | 3 GB LPDDR3 / 32 GB eMMC | Dual-slot (_a / _b) GPT layout |
| Wireless | Qualcomm WCNSS (Pronto) | 802.11b/g/n Wi-Fi with automatic AP association |
| Power | 4.2 V Bench PSU | Direct feed to battery terminals (no battery fitted) |
| Bootloader | LK BOOT.BF.3.3 |
Unlocked headlessly via devinfo partition patch |
Hardware & Feature Support Status
| Feature | State | Notes |
|---|---|---|
| Alpine Linux Boot | Working | Alpine 3.19.9 aarch64 on system_a with OpenRC (gm8-mark-boot-successful, gm8-clock-floor) |
| USB Networking | Working | RNDIS 18d1:d002, dedicated node subnet 172.16.43.1/24 + pinned host MAC 02:67:38:00:00:02 |
| SSH Access | Working | OpenSSH root key authentication over USB (172.16.43.1) and Wi-Fi |
| Root Filesystem | Working | ext4 on system_a, remounted read-write by OpenRC |
| Wi-Fi (WCNSS) | Working | Pronto driver loaded, live AP scans, wpa_supplicant + DHCP on boot |
Package Manager (apk) |
Working | HTTPS apk update & package installation verified across reboots |
| USB Ethernet | Working | SR9700/9702 USB Ethernet adapters supported with patched boot_a kernel |
| A/B Android Fallback | Working | Stock Android 9.0 preserved on system_b |
| Button-Free EDL | Working | Full partition read/write via Firehose (05c6:9008) |
Key Reverse-Engineering Discoveries
- Headless Bootloader Unlock via
devinfo(0x10):- Disassembly of the LK (
aboot) binary revealed that signature verification is skipped whenever the 32-bit word at offset0x10of thedevinfopartition is non-zero ("Device is unlocked! Skipping verification..."). - Writing a patched
devinfovia EDL unlocksfastbootand allows custom boot images without needing a screen to confirm an on-device prompt.
- Disassembly of the LK (
- Orange-State ADB Auto-Authorization:
- With
devinfounlocked, the stock user-build ROM enumerates ADB in an already-authorized state (adb devices → device) without requiring an RSA prompt tap on a missing screen.
- With
- Surgical
boot.imgSplicing (boot_splice.py) vs. AIK:- Standard Android Image Kitchen (AIK) repacks zero out header fields (
unused@0x2Candid[]) that this device's LK bootloader checks, causing silent no-boots.boot_splice.pysurgically splices kernel/ramdisk payloads into the stock header so LK boots them reliably.
- Standard Android Image Kitchen (AIK) repacks zero out header fields (
- Surviving LK BCB & 7-Boot A/B Slot Retry Counter Decay (
gm8-mark-boot-successful):- If the Bootloader Control Block (
miscpartition) containsbootonce-bootloader, or if the A/B slot retry counter in GPT attributes decays to zero after ~7 boots without Android'sbootctl mark-boot-successfulrunning, LK marks both slots unbootable (current-slot:INVALID,slot-unbootable:a:Yes) and traps the board infastboot. - Zeroing
miscover EDL recovers the board, and ourgm8-mark-boot-successfulOpenRC service runssgdiskon every boot to set GPT attribute bit 54 ("successful") on the activeboot_<slot>partition so the retry counter never decays again.
- If the Bootloader Control Block (
- Dedicated USB Subnet (
172.16.43.1/24), Pinned Host MAC & 1970 RTC Clock Floor:- The USB RNDIS gadget pins a deterministic host-side MAC address (
02:67:38:00:00:02) and uses172.16.43.1/24(host172.16.43.2/24viasetup_gm8_usb_network.sh) so the GM 8 can stay plugged in simultaneously alongside postmarketOS nodes on172.16.42.0/24. - Because the battery-less board powers up with its RTC reset to
1970-01-01, thegm8-clock-floorservice advances the system clock to at least the rootfs build timestamp before networking starts, preventing TLS certificate validation failures during earlyapk updateruns before NTP syncs.
- The USB RNDIS gadget pins a deterministic host-side MAC address (
Build & Flash Workflow
# 1. Build the reproducible Alpine aarch64 system-as-root ext4 image
./pmos/build_gm8_helpers.sh
./pmos/build_gm8_root_tar.sh
./make_gm8_system_sar.sh
# Verified gm8_alpine_system_sar.img SHA-256:
# 696199acd31a6cad5d07a2454429ea12ad798a55012c3fc94d3521f3ede3a8fb
# 2. Flash to slot A while keeping stock Android 9 on slot B
fastboot set_active a
fastboot flash system_a gm8_alpine_system_sar.img
fastboot reboot
# 3. Configure persistent host NetworkManager profile (172.16.43.2/24 -> 172.16.43.1)
./setup_gm8_usb_network.sh
ssh [email protected]
Device Tags: