在 OnePlus 8 上运行 iOS 16.5:每个功能的参考与现状

XNU 和未修改的 iOS 16.5 用户空间跑在 OnePlus 8 上。按功能整理:试过什么、参考了什么、现在到哪一步,包括还没成功的部分。

这是一个研究项目:Apple 开源的 XNU(xnu-8796.121.2)加上未修改的 iOS 16.5 用户空间,运行在 OnePlus 8(IN2010,Snapdragon 865)上。代码在 Evsio0n/instantnoodle-xnu,基于 OOSEX GANG 的 HackiOS 和 haxi0/iphont-xnu-kernel。仓库里没有 Apple 文件、密钥和设备转储,也和 Apple、OnePlus、Qualcomm 没有关系。

下面每个功能写三件事:参考(依据什么来做)、试过(包括放弃的路)、现状。

状态都只在一台手机上验证过(IN2010,面板 AMB655UV01),截至 2026-11-06。用词的意思:

  • 已安装:包含在从手机自身存储启动的版本里,不接电脑也能跑。
  • RAM:只在从电脑载入的测试启动里跑过,结束后不留下任何东西。
  • 肉眼确认:在手机上亲眼看过;日志:只从日志读到。
  • 推论:还没有直接证据。

一览

功能现状
启动、安装、回退已安装
存储与 /var已安装
XNU 与 iOS 用户空间已安装
90 Hz 显示、自己的 MDP 驱动、EDR已安装;有卡顿
Metal over Vulkan,全系统已安装;内存持续增长
HDR 照片RAM 肉眼确认,安装版没复查
相机已安装;暗处每秒 15 帧
手电筒和闪光灯、蓝牙RAM 肉眼确认,已带进安装版
Wi-Fi已安装;撑不过系统休眠
声音、麦克风、震动以前验证过,这个版本没完整复查
系统休眠关 Wi-Fi 可用,安装版关闭
地图、Wi-Fi 定位地图能用但手势不跟手;定位在安装版没确认
Modem 与 GPS固件能跑,QMI LOC 有回应,GPS 没定到位
传感器、自动亮度未完成
第三方 App能注册、能启动进程,没看到画面
App Store、Apple ID、推送走不通

启动与存储

启动链、Loader、安装

参考: Project Silicium / Mu-Silicium;用 UEFIReader 读手机自己的 xbl;OnePlus 8T(kebab)的驱动;修补手机自己的 UFSDxe。

试过: fastboot boot 的 RAM 启动;把 iOS 卷写进 userdata;两个安装槽加启动守护(连续 3 次起不来就退回上一版)。放弃了替换 ABL/XBL,有防回滚风险。

现状: 已安装。Metal 版本写进一个槽,旧版留在另一个槽,开机菜单可选。不接线的真实启动也跑通了。插着 USB 复位会让原厂 ABL 判断错,要先拔线。

存储与 /var

参考: Apple 的 hfs-627.100.6、ios-instantnoodle 的补丁、libdeflate、libzbitmap、apfsck。

试过: 由 Loader 提供 UFS(异步 Block I/O 不行);从零写只读 APFS;ramfs;归档式 var store;HFS+ 数据卷。

现状: HFS+ 的 /var 可持久保存,已安装。可写 APFS 没开始。

XNU 与 iOS 用户空间

参考: Apple 开源的 XNU 和 sched_clutch_edge.md;上游 HackiOS;从 iOS 用户空间这一侧反推协议;Procursus、Sileo、ElleKit。

试过: 通用 BCM2837 配置(RELEASE 配置编不过);放弃只支持 iPadOS 的 UniXNU;用替身代替闭源 kext;Edge 调度器加自己的 CLPC 替代;用带防护的按地址 hook 注入。

现状: 8 核启动到主画面,App 能用,已安装。壁纸切换器还是黑的,设壁纸不行。

显示

面板、90 Hz、撕裂

参考: 手机运行中的设备树;Linux 的 dpu_hw_intf_disable_autorefresh;从 iOS 读到的 IOMFBDisplayRefresh。

试过: 先按 ANA6705 发命令,后来发现这台是 AMB655UV01;CPU 复制会撕裂;单缓冲只有 43–45 fps;后来用双缓冲、GPU 缩放、靠 TE 同步推送。DCS sleep-in 不能用,发了屏幕会有静态问题。

现状: 90 Hz 无撕裂,已安装。没有锁定 90,忙的时候 85–87 fps,约 2% 的提交会迟到。

自己的 MDP 驱动

