# How VPhoneCore Library Works with Apple Virtualization.framework: A Complete Technical Breakdown

> Discover how the VPhoneCore library builds virtual iPhones by translating manifests into VZVirtualMachineConfiguration using Apple Virtualization framework APIs. Learn the technical details.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: deep-dive
- Published: 2026-09-09

---

**VPhoneCore library builds a virtual iPhone by translating a high-level manifest into a `VZVirtualMachineConfiguration` using both public and private APIs from Apple's Virtualization.framework.**

The VPhoneCore library orchestrates a complete macOS-based virtual iPhone (vPhone) by assembling and configuring Apple Virtualization.framework's device classes. The implementation centers on [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift), which converts a codable *manifest* into a fully operational `VZVirtualMachine`. This article examines how VPhoneCore integrates with Virtualization.framework at every layer—from hardware modeling to runtime control.

## Creating the Hardware Model and Platform Configuration

Every virtual iPhone begins with a hardware model definition. VPhoneCore creates a PV-3 iPhone-compatible model through `VPhoneHardware.createModel()`:

```swift
let hwModel = try VPhoneHardware.createModel()      // → VZMacHardwareModel (PV = 3)

```

The hardware model attaches to a `VZMacPlatformConfiguration`, which also requires:

- A persistent `VZMacMachineIdentifier` (stored in the manifest and regenerated if absent)
- ECID extraction via the private-API-friendly `Dynamic` wrapper to form a predictable UDID
- Auxiliary NVRAM storage initialized with boot arguments

The platform configuration setup in [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) demonstrates this assembly:

```swift
let platform = VZMacPlatformConfiguration()
platform.machineIdentifier = machineIdentifier
platform.hardwareModel   = hwModel
platform.auxiliaryStorage = try VZMacAuxiliaryStorage(
    creatingStorageAt: options.nvramURL,
    hardwareModel: hwModel,
    options: .allowOverwrite
)

```

VPhoneCore writes boot arguments (`"serial=3 debug=0x104c04"`) using `Dynamic` to reach the private `setDataValue(_:forNVRAMVariableNamed:)` API. This pattern—public structure with private injection—recurs throughout the codebase.

## Boot Loader Configuration and DFU Support

The boot loader supports optional custom ROM injection for DFU-style operations:

```swift
let bootloader = VZMacOSBootLoader()
if let romURL = options.romURL {
    Dynamic(bootloader)._setROMURL(romURL)      // private API injection
}

```

When `forceDFU` is requested, VPhoneCore constructs `VZMacOSVirtualMachineStartOptions` and sets the private flag via `Dynamic` before calling `await vm.start(options: opts)`.

## virtual iPhone Device Architecture

VPhoneCore instantiates all essential Virtualization.framework device classes and attaches them to a `VZVirtualMachineConfiguration`. The following table maps each subsystem to its framework implementation:

| Component | Virtualization.framework Class | VPhoneCore Integration |
|-----------|-------------------------------|------------------------|
| **CPU / Memory** | `config.cpuCount`, `config.memorySize` | Validated against framework minimums |
| **Graphics** | `VZMacGraphicsDeviceConfiguration` → `VZMacGraphicsDisplayConfiguration` | Screen dimensions and PPI from manifest |
| **Audio** | `VZVirtioSoundDeviceConfiguration` | Host audio input/output streams |
| **Storage** | `VZVirtioBlockDeviceConfiguration` | `VZDiskImageStorageDeviceAttachment` for disk images |
| **Network** | `VZVirtioNetworkDeviceConfiguration` | Generated by `VPhoneNetworking.makeNetworkDevice` with NAT/bridged/off modes |
| **Serial (PL011 UART)** | `VZSerialPortConfiguration` | Pipe-based I/O with interactive host stdin/stdout |
| **VideoToolbox** | `VZMacVideoToolboxDeviceConfiguration` | Injected via `Dynamic._setAcceleratorDevices` |
| **Neural Engine** | `VZMacNeuralEngineDeviceConfiguration` | Injected via `Dynamic._setAcceleratorDevices` |
| **Scaler Accelerator** | `VZMacScalerAcceleratorDeviceConfiguration` | Injected via `Dynamic._setAcceleratorDevices` |
| **Touch Screen** | `VZUSBTouchScreenConfiguration` | Injected via `Dynamic._setMultiTouchDevices` |
| **Entropy** | `VZVirtioEntropyDeviceConfiguration` | Always present |
| **Keyboard** | `VZUSBKeyboardConfiguration` | Added to `config.keyboards` |
| **Vsock Control Channel** | `VZVirtioSocketDeviceConfiguration` | Enabled unless `--no-vphoned` |
| **Synthetic Battery** | `VZMacBatteryPowerSourceDeviceConfiguration` + `VZMacSyntheticBatterySource` | Runtime charge and state control |
| **SEP Coprocessor** | `VZSEPCoprocessorConfiguration` | Storage and optional ROM with debug stub |
| **Kernel GDB Stub** | `VZGDBDebugStubConfiguration` | Auto-assigned or user-specified port |

Private-API devices follow a consistent pattern: `Dynamic._VZ…` creates the hidden object, then `Dynamic(config)._set…` attaches it to the configuration.

## Validation and VM Lifecycle

Once assembled, the configuration undergoes framework validation before instantiation:

```swift
try config.validate()
let virtualMachine = VZVirtualMachine(configuration: config)
virtualMachine.delegate = self

```

