diff --git a/NOTICE b/NOTICE index c24a0025d..c69d8bff3 100644 --- a/NOTICE +++ b/NOTICE @@ -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. diff --git a/THIRD_PARTY_LICENSES.md b/THIRD_PARTY_LICENSES.md index b02376257..2cc78e7a8 100644 --- a/THIRD_PARTY_LICENSES.md +++ b/THIRD_PARTY_LICENSES.md @@ -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 | diff --git a/configs/boot-args.lst b/configs/boot-args.lst index d5040b5a9..5140ce5e5 100644 --- a/configs/boot-args.lst +++ b/configs/boot-args.lst @@ -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 diff --git a/configs/symbols.tsv b/configs/symbols.tsv index 214128d22..f227ba4e6 100644 --- a/configs/symbols.tsv +++ b/configs/symbols.tsv @@ -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 diff --git a/docs/boot-args.md b/docs/boot-args.md index 1f6bbaa8a..4e8133bcb 100644 --- a/docs/boot-args.md +++ b/docs/boot-args.md @@ -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). @@ -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 | |---|---|---|---|---| @@ -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` | | diff --git a/docs/ios27/FULLROOT.md b/docs/ios27/FULLROOT.md index 3bffd6645..d29f5c3cb 100644 --- a/docs/ios27/FULLROOT.md +++ b/docs/ios27/FULLROOT.md @@ -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. diff --git a/docs/ios27/METAL-ROTATION.md b/docs/ios27/METAL-ROTATION.md new file mode 100644 index 000000000..318c4b143 --- /dev/null +++ b/docs/ios27/METAL-ROTATION.md @@ -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. diff --git a/docs/ios27/MODEM-IOS.md b/docs/ios27/MODEM-IOS.md new file mode 100644 index 000000000..5d506426a --- /dev/null +++ b/docs/ios27/MODEM-IOS.md @@ -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//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. diff --git a/docs/ios27/SILEO.md b/docs/ios27/SILEO.md new file mode 100644 index 000000000..465b9870b --- /dev/null +++ b/docs/ios27/SILEO.md @@ -0,0 +1,141 @@ +# iOS 27 on the S9: Sileo and the package manager's prefix + +The 16.5 line has had this by default for a while (`tools/mk-jb.sh`, `userland/src/jb_seed.c`, [apps](../apps.md)). The +iOS 27 root did not: `tools/ios27/fullroot/` had no step for it, so a full root had no `/var/jb`, no Sileo and nothing in +`/bin` but `df` and `ps`. It was never installed; nothing crashed and nothing wiped it. This page is the step that puts +it there, what it leaves on the phone, how it is kept, and what "secure user data" means on this port today. + +"Jailbreak" is the word people use for this; here it only means the rootless prefix `/var/jb` with the +[Procursus](https://github.com/ProcursusTeam/Procursus) bootstrap (dpkg, apt, a shell and the usual tools) and +[Sileo](https://github.com/Sileo/Sileo) on a system whose kernel is ours. Nothing is broken into. + +## What the build does + + tools/ios27/sileo/prepare.sh # no root; once; also run by tools/ios27/s9/prepare-root-inputs.sh + sudo tools/ios27/s9/build-root.sh inputs # steps.d/60-sileo.sh is one of its steps; ENABLE_SILEO=0 leaves it out + +`prepare.sh` fetches two files from `apt.procurs.us`, each pinned by SHA-256 in `tools/mk-jb.sh` (the bootstrap for +`iphoneos-arm64-rootless/1800`, and `org.coolstar.sileo` 2.5.1), unpacks them into `jb/` of the checkout (never in git) and +builds two small programs of ours for iOS. A changed file upstream stops the build. It is the installer's flavour of +`mk-jb.sh` (`PREINSTALL= ELLEKIT=`): the bootstrap and Sileo and nothing else. + +`steps.d/60-sileo.sh ROOT` then puts on the root: + +| What | Why | +|---|---| +| `/jb` | The prefix as the image carries it. Never run from. `jb_seed` copies it to `/private/var/jb` at the first boot; after that the copy is the phone's own and a later root does not touch it, unless the stamp in `/jb/.scion-stamp` differs: then the old copy is moved aside (`/private/var/jb.old-