参考: 主线 Linux DPU(dpu_hw_*.c)和 arm-smmu-qcom.c;Lineage 的 kona-sde.dtsi;U-Boot 的 qcom-hyp-smmu.c;在电脑上读 20F66 的 QuartzCore。

试过: mdp=1..8 一步步来:只读、校验和证明的纯色填充、取帧、靠 S2CR 建自己的 SMMU context、VIG 缩放、图层分离。读启动时的 context 会 CrashDump,放弃了。修了 GPU 写正在被取帧的 surface 造成的黑色三角形(fb_wait)。

现状: 默认开启,已带进安装版。看过的运行都是 0 欠载、0 SMMU 错误。NV12 和翻转只编译过。

EDR 与 HBM

参考: 面板设备树的 HBM 命令和 430 nits;dyld cache 里的 QuartzCore。

试过: edr=1 解决 CoreAnimation 以为屏幕只有 0 nits 的问题;HBM 带时间限制。

现状: EDR 已安装。HBM 开关日志确认,默认关闭,实际亮度没量过。

GPU 与 Metal

Adreno 650 与 OpenGL ES

参考: Linux msm 驱动、a650_hwcg[]、sm8250.dtsi;厂商的 a6xx_gmu_suspend;Mesa 25.0.7 freedreno;固件来自手机的 vendor_a。

试过: adreno=N 分步启动;冷启动 CrashDump 靠先处理 zap 头解决;HKGPU 说 msm DRM;Mesa 接在 EAGLContext 后面。

现状: 页表、挂死恢复(3/3)、DCVS、休眠时掉电都验证过。省了多少电没量。

AIR 到 NIR

参考: Apple 的 .metallib 语料,llvm-dis 当对照;Metal Shading Language Specification;真 Metal 的行为直接在 M1 Max 上量。

试过: IOGPU 路线实测走不通;自己写 bitcode 读取器和 AIR→NIR 前端;Gallium 后端放弃,改走 Vulkan。

现状: 456 个模块里 321 个能编译(所有入口点都在内),271 个 fragment shader 全部能画。mesh 和 tessellation 没开始。

Vulkan(turnip)

参考: Mesa 25.0.7 turnip 和 ir3;MoltenVK 的格式表。

试过: M1 到 M5 分阶段铺满全系统;直接喂 NIR,不经 SPIR-V;在 HKGPU 上垫一层 libdrm。

现状: metal=2,合成器、主画面、设置、Safari、照片、地图、相机都跑在 Metal 上,已安装。

着色器种子、CoreImage、Memo

参考: 在 Mac 上跑真正的 CoreImage 当对照;20F66 的二进制。

试过: 开机前收集翻译结果放进 root;function stitching 让 CoreImage 能跑;CPU 的 gain map 替身,后来退役;记住被拒的 pipeline,不再反复重试。

现状: 合成器的翻译时间从二十多秒降到约 2.8 秒。地图 99.9% 的 pipeline 请求都是在重试同两个被拒的,修掉后静止时从每秒约 7 帧升到约 17 帧(这两轮都有手指操作,不算干净对照)。图形 pipeline 缓存编好了,没验证。

卡顿

参考: 反汇编 20F66 的 QuartzCore 看 swap 节奏;其余靠自己的日志。

试过: fb_wait=13、三个 surface;打开 gpu_irq、DCVS 和 clock gating(对照后没赢);GPU 从 525 MHz 开到这颗芯片支持的 587 MHz,地图帧率没升,合成器节奏只稍微稳了一点(各一轮)。

现状: 还卡。显示路径没问题;地图加合成器的 GPU 时间约 15.6 ms,超过 90 Hz 的 11.1 ms。帧间隔不均是不是手感上的卡,是推论。手势时还有大量缓冲区在重复创建。

内存增长

参考: 只有自己的日志(memlog、计数器)。

试过: Maps 的 4x 目标用 256 MB 图像池(不是主因);统计 hkmetal 活着的对象。

现状: 没解决。backboardd 重度使用 12 分钟涨到 2.5 GB,不回落;约 10 分钟后后台 App 被杀,画面可能重启。hkmetal 的对象数量持平,所以问题应该在更下层(推论)。

HDR 与 HEIC 照片

参考: 反汇编 20F66;vt_test.c;gain map 和 Mac 上真正的 CoreImage 对比。

试过: CoreImage 走 GL(得到灰色 gain map);改走 Metal;把 CMPhoto 的 -12914 追到 VideoToolbox 的旋转。