`VPhoneVirtualMachine` conforms to `VZVirtualMachineDelegate`, handling guest termination, errors, and network device disconnections. All delegate callbacks log events and exit the host process appropriately.

Post-launch, VPhoneCore prints the automatically assigned kernel-debug port (macOS 26+ only) and wires the VM's serial output to host stdout.

## Manifest-Driven Configuration

[`VPhoneVirtualMachineManifest.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachineManifest.swift) defines the codable representation of persistent VM state. The manifest stores CPU count, memory, screen parameters, network mode, storage paths, ROM locations, and SEP configuration. At startup, `VPhoneVirtualMachineManifest.load(from:)` deserializes this state; new machine identifiers are generated and persisted back to disk.

## Building a VM from Manifest: Complete Example

```swift
import VPhoneCore

let manifestURL = URL(fileURLWithPath: "config.plist")
let manifest = try VPhoneVirtualMachineManifest.load(from: manifestURL)

let options = VPhoneVirtualMachine.Options(
    configURL: manifestURL,
    romURL: nil,
    nvramURL: URL(fileURLWithPath: "nvram.bin"),
    diskURL: URL(fileURLWithPath: "Disk.img"),
    cpuCount: 8,
    memorySize: 8 * 1024 * 1024 * 1024,
    sepStorageURL: URL(fileURLWithPath: "SEPStorage"),
    sepRomURL: nil,
    screenWidth: 1290,
    screenHeight: 2796,
    screenPPI: 460,
    screenScale: 3.0,
    kernelDebugPort: nil,
    variant: .regular,
    noVphoned: false
)

let vm = try VPhoneVirtualMachine(options: options)
try await vm.start(forceDFU: false)          // Normal boot

```

## Runtime Control and Guest Communication

VPhoneCore provides runtime manipulation through several channels:

**Synthetic battery updates:**

```swift
vm.setBattery(charge: 45.0, connectivity: 2) // 45% charge, disconnected

```

**DFU mode for low-level flashing:**

```swift
try await vm.start(forceDFU: true)           // Boots into DFU, ready for irecovery

```

The vsock-based control channel ([`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift)) enables host-guest communication through `VZVirtioSocketDeviceConfiguration`. This channel supports IPA installation, screen recording, and other management operations without requiring network connectivity.

## Key Source Files

The VPhoneCore library spans multiple files with distinct responsibilities:

- [`sources/vphone-cli/VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVirtualMachine.swift) — Core class assembling `VZVirtualMachineConfiguration` and driving VM lifecycle
- [`sources/VPhoneCore/VPhoneVirtualMachineManifest.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneVirtualMachineManifest.swift) — Codable manifest for persistent VM parameters
- [`sources/vphone-cli/VPhoneHardwareModel.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneHardwareModel.swift) — PV-3 hardware model creation helper
- [`sources/VPhoneCore/VPhoneNetworking.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/VPhoneCore/VPhoneNetworking.swift) — Network device factory for NAT/bridged/off modes
- [`sources/vphone-cli/VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneControl.swift) — Host-side vsock client for guest daemon communication
- [`sources/vphone-cli/VPhoneMenuRecord.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneMenuRecord.swift) — UI layer exposing VM controls to users
- [`sources/vphone-cli/VPhoneIPAInstaller.swift`](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneIPAInstaller.swift) — IPA installation via vsock channel

## Summary

- **VPhoneCore library integrates with Virtualization.framework** by translating a manifest into a complete `VZVirtualMachineConfiguration` in [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift)
- **Private API access** through the `Dynamic` library enables touch screen, accelerators, and DFU booting that lack public SwiftPM headers
- **Hardware modeling** uses `VZMacHardwareModel` (PV-3) with persistent `VZMacMachineIdentifier` and ECID-derived UDID
- **Device configuration** spans 15+ Virtualization.framework classes covering compute, graphics, storage, network, audio, serial, and security subsystems
- **Runtime control** operates through synthetic battery APIs, vsock socket device, and optional kernel GDB debug stub

## Frequently Asked Questions

### What is the `Dynamic` library used for in VPhoneCore?

The `Dynamic` library provides runtime Objective-C method dispatch to access private Virtualization.framework APIs that Apple does not expose in public SwiftPM headers. VPhoneCore uses `Dynamic` to inject ROM URLs, attach accelerator devices (VideoToolbox, Neural Engine, Scaler), enable multi-touch screens, and set DFU boot flags without compile-time symbol resolution.

### How does VPhoneCore persist VM state between launches?

VM state persists through `VPhoneVirtualMachineManifest`, a Codable struct stored as a property list. The manifest records CPU count, memory allocation, screen dimensions, network mode, storage paths, ROM locations, machine identifier, and SEP configuration. On startup, `VPhoneVirtualMachineManifest.load(from:)` deserializes this state; new identifiers are generated and written back when created.

### Can VPhoneCore run on any Apple Silicon Mac?

VPhoneCore requires macOS with Virtualization.framework support and Apple Silicon hardware. Specific features like the automatically assigned kernel-debug port require macOS 26 or later. Some functionality depends on private APIs that may change between macOS versions.

### How does the vsock control channel work without network connectivity?

VPhoneCore uses `VZVirtioSocketDeviceConfiguration`—a paravirtualized socket device that operates independently of network stack configuration. The host-side [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift) connects to the guest's `vphoned` daemon through this channel, enabling management operations even when the VM's `VZVirtioNetworkDeviceConfiguration` is disabled or misconfigured.