AppleSilicon/README.md
Youssef ba2ac1523e vmapple: Apple hypercall contract on upstream PAC; KVM/WHPX paths
Replace the Apple PAC emulation in target/arm with the contract the
vmapple kernel actually uses. Firmware writes the architected PAC keys
once on the boot CPU; the kernel never writes a key register and asks
the hypervisor over SMCCC (0xc100000x, HAS_PARAVIRTUALIZED_PAC).

- target/arm: pauth_helper.c, helper.c, cpu.{c,h}, internals.h and
  arm-powerctl.c restored to upstream. The KERNELKEY/APCTL/APCFG
  registers, kernel-key mixing, AppleMode, the diversifier and
  PAC_INHERIT are gone: no firmware stage or kernel touches them.
- target/arm/smccc.{c,h}: a board handler for non-PSCI SMCCC calls,
  offered each call from TCG's PSCI path, KVM and WHPX.
- hw/vmapple/hvc.c: SET_INITIAL_STATE saves the boot CPU's keys and
  installs them on each secondary; GET_DEFAULT_KEYS returns random
  non-zero pids (zero pids kill launchd); per-process key calls
  succeed as no-ops; every call returns 0 (xnu 26 spins otherwise).
  On the boot CPU's call, device-tree timebase-frequency is rewritten
  to the real counter rate before pe_identify_machine() reads it.
- Timer routed through the GIC as PPI 27 only: xnu's pe_init_fiq()
  makes it group 0, which GICv3 signals as FIQ. The FIQ-OR gate and
  the out-of-tree KVM_CAP_ARM_APPLE_VM requirement are removed.
- KVM: SMCCC filter forwarding the Apple range, KVM_EXIT_HYPERCALL
  handling, and KVM_EXIT_ARM_NISV emulation (target/arm/emulate-ldst)
  for pe_init_fiq's pre-indexed GICR_IGROUPR0 store, applied to the
  in-kernel vGIC through device attributes.
- WHPX: hypercall exits, ISV=0 MMIO emulation instead of an assert,
  and the GIC addresses taken from the machine.
- All ORCHARD_* switches removed.

Tested under TCG on x86-64: Ventura boots to the desktop with 12
vCPUs; guest clock rate 1.0006 with a 19.2 MHz counter (0.801 without
the device-tree fix). KVM code is syntax-checked for arm64 only;
WHPX code is not compiled. Neither has run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 00:38:02 +03:00

5.5 KiB

macOS on QEMU, on a Linux host

Video link: https://jumpshare.com/share/xWiBdnqUZPoGVcCptEGG

Boots an arm64 macOS guest (Ventura) on QEMU/TCG on Linux, through the genuine Apple boot chain — AVPBooter → iBootStage1 (LLB) → iBootStage2 (iBoot) → stock XNU — with a GPU that renders the desktop on the host's Vulkan.

No Apple hardware is involved at run time, and nothing Apple ships is redistributed here: you supply the firmware and the disk image, and the scripts below fetch or patch them in place.

                                  guest
   ┌──────────────────────────────────────────────────────────────┐
   │ macOS 13 (arm64e, RELEASE_ARM64_VMAPPLE) — unmodified        │
   └──────────────────────────────────────────────────────────────┘
        │ PVG command stream            │ virtio-blk (aux + root)
   ┌────┴──────────────┐          ┌─────┴───────────────────────┐
   │ reims-vgpu        │          │ QEMU `apple-vm` machine     │
   │ (Rust, Vulkan)    │          │ vmapple devices + AVPBooter │
   └────┬──────────────┘          └─────────────────────────────┘
        │ Vulkan
   ┌────┴──────────────┐
   │ host GPU (RADV)   │
   └───────────────────┘

What you need

Host Linux, x86-64. A Vulkan GPU (developed on AMD RENOIR / Mesa RADV).
RAM 16 GB+ — the guest gets 10 GB by default, and the whole RAMBlock is imported into one Vulkan heap, so the host needs that much importable GPU memory too.
Disk ~40 GB for the macOS image (50 GB apparent, sparse).
Tools cargo (stable Rust), a C toolchain, ninja, meson, python3 with requests and lz4.
Extra tool apfs-fuse, to read the macOS image — that is where the firmware comes from.

Getting it running

# 1. build QEMU (this also builds the Rust GPU device)
scripts/build.sh

# 2. fetch the macOS image: disk, NVRAM, and the VM config that carries its ECID
scripts/fetch-tart-image.py --out-dir images        # ~30 GB, resumable

# 3. take Apple's VM firmware out of the image, and patch it to run here
scripts/extract-avpbooter.py images/disk.raw -o images/AVPBooter.vmapple2.bin
scripts/patch-avpbooter.py images/AVPBooter.vmapple2.bin images/AVPBooter.patched.bin

# 4. optional: ask the kernel for a serial log
scripts/prepare-aux.py images/aux.img --set 'boot-args=-v serial=3'

# 5. boot
scripts/boot-robust.sh      # or scripts/run-vm.sh to stay in the foreground

The desktop appears in the device's own Vulkan window. First boot to the login screen takes a few minutes under TCG; see Known problems before concluding anything has gone wrong.

What is in here

Path What it is
qemu/ Upstream QEMU with our changes applied (see TECHNICAL.md for the list).
reims-vgpu/ The paravirtual GPU, vendored in-tree — steelbrain/reims-vgpu, a Rust crate that turns Apple's PVG command stream into Vulkan, with our changes baked in. Not ours.
scripts/ Fetch, patch, build and run.
TECHNICAL.md How the whole thing works, and what each change is for.
CONTRIBUTING.md Where a change belongs, how to test it, and the evidence rule.

Supporting the project

buymeacoffee.com/yaelliethy

Contributions go to hardware and to keeping this maintained. The first target is an arm64 laptop — a Snapdragon X2 Elite Extreme machine, about $1,600.

That is not a wish-list item. Everything here runs the guest under TCG, because the development host is x86-64 and the guest is arm64 — every boot, every test, every bisect pays emulation cost. An arm64 host makes the KVM path testable (see the KVM section in TECHNICAL.md, which is written as an open question precisely because nobody has been able to try it), and should make development considerably faster.

Licensing and what is not distributed

The QEMU changes are GPL-2.0-or-later, like QEMU itself. reims-vgpu/ is steelbrain/reims-vgpu, LGPL-3.0.

The AVPBooter patch applied by scripts/patch-avpbooter.py is from NyanSatan's Virtual-iBoot-Fun.

Not included, and not redistributable: nothing Apple ships is in this repository. The macOS image is fetched at run time from the public cirruslabs/macos-ventura-base image, and Apple's VM firmware (AVPBooter.vmapple2.bin) is taken out of that image, where macOS itself carries it in Virtualization.framework. Apple's licence permits macOS virtualisation only on Apple-branded hardware — check that your use is within it.

A host quirk worth knowing

If QEMU's configure dies with

TypeError: canonicalize_version() got an unexpected keyword argument 'strip_trailing_zero'

an old packaging in ~/.local/lib/python3.x/site-packages is shadowing the one in QEMU's build venv. scripts/build.sh already exports PYTHONNOUSERSITE=1, which is the whole fix.