现状: 测试启动里 HDR 高光有效,肉眼确认。直式 HDR 照片的加载脚本量到从 15.7 秒降到 4.15 秒,之后没再人工看过;安装版没复查。

相机

传感器

参考: 手机设备树;OnePlus 的模块文件;Linux 的 camss-csid-gen2.c、camss-csiphy-3ph-1-0.c、pinctrl-sm8250.c;iOS 的 AVCaptureSession.plist。

试过: cam=1..5:读寄存器、芯片 ID、CSIPHY + IFE-lite 取 raw、做 iOS 采集设备;修 eGPIO 才唤醒 IMX586;0.5x 靠 hook。

现状: IMX586、IMX481、IMX471 在相机 App 里能用,已安装。微距只读到芯片 ID。

ISP

参考: Mesa;在 macOS OpenGL 上核对;调校数据用 tools/camtuning.py 从 OnePlus 的文件取。

试过: CPU 的 camera_isp.c(95 °C 降频,放弃用于预览);camera_gpu.c,GLES3 经 OSMesa;Titan 480 IFE 延后。

现状: GPU 预览和 CPU 结果相差 1 级以内。拍照走 CPU。硬件 ISP 和零拷贝没开始。

对焦、曝光、闪光灯、预览

参考: 模块文件;LineageOS 的 cam_flash_core.c、leds-qpnp-flash-v2.c;Linux 的 leds-qcom-flash.c。

试过: LC898217XC、AK7374 上的反差对焦;曝光拉长帧时间;关掉 mediaserverd 的静音填充(它造成每秒约 1 GB 的内存增长);预览的 format 500 纹理只复制一次,造成三张画面循环,改成跟着 surface 的 seed 重新复制。

现状: 对焦可用。闪光灯和预览修复肉眼确认。暗处每秒 15 帧,亮处没量。暗处对焦可能卡在近端。视频有没有声音取决于下面的麦克风路径。

无线

Wi-Fi(QCA6390)

参考: Linux 7.0.14 的 ath11k;FreeBSD 15.1;OpenBSD qwx(4);linux-firmware;wpa_supplicant;IEEE 802.11-2020 Annex J.10。

试过: 未修改的 ath11k 跑在类 LinuxKPI 层上;自己的 MHI host;Android 的固件会断言,放弃;通过 ioctl 接 Apple80211。

现状: 连接、Safari、WPA2、WPA3 都验证过,开机自动连接已安装。撑不过系统休眠:恢复时固件崩溃,内核因为 DMA 归属不明故意停住,要手动重启。

蓝牙

参考: Linux 的 hci_qca.c、btqca.c、qcom_geni_serial.c;UniXNU-sheng(没有可复用的驱动);手机自带固件。

试过: UART 传输;去掉合成的 HCI 回复;放弃 BlueTool 脚本;用带防护的 hook 提供厂商描述。

现状: BLE GATT、经典配对验证过,默认开启,肉眼确认。唤醒后重连失败过;和 Wi-Fi 同时大流量没验证。

Modem 与 GPS

参考: LineageOS 的 esoc-mdm-pon.c、mhi_pm.c;Linux 的 pci_generic.c;libqmi;Qualcomm 的 location_service_v02.h;Replicant 的 sahara.c;postmarketOS wiki(只看到摘要)。

试过: modem=1..3:warm reset、PCIe、BHI、Sahara,然后 QRTR 和 QMI LOC。启动 GPS 先被拒(引擎锁定了非框架客户端),标明 AFW 客户端后被接受,约 70 秒后 modem 自己崩溃。把失败原因缓冲区交给 modem 后读到 remotefs_sahara.c:850 的断言:它要通过主机同步文件系统,没人响应(推论)。“干净拒绝”的方案写好并编译了,没跑。

现状: SDX55 能跑到 mission,能干净停止,QRTR 列出 47 个服务。没收到过卫星,没定到位。 从来不注册网络。SIM、数据、通话没开始。这些都还在私有分支和补丁里,没进主内核。

声音与外设

音频

参考: Linux 的 q6afe.c、q6adm.c、q6asm.c、hci_conn.c;NXP 驱动 v6.5.3;OxygenOS 的 mixer paths;PipeWire 的 SCO 做法。

试过: 通过 TrustZone 启动 DSP;ASM/ADM/AFE;用软件保护代替 TFADSP;为耳机调 SCO 节奏。

现状: 喇叭听到过,麦克风用拍手确认过,A2DP 听到过,都在 RAM。Metal 版本上麦克风看到有信号,喇叭只看到样本到了驱动。耳机孔、听筒、通话没开始。

