Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4843e59
Merge remote-tracking branch 'origin/wip/ios27-liquid-glass' into s9/…
claudiusthebot Nov 12, 2026
365e4f3
Merge remote-tracking branch 'origin/s9/sensors-ios27' into test-sensors
claudiusthebot Nov 12, 2026
b6d6a59
ios-27 metal: the interface on its side draws under the Metal composi…
claudiusthebot Nov 12, 2026
49500b1
Merge branch 's9/metal-perf' into test-sensors
claudiusthebot Nov 12, 2026
ddab5a7
Galaxy S9: its own modem, the Shannon CP, started from XNU (cp=N, off…
claudiusthebot Nov 12, 2026
6cdb31a
jb_seed: the copy of the prefix is root:wheel whatever owners the ima…
claudiusthebot Nov 12, 2026
5383a81
iOS 27: Sileo and the package manager's prefix as a step of the full …
claudiusthebot Nov 12, 2026
98d6cdd
Galaxy S9 modem: a data context and three packets through it (cp=6, c…
claudiusthebot Nov 12, 2026
fe23b36
tools/apn-table.py: Android's public list of access point names as a …
claudiusthebot Nov 12, 2026
f8d797f
iOS 27 Sileo step, REV 2: apt's methods stay root, Sileo registered f…
claudiusthebot Nov 13, 2026
5da9b54
Galaxy S9 modem: cp_sim=1, one SIM file read (EF_AD) in low power mod…
claudiusthebot Nov 13, 2026
9885ce3
Merge remote-tracking branch 'origin/main' into s9/p1-everyday
claudiusthebot Nov 13, 2026
a4ee488
Merge remote-tracking branch 'origin/s9/sileo-ios27' into s9/p1-everyday
claudiusthebot Nov 13, 2026
4c4f135
Merge remote-tracking branch 'origin/s9/modem-data' into s9/p1-everyday
claudiusthebot Nov 13, 2026
f981eff
ios-27 Wi-Fi: 64-wifi-nettest.sh, a test root's network check at ever…
claudiusthebot Nov 13, 2026
9e9f80e
Galaxy S9 modem: NV data from EFS read-only into RAM (cp_nv=2), the C…
claudiusthebot Nov 13, 2026
9ed051e
docs/ios27/MODEM-IOS.md: what iOS needs for SIM, carrier, bars and ce…
claudiusthebot Nov 13, 2026
4891c41
iOS 27 Sileo step: package-installed apps get their icons (scion-apps…
claudiusthebot Nov 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ Fetched at build time, never committed:
- the phone's firmware (GPU, Wi-Fi, audio DSP, modem, haptics, cameras): the vendor's, pulled from the
user's own phone (devices/redwood/pull-firmware.sh).
- lzfse (Apple, BSD-3-Clause), built by xnuloader/mkidentity.sh when no LZFSE decoder is installed.
- Android's list of access point names (device/sample etc/apns-full-conf.xml, The Android Open Source Project, Apache-2.0), for an
image that carries a table of them: fetched at a pinned commit, its SHA-256 checked, and made into the table by tools/apn-table.py,
entries unchanged. Neither the list nor the table is in this repository.
- Mesa (for GL=1 images; Turnip for TURNIP=1, tools/mk-turnip.sh), Procursus and Sileo packages (tools/mk-jb.sh): their own licenses.
- Mesa's PanVK (Mesa 25.0.7, MIT), for PANVK_DIR= images: fetched by tools/mk-panvk.sh, patched with tools/mesa/*.patch
and tools/mesa/panvk/*.patch (Mesa's licence applies to the lines those add) and built into libvulkan_panfrost.dylib.
Expand Down
1 change: 1 addition & 0 deletions THIRD_PARTY_LICENSES.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ This supersedes the summary in `NOTICE`, which stays as the short, canonical lis
| Mesa (GL=1 images) | `tools/mk-mesa.sh` | Mesa project | MIT and others |
| Mesa's gfxstream guest Vulkan driver (`src/gfxstream`, with the Vulkan runtime it builds on) | `tools/gfxstream/mk-vk.sh` | Google / AOSP via the Mesa project | MIT |
| gfxstream (codegen descriptions; host renderer for the Scion app) | `tools/gfxstream/fetch.sh`, `mk-host-android.sh` | Google | Apache-2.0 (some MIT) |
| Android's list of access point names (data for an image's APN table; not in the repository) | `tools/apn-table.py` (fetched from android.googlesource.com/device/sample at a pinned commit, SHA-256 checked) | The Android Open Source Project | Apache-2.0 |
| metal2vulkan (runtime, translator, AIR reader; METAL=vk images) | `tools/metal/mk-metal2vulkan.sh` (github.com/steelbrain/metal2vulkan at `720ef1ce9ae2`, with AdrenoMetal's patches and ours in `tools/metal/m2v/`) | Anees Iqbal | GPL-2.0-or-later OR LGPL-3.0-or-later; only ever in its own `libmetal2vulkan.dylib`, which can be replaced |
| Rust toolchain and crates (ash, libc, sha2, serde ...) | `tools/metal/mk-metal2vulkan.sh` (rustup into `xnu-deps/rust`, crates.io) | the Rust project, crate authors | MIT / Apache-2.0 |
| Turnip, Mesa's Vulkan driver (TURNIP=1) | `tools/mk-turnip.sh`, in `tools/mk-mesa.sh`'s tree | Mesa project, 25.0.7 | MIT and others |
Expand Down
13 changes: 13 additions & 0 deletions configs/boot-args.lst
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,19 @@ cohtest_delay k
console_quiet k
core0 kl
core1 l
cp k
cp_apn k
cp_delay k
cp_ds k
cp_if k
cp_if_kb k
cp_nv k
cp_ping k
cp_rev k
cp_route k
cp_sim k
cp_vss k
cp_wait k
cpufreq k
cpufreq_gov k
cpufreq_gov_big_dual k
Expand Down
13 changes: 13 additions & 0 deletions configs/symbols.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,19 @@ COHTEST_DELAY arg cohtest_delay User space k hakios.exynos_m3.c
CONSOLE_QUIET arg console_quiet User space k 1003-avf-console-quiet.patch
CORE0 arg core0 Loader kl loader.c,psci_smp.c the kernel's box for this core (above), if it has one, and only with a kernel on another core to watch
CORE1 arg core1 Loader l loader.c core 1, which S-Boot uses for its own display work, listed for the kernel all the same
CP arg cp User space k hakios.shannon.c
CP_APN arg cp_apn User space k hakios.shannon.c the access point name stage 6 asks the data context for (the operator's published default; none: no stage 6)
CP_DELAY arg cp_delay User space k hakios.shannon.c seconds after the boot before the modem's driver does anything (30), so that its lines are in the log
CP_DS arg cp_ds User space k hakios.shannon.c the dual SIM field told to the modem (0)
CP_IF arg cp_if User space k hakios.shannon.c with cp=6 or 7 and cp_apn: the active data context becomes a network interface, pdp_ip0 (IPv4, point to point, the CP's address for it), and stays
CP_IF_KB arg cp_if_kb User space k hakios.shannon.c with cp_if=1: at most N KB through pdp_ip0 in a boot, both ways (2048 by default; the owner's mobile plan), then it drops
CP_NV arg cp_nv User space k hakios.shannon.c the phone's own NV data, a file nv_data.bin the image's builder put beside the kernel, is given to the modem (none: zeros, and no stage 4)
CP_PING arg cp_ping User space k hakios.shannon.c the address stage 7 sends its one echo request to (none: the context's first DNS server)
CP_REV arg cp_rev User space k hakios.shannon.c the board's revision told to the modem (26, this phone's)
CP_ROUTE arg cp_route User space k hakios.shannon.c with cp_if=1: an IPv4 default route through pdp_ip0 (only when there is none yet: Wi-Fi's wins)
CP_SIM arg cp_sim User space k hakios.shannon.c in low power mode, once the SIM is ready, one read of its administrative data file (EF_AD, 4 bytes: no identity) is asked, to see if the modem takes
CP_VSS arg cp_vss User space k hakios.shannon.c the image's VSS part (the voice processor's) is not copied
CP_WAIT arg cp_wait User space k hakios.shannon.c seconds the started modem is watched before it is put back in reset (20; 25 with the link)
CPUFREQ_GOV arg cpufreq_gov User space k hakios.exynos_cpufreq.c run it (0, or none: the fixed rates of cpufreq_lit= and cpufreq_big=)
CPUFREQ_GOV_BIG_DUAL arg cpufreq_gov_big_dual User space k hakios.exynos_cpufreq.c
CPUFREQ_GOV_BIG_MAX arg cpufreq_gov_big_max User space k hakios.exynos_cpufreq.c
Expand Down
17 changes: 15 additions & 2 deletions docs/boot-args.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Made by `tools/boot-args.py --markdown`; CI fails if it is out of date with the source (`tools/boot-args.py --check`).

Every argument that the kernel, the loader or user space of this port reads, and which file reads it. **675 arguments**: 584 read by the kernel, 23 by the loader, 85 by user space (one is read in more than one place).
Every argument that the kernel, the loader or user space of this port reads, and which file reads it. **688 arguments**: 597 read by the kernel, 23 by the loader, 85 by user space (one is read in more than one place).

This is a catalogue of what exists and who reads it, not a manual. What an argument means is in the head of the file that reads it. The stable switches have a symbol in the configuration (`tools/hakios-config.py help SYMBOL`, `docs/configs.md`); the rest are the knobs of bring-up (a driver's steps, pauses, traces, test modes) and can change with the driver. Any of them can be given in a configuration with `CONFIG_BOOTARGS="name=value ..."`, which checks that each name is in this list. What the arguments of the two Metal paths do: [Metal on the Adreno](reference/metal.md#boot-arguments).

Expand Down Expand Up @@ -593,7 +593,7 @@ Layers: **K** the kernel, **L** the loader, **U** user space (through `sysctl ke
| `ufs_probe` | L | `loader.c` | `CONFIG_UFS_PROBE` | |
| `ufs_write_guid` | L | `loader.c` | `CONFIG_UFS_WRITE_GUID` | |

## User space (170)
## User space (183)

| Argument | Layer | Read by | Configuration | Set by |
|---|---|---|---|---|
Expand Down Expand Up @@ -659,6 +659,19 @@ Layers: **K** the kernel, **L** the loader, **U** user space (through `sysctl ke
| `cohtest` | K | `hakios.exynos_m3.c` | `CONFIG_COHTEST` | |
| `cohtest_delay` | K | `hakios.exynos_m3.c` | `CONFIG_COHTEST_DELAY` | |
| `console_quiet` | K | `1003-avf-console-quiet.patch` | `CONFIG_CONSOLE_QUIET` | |
| `cp` | K | `hakios.shannon.c` | `CONFIG_CP` | |
| `cp_apn` | K | `hakios.shannon.c` | `CONFIG_CP_APN` | |
| `cp_delay` | K | `hakios.shannon.c` | `CONFIG_CP_DELAY` | |
| `cp_ds` | K | `hakios.shannon.c` | `CONFIG_CP_DS` | |
| `cp_if` | K | `hakios.shannon.c` | `CONFIG_CP_IF` | |
| `cp_if_kb` | K | `hakios.shannon.c` | `CONFIG_CP_IF_KB` | |
| `cp_nv` | K | `hakios.shannon.c` | `CONFIG_CP_NV` | |
| `cp_ping` | K | `hakios.shannon.c` | `CONFIG_CP_PING` | |
| `cp_rev` | K | `hakios.shannon.c` | `CONFIG_CP_REV` | |
| `cp_route` | K | `hakios.shannon.c` | `CONFIG_CP_ROUTE` | |
| `cp_sim` | K | `hakios.shannon.c` | `CONFIG_CP_SIM` | |
| `cp_vss` | K | `hakios.shannon.c` | `CONFIG_CP_VSS` | |
| `cp_wait` | K | `hakios.shannon.c` | `CONFIG_CP_WAIT` | |
| `cpufreq_gov` | K | `hakios.exynos_cpufreq.c` | `CONFIG_CPUFREQ_GOV` | |
| `cpufreq_gov_big_dual` | K | `hakios.exynos_cpufreq.c` | `CONFIG_CPUFREQ_GOV_BIG_DUAL` | |
| `cpufreq_gov_big_max` | K | `hakios.exynos_cpufreq.c` | `CONFIG_CPUFREQ_GOV_BIG_MAX` | |
Expand Down
2 changes: 2 additions & 0 deletions docs/ios27/FULLROOT.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ some Settings rows lack icons.
`_PanicOnCrash` dropped; `lists/`; `DISABLE_HOGS=1` adds the opt-in CPU-hog list) | `30 overlay` (builder's userland shims,
manifest-checked) | `40 prefs` (Reduce Motion / Reduce Transparency OFF, CA compression off, watchdogs off) |
`50 xpc-disable` (MessagesBlastDoorService) |
`60 sileo` (the package manager: the Procursus bootstrap and Sileo as `/jb`, seeded to `/var/jb` at the first boot, kept and
flushed; default on, `ENABLE_SILEO=0` turns it off; needs `tools/ios27/sileo/prepare.sh` first; [SILEO.md](SILEO.md)) |
`70 lsd-extkit` (ExtensionKit FeatureFlag off + LaunchServices store rebuild: the kernel has no AMFI trust cache, so the signed
extension-point cache was rejected and no framework-declared extension point registered; `ENABLE_LSD_EXTKIT=0` turns it off).
4. `check-root.sh`: required files, cache hard links, patched words, launchd plist sanity, prefs, Mach-O rewrite complete.
Expand Down
50 changes: 50 additions & 0 deletions docs/ios27/METAL-ROTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# iOS 27 on the Galaxy S9: the interface on its side under the Metal compositor (12 November 2026)

With CoreAnimation's Metal renderer as the compositor ([LIQUID-GLASS.md](LIQUID-GLASS.md)) the panel kept its last upright
picture whenever the interface turned to landscape, until it was upright again. The app underneath was running and took
touches. Under the OpenGL ES compositor the same turn drew.

## What CoreAnimation asks for

The display's two swap surfaces never change: 828 x 1792 pixels, 3328 bytes a row, rows along the panel. When the display
is to show the interface turned by a quarter, CoreAnimation's Metal renderer does not turn its own drawing. It asks Metal
for a texture over each swap surface whose descriptor has the turned size, 1792 x 828, and a rotation (a private property
of Metal's texture descriptor; 3 on a phone held in landscape, 0 otherwise), and then draws the interface into that
texture the way it reads. A GPU with turned render targets stores the picture turned, so the surface still holds what the
panel scans out. (The OpenGL ES renderer has no such texture and turns its drawing itself, which is why that path drew.)

Seen on the phone, in a line the plug-in printed for the refusal: `want 1792x828 fmt 80 usage 0x5 rotation 3 | surface
828x1792 bpr 3328`, asked from the renderer's "texture of this surface" step when it makes a buffer current, sixty times in
the two seconds of the turn. The plug-in ignored the rotation, took the request for a texture 1792 pixels wide over rows
of 3328 bytes, and refused it (`BufferTexture(RowPitch { bytes_per_row: 3328, row_bytes: 7168 })`). With no texture for
its destination CoreAnimation drew nothing.

## What the plug-in does now

No Vulkan image can lie over the surface that way, so a texture asked for with a rotation is two textures
(`tools/ios27/metal/patches/frontend-turned.diff`, "turned textures"):

- the one the caller gets has the asked shape and lives in device memory. Everything drawn into it, sampled from it or
copied with it is as the caller means it; its `iosurface` and `rotation` answer what was asked;
- the surface's own texture, unturned, which the caller never sees.

Every command buffer that drew into the first (or into a view of it) ends with one more render pass, added at commit: a
single triangle over the surface's texture whose fragment reads the picture through the turn
(`tools/ios27/metal2/TurnShaders.metal`, one fragment function for each of the three turns, nearest sampling, texel for
texel). The surface is written before the buffer completes, which is before the window server hands it to the display.
The pass is built by the bundle's script with the Metal compiler of the same Xcode and compiled on the phone like any
other pipeline (and kept in the pipeline cache).

Cost: one pass over the screen for each frame while the interface is turned, and 6 MiB of device memory for each of the
two swap surfaces. Upright, nothing changes: a descriptor without a rotation takes the path it always took.

Only rotation 3 has been asked for by iOS 27 and only that one has been seen on a panel; 1 and 2 are written the same
way and are untested. A texture with a rotation that is not a plain 2D, single-level, single-sample texture of the
surface's turned size is refused with a line.

## Seen

Phone held on its long edge, Notes in front: landscape, then upright (the accelerometer answered by the console's
`sensors fake 0 4096 0`), then landscape again, each drawn, with the glass of the search field and the round buttons that
the OpenGL ES compositor does not draw. `native-metal: turned texture 1792x828 fmt 80 turn 3 over surface 1 (828x1792)`
once for each swap surface, no refusal. The picture is the same way up as the OpenGL ES compositor's.
84 changes: 84 additions & 0 deletions docs/ios27/MODEM-IOS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# The Galaxy S9's modem on iOS 27: what iOS needs for SIM, carrier and bars

Written 13 November 2026. This is a research note and plan. Nothing here is built yet, except the kernel side under
"What the kernel gives today". Facts about iOS come from public documentation and published research. No Apple
binary, offset or table is in this file.

## What the kernel gives today (scion-kernel `drivers/modem/hakios.shannon.c`, all off by default)

| Boot-arg | What it does |
|---|---|
| `cp=1`…`cp=7` | The S9's Shannon CP: loaded from RADIO, checked by the secure world, started, linked. Then low power mode, the SIM's state, normal mode (registration), one data context (`cp_apn=`), and three test packets through it |
| `cp_nv=2` | The CP's non-volatile data read at boot from the EFS partition, `/nv_data.bin`, through a read-only ext4 reader (`hakios.ext4ro.h`). It is kept in RAM only. EFS is never mounted and never written; only its size and a CRC prefix are logged |
| (with `cp_nv=2`) | The CP's file requests for its NV data (RFS NV read/write) are answered from that RAM copy. Its writes stay in RAM for the run and are never written back |
| `cp_if=1` | The active data context becomes `pdp_ip0`: IPv4, point to point, with the context's address on it. The context stays up until `sysctl kern.hakios.cp.go=2` |
| `cp_route=1` | An IPv4 default route through `pdp_ip0`, if there is none yet |
| `cp_if_kb=N` | A per-boot byte budget on `pdp_ip0`, 2048 KB by default |

Seen on phone 1 (SM-G960F, GoMo SIM on eir, 272-03), 13 Nov 2026:
- SIM ready, registered HOME.
- The NV data came from EFS, and the CP's NV writes were answered.
- `pdp_ip0` came up with the context's address and a default route, and packets went both ways from user space.

## What iOS has on top of a baseband, and why none of it sees ours

- **CommCenter** (CoreTelephony's daemon) owns the baseband. It finds the modem through IOKit services that Apple's
baseband drivers publish. On an iPhone 11 (the identity this port uses, iPhone12,1) that is an Intel XMM modem over
PCIe, spoken to in Apple's ARI protocol ("Apple Remote Invocation"; reverse-engineered in public by the ARIstoteles
project, Kröll et al., WiSec 2021).
- CommCenter does everything above the modem: SIM handling, registration, the operator's name (from the SIM, the
network and the carrier bundles), signal bars, data contexts, the cellular network service and its DNS, and SMS
and calls.
- **Clients** (SpringBoard's status bar, Settings > Mobile Service, Preferences) ask CommCenter over private XPC
(CoreTelephony's `CTServerConnection`, the `com.apple.commcenter.*` services). They never see the modem.
- **Data on iOS:** CommCenter brings a context up, configures `pdp_ipN`, and registers a cellular network service with
configd (the IPv4 and DNS state that IPMonitor turns into the routing table and the resolver). Without that service,
a kernel route through `pdp_ip0` carries traffic, but iOS's resolver has no DNS server for it, and iOS's own
reachability does not treat cellular as up.

Our CP speaks Samsung IPC over SIPC5 rings, not ARI. CommCenter finds no baseband it knows, so iOS shows no SIM, no
carrier and no bars.

## The ways to the iOS side, in order of size

1. **DNS and "cellular is up" for user space (small; next).**
- A root daemon in the package-manager prefix reads the kernel's modem state (new read-only sysctls:
registration, the context's address and DNS servers, signal).
- It publishes a network service for `pdp_ip0` into configd's dynamic store: `State:/Network/Service/<id>/IPv4`
(address, interface `pdp_ip0`, router) and `.../DNS` (the context's DNS servers).
- IPMonitor then makes the default route and the resolver as it does for any service. The kernel's own default
route (`cp_route=1`) is no longer needed.
- Wi-Fi keeps priority through service order (IPMonitor's rank).
- Gives: names resolve, and every app's traffic goes over cellular when Wi-Fi is off.
- Does not give: bars or a carrier name.
2. **Bars and carrier name in the status bar (medium; cosmetic).**
- The port already injects dylibs into SpringBoard and backboardd (`sweetinject`).
- A small injected library in SpringBoard would feed the status bar's cellular entry (signal bars, operator name,
"4G"/"LTE") from the same sysctls: the registration state, the technology (33 = LTE seen), the signal reports,
and the network's name from the CP's operator notification (not decoded yet).
- Settings would still say "No SIM": that comes from CommCenter.
- This touches only our own injected code. No Apple binary changes.
3. **A real CoreTelephony baseband (large).** Either:
- a shim that answers CommCenter as an ARI baseband would (the IOKit services, the ARI messages for SIM,
registration, signal and data) and translates them to Samsung IPC. This needs ARI's message set for the
iPhone12,1 firmware generation.
- or a replacement for CommCenter's XPC services. The private interface is large.

Either one gives SIM in Settings, the operator from the carrier bundle, bars, and data through iOS's own
path. Weeks of work, with real risk. Do not start without the owner's go.

What stays out of every path:
- No IMEI or NV change.
- No unlock of any kind.
- No calls or SMS without the owner's explicit say-so.
- EFS read-only.
- No Apple binary patched.

## Next concrete steps

1. Kernel: expose read-only sysctls `kern.hakios.cp.{reg,tech,signal,ip4,dns4}`. Decode the operator name
notification, group 0x0a number 0x52 seen, unconfirmed.
2. A `scion-celld` root daemon (prefix, launchd job like `com.scion.jbseed`) publishing the pdp_ip0 service to configd
(step 1 above).
3. Then the status-bar library (step 2).
4. Then decide on step 3 with the owner.
Loading
Loading