Files
vphone-cli/research
zqxwceandClaude Opus 4.8 9c1227f89b kernel: jb: Fix iOS 27 native VZ-view display (force the kern present path)
iOS 27 userland on the 26.4 vphone600 kernel booted with a working GUI over the
in-guest TrollVNC capturer, but the normal vphone-cli window (the host VZ view)
stayed black. Root cause, proven at the instruction level in the 27.0 DSC
IOMobileFramebuffer: the host VZVirtualMachineView is fed by the guest
AppleParavirtGPU scanout, which the 26.4 kernel drives ONLY from the IOMFB
userclient SwapEnd (external method 5) -- the `_kern_Swap*` path that 26.x used
(and that the SwapEnd size patch fixed on 26.0/18.x). iOS 27 defaults the
paravirt display's present to IOMFB's parallel `_virt_Swap*` path: `_virt_SwapEnd`
performs no userclient call -- it invokes an in-process callback and hands the
composited IOSurface to a virtual-display consumer -- so frames never enter the
kernel userclient and the paravirt GPU never scans out (live AppleParavirtGPU
scheduler sat idle). TrollVNC still saw frames because it captures the composited
surface in-guest, independent of the paravirt scanout.

Fix = force the display's present back onto the kern/method-5 path, in two halves:

Userland (DSC), new patcher cfw_patch_iomfb_force_kern.py (cfw.py +
cfw_install.sh, 27-gated): the public `_IOMobileFramebufferSwap*` entrypoints are
thin dispatch trampolines (`cbz x0; ldr xN,[x0,#slot]; cbz xN; braaz xN`) that
tail-call a per-connection swap fp (kern or virt impl). Rewrite each trampoline's
first instruction to `b _kern_Swap<Name>` -- args untouched, so this is
behaviourally identical to the connection having selected the kern fp. Fully
dynamic: public + `_kern_` addrs resolved by name via `ipsw dyld symaddr`,
trampoline shape verified by Capstone, branch bytes from the Keystone `asm_at()`
helper, modified DSC code pages re-attested. Runtime: 31 entrypoints retargeted,
4 non-trampoline setters left on virt, required {SwapBegin,SwapEnd,SwapSetLayer}
present.

Kernel (KernelJBPatchIomfbSwap, re-enabled in KernelJBPatcher.findAll): iOS 27's
native SwapEnd struct is 0x6e0 bytes (26.x sent 0x588) and the 26.4 userclient
exact-checks 0x588 in two places, so method 5 would return kIOReturnBadArgument.
patchIomfbSwapEndVariableSize flips the dispatch-table checkStructureInputSize
0x588 -> kIOUCVariableStructureSize; patchIomfbSwapEndHandlerSize retargets the
handler's internal `cmp w2,#0x588` -> #0x6e0. 27's IOMFBSwapRec prefix matches
26.x, so the paravirt swap handler reads valid fields. patchParavirtDisplayPrimary
stays disabled (wrong theory, harmful -- see JB-02c).

Validated on-device (17,3_27.0_24A5380h + cloudOS 26.4 c0ecdb4b, JB): clean boot,
no kIOReturnBadArgument / SwapEnd rejection / SECURITY_POLICY kill / panic, and
the iOS 27 userland now renders AND is interactive in the native VZ view.

research/0_binary_patch_comparison.md: DSC-patch item 9 corrected (27 no longer
size-truncated), new item 11 (force-kern), JB-26/27 rows added, all marked
validated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
Claude-Session: https://claude.ai/code/session_013pk5tsoBeuu3jhkmnRFtic
2026-07-20 16:20:34 +03:00
..