Skip to content

Samsung Galaxy S9 (starlte, SM-G960F, Exynos 9810): HakiOS, iOS 16.5 on XNU; not built on the UniXNU tree ​

Scion-Project/scion-starlte

Samsung Galaxy S9 (SM-G960F, Exynos 9810) running iOS 16.5 on XNU through HakiOS. Upstream: based on HakiOS (Scion-Project/scion-kernel, from oosexgang's HakiOS), not on the UniXNU tree; no UniXNU components are used. Seen on the phone 1-3 November 2026, and on by default on every image (configs/starlte.config, README.md, Defaults): six cores, touch, battery, haptics, USB console, the S6E3HA8 panel through the DPP's scaler with zero-copy scan-out, brightness slider, Mali-G72 through Mesa Panfrost, CPU DVFS governor with touch boost and TMU throttling, native UFS root and persistent /var, RTC, Wi-Fi joined from iOS's Settings with DHCP, the front camera in the stock Camera app at 30 fps, speaker audio through ABOX and the MAX98512s, the CS47L93 codec's main microphone recorded through ABOX. Seen working but not a default (no room on the line): the sensor hub's six sensors and iOS's orientation and proximity (shub=6, SENSORS.md); Bluetooth patched at 4 Mbaud with an LE scan from the USB console (bt=7, BLUETOOTH.md); the codec's microphone as iOS's (abox_mic=1, AUDIO.md). Not yet: headphones, Bluetooth in iOS, modem, rear cameras, core 1, the low RAM bank.

Source record: porting.toml, 76bbd6000aeea88c4da5e3e0cdc2225178d1eac0.

This page is generated from the device record.

AreaStatus
Configurationimplemented
upstreamnot-applicable
Firmware and bootdevice-verified
CPU and interruptsdevice-verified
Memory and DMAdevice-verified
Storage and rootdevice-verified
Displaydevice-verified
Inputdevice-verified
GPUdevice-verified
Networkdevice-verified
Audiodevice-verified
Powerdevice-verified
Image assemblydevice-verified
Diagnosticsdevice-verified
cameradevice-verified
modemplanned

Configuration ​

implemented

Hardware and dependencies ​

  • Samsung Galaxy S9 SM-G960F (starlte), Exynos 9810 (S5E9810): 4 Cortex-A55 (MPIDR 0x000-0x003) and 4 Exynos M3 (0x100-0x103), Mali-G72 MP18, 4 GB RAM.
  • Kernel tree: Scion-Project/scion-kernel main, which pins this repository by revision in devices/manifest.conf.

Configuration ​

  • configs/starlte_defconfig and configs/starlte.config (EXYNOS_M3, EXYNOS_CAMERA and the S9 drivers built); soc/configs/exynos9810.config; soc/soc.conf.
  • The S9's defaults, the configuration seen working on the phone, are CONFIG_ symbols at the end of configs/starlte.config: devices/starlte/mkimage.sh puts them on every image's command line (cpus=6 bootcpu=2 m3_prep=3 pan=0 isa_floor=1 ... ufs=3 ... fb_zc=1 cam_s9=7 cam=5 abox=8 max98512=3 wifi_pcie=6 brcmfmac=8 wifi=1), and a run's own arguments go over them by name. Drivers not yet seen working stay off until their argument is given.

Procedure ​

  • tools/hakios-device.py sync starlte in the kernel tree, then make starlte_defconfig && make kernel.

Development findings ​

  • Each driver goes up in logged steps (driver=N) so a first phone run is safe; device.conf records each subsystem as seen on the phone, or written and not yet seen. Diagnostics (fps_log, systrace, *_probe, *_log) are never defaults.

Completion criteria ​

  • The kernel builds with starlte_defconfig and the image boots iOS 16.5 on the phone (see firmware and cpu).

Current limits ​

  • The kernel's command line holds 607 characters: the defaults take 422 and a run about 155 more (CONFIG_CMDLINE_RUN), so a run's added diagnostics have about 30 left; mkimage.sh warns past that.

Next action ​

  • Add each driver to the defaults once it is seen working on the phone (the torch, the headphones; the sensors, Bluetooth and the microphone in iOS once the line has room).

Evidence ​

upstream ​

not-applicable

Hardware and dependencies ​

  • HakiOS: Apple's open-source XNU (xnu-8796.121.2) on Android phones, with its own loader (xnuloader) and drivers. The S9 port lives in Scion-Project/scion-kernel (common tree, descended from oosexgang/hakios-xnu-kernel) and this repository (device files, checked out at devices/starlte).

Configuration ​

  • No UniXNU source pin, component, kit, OS profile or package script is used. board.toml lists no components and exists only so the catalog can identify the board.

Procedure ​

  • Build and boot with the HakiOS tree as README.md (Build, On the phone) describes: make starlte_defconfig, make kernel, make loader, devices/starlte/mkimage.sh.

Development findings ​

  • This record follows UniXNU's porting-record format so the S9 can be listed; the port is not built on the UniXNU tree and shares no code with it.

Completion criteria ​

  • The catalog page links to this repository and states that the port is HakiOS-based.

Current limits ​

  • UniXNU's build, package and checker scripts do not build this board; its component IDs do not apply.

Next action ​

  • Keep this record in step with device.conf when an area's state changes.

Evidence ​

Collect evidence using the next action.

Firmware and boot ​

device-verified

Hardware and dependencies ​

  • Samsung S-Boot (bootloader unlocked) loads an Android boot image (header v1) from BOOT.
  • Project Silicium's Mu-Silicium starltePkg UEFI with HakiOS's changes (uefi/), and Silicium's Carbon Hypervisor at EL2 (Hyp.bin, GPL-2.0), which answers PSCI.

Configuration ​

  • uefi/BASE pins the Silicium commit; uefi/files/.../MemoryMapLib.c reserves 0xF0000000 + 64 MB where the boot shim copies the payload.
  • The boot image kernel is BootShim + UEFI FD + payload, uncompressed, without a device tree (S-Boot uses the phone's dtb partition).

Procedure ​

  • S-Boot -> boot image -> Silicium UEFI (GOP on the panel's buffer at 0xCC000000) -> xnuloader (platform starlte) -> XNU at EL1.

Development findings ​

  • The Exynos 9810's own firmware does not do PSCI properly; Carbon at EL2 provides it and forwards CPU_ON to EL3.
  • The payload lands in the CP's region (modem_if); the loader moves it to 0xD0000000 first thing (payload_move) and keeps the CP's and ABOX's memory from UEFI and XNU.

Completion criteria ​

  • The phone boots from S-Boot through UEFI and the loader into XNU and iOS's user space.

Current limits ​

  • The prebuilt UEFI's Silicium base predates Carbon's update of 2026-10-13.

Next action ​

  • Rebase uefi/ on a newer Silicium and rebuild prebuilt/SILICIUM_UEFI.fd.

Evidence ​

CPU and interrupts ​

device-verified

Hardware and dependencies ​

  • GIC-400 (GICv2); 4 Cortex-A55 and 4 Exynos M3; PSCI from Carbon at EL2.
  • PMU fields of the big cluster written by Samsung's kernel before any CPU_ON (BSP flexpmu_cal_system_exynos9810.h, read for facts only).

Configuration ​

  • cpus=6 bootcpu=2 m3_prep=3 pan=0 (isa_floor on by m3_prep=3): A55s 2 and 3 plus the four M3s; core 1 is parked by S-Boot and left out by the loader.

Procedure ​

  • m3_prep=1 reads the cluster's PMU state, 2 writes the six fields with read-back, 3 lets the M3s start; each step is logged before it is taken (drivers/core/hakios.exynos_m3.c, patch 1508).

Development findings ​

  • An M3's CPU_ON hung until the big cluster's PMU fields were written as Samsung's kernel does.
  • PAN is ARMv8.1 and UNDEFINED on the ARMv8.0 M3, so pan=0 (patch 1509).
  • launchd got SIGILL on an M3 when told the A55's 8.2 features; isa_floor (patch 1510) reports only the ARMv8.0 set all cores share.
  • A cache-coherency check across clusters (cohtest=1, every A55 against every M3 both ways) passed.

Completion criteria ​

  • Six cores run iOS: two A55s and four M3s, booted on an A55.

Current limits ​

  • Core 1 is unavailable (parked by S-Boot); an M3 does not return from CPU_OFF, so the kernel idles with WFI; booting on an M3 (bootcpu=4) has not been tried.

Next action ​

  • Try bootcpu=4 cpus=8 and recover core 1.

Evidence ​

Memory and DMA ​

device-verified

Hardware and dependencies ​

  • RAM 0x80000000-0xFFFFFFFF and 0x880000000-0x8FFFFFFFF (4 GB); secure holes removed by Silicium's RamManagerLib.
  • reserved-memory of Samsung's device tree: modem_if 0xF0000000-0xF91FFFFF, cp_ram_logging, exynos_ss, ABOX.

Configuration ​

  • Payload at 0xD0000000 + 64 MB after payload_move; the display's scan-out buffers 0xD4000000-0xD6FFFFFF; the camera's frames 0xD8000000-0xD9FFFFFF; UFS's own mode 0xDA000000 + 4 MB; Wi-Fi's optional DMA pool 0xDC000000 + 44 MB; fb_zc's pool 0xDEC00000-0xE18FFFFF; one table with build-time non-overlap checks in the kernel's sys/hakios.exynos9810_mem.h. XNU's RAM the largest free block at 0x880000000 + 2 GB.

Procedure ​

  • The loader reserves the CP, ABOX and exynos_ss pages from UEFI (keep_out_reserve) and chooses XNU's window around them (choose_window).

Development findings ​

  • None of XNU's RAM is below 4 GB, so 32-bit DMA engines (DECON's DPP, the camera's WDMA, DWC3 descriptors) use fixed buffers below 4 GB mapped through IOKit.
  • An 11 MB ml_io_map_wcomb of the display buffers panicked; mapping them through IOKit works.

Completion criteria ​

  • Boots with the payload out of the modem region and the 32-bit DMA buffers below 4 GB.

Current limits ​

  • No SMMU (SysMMU) programming; devices use physical addresses.

Next action ​

  • Program the SysMMUs where a driver needs more than a fixed buffer.

Evidence ​

Storage and root ​

device-verified

Hardware and dependencies ​

  • UFS 2.1 host on the Exynos 9810 (0x11120000), as Silicium's UEFI leaves it; GPT on LUN 0 (SYSTEM, USERDATA and the rest).

Configuration ​

  • ufs=3 system_apfs=ufs_SYSTEM ufs_write=1 var_hfs=ufs_USERDATA_data, the defaults: the kernel's own UFS driver takes the controller after a self-test against the loader's reads (kernel PR 155, scion-starlte PR 33), writes fenced to USERDATA, /private/var on an HFS+ volume in USERDATA made once from TWRP.
  • ufs=2: block I/O through the loader and the UEFI's block service, ufs=3's fallback.

Procedure ​

  • ufs=3: references read through the loader, the controller taken as UEFI left it, every unit's head, GPTs and partition blocks compared byte for byte, writes fenced by a whitelist, then the switch; any failure falls back to ufs=2.

Development findings ​

  • Loader-backed UFS reads and writes carry the root and a persistent /private/var.
  • ufs=3 on the phone: the self-test and the fence test (68 writes judged, none sent) passed and the kernel switched to native reads (read only); some runs fell back to ufs=2 after a read failed past the switch, which the branch's later commits address.

Completion criteria ​

  • iOS mounts its system from SYSTEM through the kernel's own driver and keeps /private/var in USERDATA across boots.

Current limits ​

  • The controller is taken as UEFI left it (never reset); the loader keeps core 0 to serve ufs=2's fallback.

Next action ​

  • Keep the self-test's fallback count at zero across daily runs; a reset of the controller of the kernel's own.

Evidence ​

Display ​

device-verified

Hardware and dependencies ​

  • Samsung S6E3HA8 AMOLED, 1440 x 2960, on DSIM0; DECON with DPP channel VGF0 (hardware scaler).

Configuration ​

  • fb_dpp=1 fb_zc=1, defaults: VGF0 scales to the panel the window server's own surface, made in fb_zc's pool (0xDEC00000-0xE18FFFFF), with nothing copied (kernel PR 160); the scan-out buffers at 0xD4000000 otherwise; panel=1 backlight=2 brightness_bridge=1 for brightness, defaults.

Procedure ​

  • UEFI's GOP framebuffer at 0xCC000000 at boot; fb_dpp takes the DPP's VGF0 and flips frames at the DECON's refresh (drivers/gpu/hakios.exynos_dpu.c).

Development findings ​

  • The S6E3HA8 has no DCS brightness command; brightness is set by gamma and AOR through DSIM0.
  • iOS 16.5's Control Center slider needed to be made operative and its value read from the slider.

Completion criteria ​

  • iOS's frames scaled to the full panel by the DPP; the brightness slider changes the panel's brightness.

Current limits ​

  • No DSIM/DECON bring-up of its own: the controller is used as UEFI leaves it.

Next action ​

  • Measure frame pacing (fps_log) and remove late frames.

Evidence ​

Input ​

device-verified

Hardware and dependencies ​

  • Samsung S6SY761 touch controller on USI03's HSI2C, ten contacts.
  • Power, volume and Bixby keys (exynos_keys).

Configuration ​

  • s6sy761=1; exynos_keys=1.

Procedure ​

  • drivers/input/hakios.s6sy761.c reads contacts over HSI2C (drivers/core/hakios.exynos_hsi2c.c) and feeds iOS's HID stack.

Development findings ​

  • A touch read retry fixed lost events on the first live session; the touch thread runs at priority 92.

Completion criteria ​

  • Touch drives SpringBoard.

Current limits ​

  • The hardware keys are written and not yet confirmed on the phone.

Next action ​

  • Confirm the keys on the phone.

Evidence ​

GPU ​

device-verified

Hardware and dependencies ​

  • Mali-G72 MP18 (Bifrost); ACPM for its clock; Mesa's Panfrost in user space.

Configuration ​

  • mali=9 (nine logged steps); HakiosMali as the kernel interface for Panfrost.

Procedure ​

  • drivers/gpu/hakios.mali.c powers and starts the GPU; CoreAnimation draws through Mesa's Panfrost (OpenGL ES).

Development findings ​

  • CoreAnimation renders through Panfrost; the kernel logs GPU busy time and job counts every 5 s.

Completion criteria ​

  • iOS's UI is rendered on the Mali-G72.

Current limits ​

  • Metal is not yet run; nothing throttles the GPU thermally.

Next action ​

  • Run Metal through the Panfrost path (GPU.md).

Evidence ​

Network ​

device-verified

Hardware and dependencies ​

  • Broadcom BCM4361 (Murata/SEMCO module) on PCIe channel 0; firmware, NVRAM and CLM from firmware/wifi or the phone's own VENDOR partition.
  • Bluetooth on UART_BT with BT_EN on the PCAL6524 expander.

Configuration ​

  • wifi_pcie=6 brcmfmac=8 brcmfmac_poll=1 brcmfmac_tcm_idx=1 wifi=1, all defaults (Linux's brcmfmac through the kernel's Linux compatibility layer, the station for iOS's Apple80211); bt=7 for Bluetooth, not a default (it would take the line's last 5 characters).

Procedure ​

  • Stage 1: PMU isolation, PERST#, WLAN_REG_ON, PHY PLL, root complex, LTSSM, link. Stage 2: brcmfmac probe, chip ID and OTP module ID, firmware and NVRAM into the chip's RAM, interrupt, command interface, the phone's address, the station, joining (WPA2 by the kernel's lx_wpa.c); configd's DHCP on en0.

Development findings ​

  • On the phone the link comes up (Gen1 x1), the chip reads as 4361 revision 5, the firmware runs, a scan hears the access points, and a WPA2 network is joined from iOS's Settings, with an address from DHCP and the Internet answering.

Completion criteria ​

  • Wi-Fi joined from iOS's Settings, DHCP and the Internet: done.

Current limits ​

  • Bluetooth: the chip patched at 4 Mbaud and an LE scan from the USB console (bt=7, phone 2, 3 November); in iOS, bluetoothd waits on BlueTool's boot.

Next action ​

  • BlueTool's boot for iOS's bluetoothd (BLUETOOTH.md, iOS).

Evidence ​

Audio ​

device-verified

Hardware and dependencies ​

  • ABOX audio subsystem; two MAX98512 amplifiers on I2C; Cirrus CS47L93 codec on SPI (headphones, microphones).

Configuration ​

  • abox=8 max98512=3, defaults (ABOX's CPU off: RDMA0 -> SIFS1 -> UAIF1, I2S 48 kHz 2 x 16 bits; the amplifiers on and off with UAIF1).
  • cs47l93=6, a default (the CS47L93 on PERIC0's SPI: its ID, FLL1, MICBIAS1, IN3L, AIF1 a slave I2S); abox rec S on the USB console records UAIF0 -> WDMA1.

Procedure ​

  • Bring up the ABOX route, play a tone (abox=7), then hand iOS's output and volume to it (abox=8).

Development findings ​

  • ABOX's DMA runs without its firmware at 192000 bytes a second; a 1 kHz tone and iOS's own sounds play through both amplifiers (frames from iOS, none lost).
  • The CS47L93 answers on SPI (ID 6371), FLL1 locks, and its main microphone records through UAIF0 -> WDMA1 at 192480 bytes a second; its tone generator came back as a clean 1 kHz sine (phone 1, 3 November).

Completion criteria ​

  • A tone, then iOS's sound, from the speakers: done.

Current limits ​

  • The proof is the DMA's rate, the guard's peaks and the amplifiers' registers; the microphone reaches iOS only with abox_mic=1, not a default; the headphones are written behind cs47l93_hp=1, not yet tried.

Next action ​

  • The headphones' first run (cs47l93_hp=1, AUDIO.md, The headphones).

Evidence ​

Power ​

device-verified

Hardware and dependencies ​

  • MAX77705 (fuel gauge 0x36, charger, haptic block, MUIC USB switch); S2MPS18 PMIC with RTC; ACPM DVFS; Exynos 9810 TMU.

Configuration ​

  • max77705=1, max77705_haptic=1, max77705_usbsw=1; cpufreq_gov=1 (its touch and frame boosts); tmu=3; rtc_pmic=1: all defaults. cpufreq_lit/cpufreq_big fix the rates when the governor is off.

Procedure ​

  • The governor moves both clusters' rates through ACPM's DVFS within Samsung's limits, and slows them from the TMU's temperatures (83 C big, 76 C little).

Development findings ​

  • The APM reports 0 for the CPU rates, so the governor runs on the rate it asked for; its temperatures come from the TMU driver itself.
  • The battery level and charger state reach iOS; haptics are felt; the RTC read gives the time of day.

Completion criteria ​

  • Battery, haptics, DVFS with thermal throttling and the RTC working under iOS.

Current limits ​

  • Read-only PMIC/charger access; no suspend; the GPU is not throttled.

Next action ​

  • Throttle the GPU from the TMU's G3D zone.

Evidence ​

Image assembly ​

device-verified

Hardware and dependencies ​

  • XNU xnu-8796.121.2 with HakiOS's patches; iOS 16.5 (20F66) from the user's own IPSW (iPhone10,3/10,6); nothing of Apple's is in this repository.

Configuration ​

  • mkxnuimg.py UEFI_TARGET=starlte; mkimage.sh -s SECONDS boot-args.

Procedure ​

  • make unpack IPSW=...; make starlte_defconfig && make kernel; make loader; build the user space; devices/starlte/mkimage.sh -s 120.

Development findings ​

  • S-Boot will not unpack gzip and takes the device tree from the phone's dtb partition, so the image is uncompressed and carries none.

Completion criteria ​

  • xnu-starlte.img flashed to BOOT boots iOS.

Current limits ​

  • Every try is a flash: Samsung has no fastboot boot.

Next action ​

  • Keep the image script in step with the loader's payload layout.

Evidence ​

Diagnostics ​

device-verified

Hardware and dependencies ​

  • DWC3 USB in device mode (CDC-ACM 1209:0001) with the 2.0 PHY; exynos_ss log_kernel for TWRP (esslog=1); PMU SWRESET and INFORM3.

Configuration ​

  • usb_gadget=5 max77705_usbsw=1; esslog=1; mkimage.sh -s N (loader_return_after).

Procedure ​

  • The kernel's log streams live over USB with a line console; after N seconds the run ends, INFORM2/3 are written and the PMU's software reset restarts the phone into TWRP, where the log is read.

Development findings ​

  • The watchdog's reset lands in BOOT; the PMU's SWRESET with INFORM3 returns to TWRP.

Completion criteria ​

  • Each run gives a live log over USB and returns to TWRP by itself.

Current limits ​

  • No resident loader to send runs to; each run is a flash.

Next action ​

  • Keep every new driver's steps logged before they are taken.

Evidence ​

camera ​

device-verified

Hardware and dependencies ​

  • Front S5K3H1 sensor: supplies on the S2MPB02, MCLK, I2C; ISPPRE domain, CSIS1 and its D-PHY, VC0's DMA.

Configuration ​

  • cam_s9=7 cam=5, defaults: the sensor streaming into a ring of four frames at 0xD8000000, /dev/hakios-camera, and iOS's camera stack through libhakios.media.

Procedure ​

  • Supplies and model ID, then the domain, the CSIS test pattern, one sensor frame in RAW10 1632 x 1224, camshot, then streaming at 30 frames a second.

Development findings ​

  • The front camera auto-exposed, demosaiced at 1632 x 1224, streams at 30 frames a second into the stock Camera app's preview.

Completion criteria ​

  • The stock Camera app shows the front camera: done.

Current limits ​

  • No ISP firmware (the processing is the kernel's and user space's own); rear cameras not started.

Next action ​

  • The rear cameras (CAMERA.md).

Evidence ​

modem ​

planned

Hardware and dependencies ​

  • Samsung Shannon CP; modem_if memory 0xF0000000-0xF91FFFFF kept free by the loader; cbd/RIL behaviour from the LineageOS 24 build.

Configuration ​

  • None yet.

Procedure ​

  • Staged milestones in docs/modem-plan.md.

Development findings ​

  • The payload was moved out of the CP's region so a modem driver can have it whole.

Completion criteria ​

  • The CP boots from its image and answers on its IPC channel.

Current limits ​

  • Not started in code.

Next action ​

  • Load the CP image into modem_if and start the CP as cbd does.

Evidence ​

Collect evidence using the next action.

Released under the BSD-2-Clause-Patent License.