触控、按键、震动

参考: OnePlus 的 sec_drivers_s6sy761.c;Linux 的 i2c-qcom-geni.c;OxygenOS 的滑块规则;手机的波形文件和驱动参数。

试过: 手动 I2C,后来 GENI FIFO;backboardd 里的虚拟 HID;redwood 的 touchscreen=1 在这台上 CrashDump,禁用;AW8697 分步启动,把 iOS 的 Actuator 映射到波形。

现状: 触控、按键、滑块、震动都可用。FIFO 启动验证过,不是默认。

电池、散热、电源

参考: OnePlus 的 bq27541_fuelgauger.c、qpnp-smb5.c、smb5-lib.c;Linux 的 qcom-cpufreq-hw.c、sm8250.dtsi。

试过: bq27541 电量计;类 schedutil 的调频;温度上限;充电限制和关机充电。

现状: 电量、充电、调频可用。开机头几分钟 CPU 传感器最高约 87 °C,重负载时曾在约 95 °C 降频。耗电没量;充电上限和低电量关机只编译过。

系统休眠

参考: PSCI;厂商的 a6xx_gmu_suspend;其余没有记录。

试过: 修挂死、核心收不到中断、中断丢失;用二分法定位 VSync 的连续时间问题;GPU 掉电。

现状: 关 Wi-Fi、先锁屏时,RAM 启动里两次唤醒屏幕和相机都正常,画面管线跨唤醒 0 错误。开 Wi-Fi 就停在上面说的那里。所以安装版用 syssleep=0:电源键只锁屏,比较耗电。SoC 最低功耗态走不到(UEFI 没退出)。

定位、地图、第三方 App

定位与地图

参考: Rye 和 Levin 2024 年关于 Wi-Fi 定位的论文;地图没有记录外部参考。

试过: 开 locationd 和开关;地图因为等 fairplayd.H2 挂住,测试 root 去掉这个 job,不伪造、不模拟;实现 vertex stage 的纹理绑定后真实地图不再画失败(从 12 次失败到 0 次)。

现状: 地图能看真实资料,手势不跟手。Wi-Fi 定位在 RAM 启动里肉眼确认,静置时自报半径 35–92 米,最远偏 20 米,没和真实位置比对。安装版的开关已写入一次,还没看到权限提示。

传感器与自动亮度

参考: hexagonrpc、libssc、pmaports 的 SDM845;qcom_pd_mapper.c;手机的 ODM 配置。

试过: SLPI 启动、GLINK/QRTR 探测、查找环境光;iOS 端的 ALS 候选只用模拟测试过;把音频 DSP 移开重叠的内存。

现状: 服务 400 有回应,传感器列表是空的(sensors PD 没起来,推论)。自动亮度和旋转都不能用。估计还要 15–25 轮启动,读数可能还要补偿。

第三方 App

参考: TrollStore 的 RootHelper/uicache.m;Telegram 官方 GitHub release。

试过: Mac 打包,手机通过 Wi-Fi 抓取并核对哈希,直接向 LaunchServices 注册,不走 installd,不重签。用 Telegram 10.0.3 和一份未加密的 13.2(后者来源是第三方,无法证明没被改过)。程序请求打开被 FrontBoard 以安全理由拒绝;手指点图标启动过进程。

现状: RAM。图标会出现,还没看到 App 画出画面。不会有推送;服务器接不接受旧版也不知道。这里的钥匙串保护不到位,不适合放重要账号。

TrustZone 与 FairPlay

参考: 观察 iOS 守护进程;U-Boot 和 Linux 的 SMMU 驱动行为;没找到公开的 QHEE 文档。

试过: 用 TrustZone 启动签名镜像;内核里放 FairPlay 桩(根本走不到,放弃);hypervisor 转储写好但搁置。不伪造 Mescal,不模拟 fairplayd,也不 hook FairPlay。

现状: 走不通,也不打算绕过。App Store 卡在加载,没有 Apple ID、推送和激活。没有 Secure Enclave;钥匙串、AMFI、Sandbox 的替身不提供真正的保护。

测试方法

试过: 几个会话共用一台手机时,xl 的锁会竞争,于是写了 tools/bootq 排队,手动测试优先;用一个点按钮就切换版本的网页,一个问题对应一个版本。

现状: 排队系统在假手机上测试过,也在实际使用。指纹和 NFC 只是禁用了守护进程,没开始做。

这篇是当前状态的快照,后面会继续变。写错的地方,以仓库里的文档和日志为准。