HakiOS for the Samsung Galaxy A32 4G (SM-A325F): MediaTek Helio G80 (MT6769T), GPU Mali-G52 MC2, eMMC. iOS 16.5's own user space (launchd → backboardd → SpringBoard → apps) on Apple's open XNU kernel (xnu-8796.121.2), with this phone's own loader and drivers.
The A32 is a legacy non-A/B phone: its boot partition is boot (there is no boot_a
and no slot B).
Nothing on the phone is replaced for good: mtkloader sits in boot in front of Android's
own kernel, starts XNU once when Android asks for it, and the phone comes back to Android
after every run. The iOS system image lives in a partition of its own (xnusys, carved from
the end of userdata) and the kernel reads it off the eMMC as it needs it.
| boot | works | mtkloader/: MMU off, eMMC through MSDC0, device tree and boot arguments for XNU; 4 cores |
| storage | works, read only | the system image read off the eMMC as needed (emmc_root=1): 4 GiB xnusys, ~2.5 GB of iOS |
| display | works | 1080×2400 command-mode DSI, iOS at scale 3; the loader's watcher kicks the panel and checks DSI busy (kernel/iokit/Kernel/MiniIOMobileFramebuffer.cpp, mtk_kick=0) |
| touch | works | STM FTS5CU56A on I2C6 at 0x49, bit-banged on GPIO89/90 (kernel/bsd/dev/hakios.fts.c); its two rails (GPIO4 and PMIC VCAMA2) are switched on from the kernel |
| buttons | works | power and volume up/down (kernel/bsd/dev/hakios.mtkkeys.c) |
| GPU | works | Mali-G52 r1p0 (step 6/6), RedwoodMali, Mesa panfrost and CoreAnimation on the GPU (GL=1 gl=1): 21,729 job chains, 0 failed, 21–31 fps peaks; with panfrost's BO cache retained and its tiler heap lazy (32 MB) a 5-minute run had no respring (one app, Photos, crashed), see docs/gpu-a32.md |
| Metal | works | the y2sios runtime (libredwoodair + RedwoodMetal.bundle) on this GPU: a system .metallib draws THE SAME as softpipe's reference pixel, 64/64 shaders at panel size (--picture), and CoreAnimation runs on Metal (metal=1 metal_plugin=1): home screen, icons, dock at ~26 fps and a gradient wallpaper drawn behind the icons, no respring (boot-arg wallpaper=1); widgets and a 60 Hz frame rate still missing, see docs/metal-a32.md |
| CPU | works | 4 cores; A75 at 1999 MHz and A55 at 1699 MHz with mtk_cpufreq=3 (kernel/bsd/dev/hakios.mtkcpufreq.c); a ten-minute run stayed there (docs/stability-a32.md) |
| battery | works | MT6358 BATADC (voltage, 3:1 divider) and CHRDET, battery=2; temperature and current are still placeholders |
| sensors | partial | the SCP sensor hub runs and the accelerometer streams (scp_step=6, kernel/bsd/dev/hakios.scp.c); turning the samples into screen rotation is still user-space work |
| Wi-Fi / Bluetooth, audio, camera, cellular | missing |
kernel/bsd/dev/hakios.mali.c (boot-arg mali=1) is the Infinix Hot 20's Mali-G52 bring-up
ported to this phone. It gets all the way to step 6 of 6:
mali: GPU_ID 0x74021000 (Mali-G52 r1p0), shader cores 0x3, tiler 0x1, L2 0x1: all powered
mali: first job, identity mode ... the word 0xc0ffee01 -- the GPU ran it
mali: second job, through the GPU's page tables ... -- the GPU ran it
mali: came up to step 6 of 6
The GPU itself works, and the layer above it does too: RedwoodMali speaks panfrost's DRM
interface to Mesa (GL=1, CoreAnimation on the GPU; docs/gpu-a32.md), and the public
y2sios Mali Metal runtime finds this phone's GPU through RedwoodMetal.bundle
(metal=1; docs/metal-a32.md). The Infinix's own panfrost/Metal work is not published; what
runs here is the public y2sios runtime on this phone's kernel and Bifrost compiler. Leaving
mali=1 on changes nothing else: the GPU stays powered and tested.
mtkloader/— the bare-metal loader (MIT): chains in front of Android's kernel inboot, relocates itself and XNU to0x40080000, reads the eMMC, builds XNU's device tree and boot arguments, and brings Android back with XNU's log inpstore.kernel/— this phone's drivers and changes in XNU (APSL 2.0, seekernel/README.md).tools/—chainboot.py(pack a bare-metal program in front of Android's kernel) andmktouchfw.py(kept for the project's other phones; the A32's touch needs no firmware).diag/—a32diag, the first program that proved the chainboot and the framebuffer on this phone.docs/— how the display, the touch screen, the buttons and the GPU were found, register by register.device.conf— the phone and the state of each component.
No file of iOS, no firmware of the phone, no boot/partition image, no screenshot, no
xnuloader/identity.h (made from your own IPSW), no log with a device's data. LEGAL.md
says it in full. Build outputs (*.o, *.bin, *.img, generated headers) are ignored by
.gitignore.
What it needs:
- a Galaxy A32 4G (SM-A325F) with an unlocked bootloader, Android 13 rooted (Magisk), and
its stock
bootimage saved; - a Mac with the common HakiOS tree (kernel build, user space, the iOS system image made from your own IPSW).
The loader and the kernel are built from the common tree; this repository holds the phone's pieces:
export HAKIOS_SERIAL=... # your phone, as `adb devices` shows it
# build mtkloader and the kernel with the common tree, then pack boot:
python3 tools/chainboot.py stock-boot.img mtkloader.bin boot-a32.img xnu-payload.binOne run, with the A32 pieces enabled:
cpus=4 fbscale=3 touchscreen=3 buttons=2 mali=1
boot boots Android by default. To ask for one XNU run, from Android:
adb shell 'printf DARWIN-REDWOOD:BOOT-XNU > /dev/pmsg0'
adb rebootXNU runs for the loader's watchdog (300 s is the value used here), returns to the loader,
and the loader starts Android with the run's log in
/sys/fs/pstore/console-ramoops-2 (readable without root on this phone). Do not reboot by
hand while XNU runs: that loses the log. Five fingers held on the screen for 1.5 s also
return to the loader and keep it.
kernel/ is APSL 2.0 (LICENSE.APSL), as code built into XNU; everything else is MIT
(LICENSE). See NOTICE and LEGAL.md.