# How vphone-cli Configures Its Virtual Machine: A Complete Technical Deep Dive

> Discover how vphone-cli configures its virtual machine using Virtualization.framework. Learn about CPU, memory, hardware, and more in this technical deep dive.

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

---

**vphone-cli configures its virtual machine by leveraging Apple's Virtualization.framework through a Swift wrapper that builds a VZVirtualMachineConfiguration with CPU, memory, hardware model, graphics device, vsock channel, and optional USB passthrough.**

The `vphone-cli` project demonstrates how to run virtualized iOS devices on Apple Silicon Macs. This article examines the exact VM configuration mechanism, walking through the source files and architecture that make this possible.

## Core Architecture Overview

vphone-cli follows a layered design built on top of Apple's native virtualization APIs. The configuration pipeline spans five primary Swift files in the `sources/vphone-cli/` directory, each handling a distinct responsibility in the VM lifecycle.

### Key Source Files

| File | Responsibility |
|------|---------------|
| [VPhoneVirtualMachine.swift](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVirtualMachine.swift) | Builds and manages the `VZVirtualMachine` instance |
| [VPhoneHardwareModel.swift](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneHardwareModel.swift) | Supplies the private iOS hardware model via runtime API calls |
| [VPhoneVirtualMachineView.swift](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneVirtualMachineView.swift) | Hosts the `VZVirtualMachineView` UI surface |
| [VPhoneControl.swift](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneControl.swift) | Manages the vsock control channel for host-guest communication |
| [VPhoneAppDelegate.swift](https://github.com/Lakr233/vphone-cli/blob/main/sources/vphone-cli/VPhoneAppDelegate.swift) | Entry point that parses CLI arguments and orchestrates VM startup |

## Virtual Machine Configuration Pipeline

The VM configuration process follows a strict five-phase pipeline from CLI arguments to running virtualized iPhone.

### Phase 1: CLI Argument Parsing

[`VPhoneAppDelegate.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneAppDelegate.swift) uses **ArgumentParser** to transform command-line flags into structured options. The `VPhoneVirtualMachine.Options` struct captures all tunable parameters:

```swift
import ArgumentParser

struct Options {
    var cpus: Int
    var memoryGB: Int
    var gpuMode: GPUMode        // .headless or .windowed
    var bootMode: BootMode      // .gui or .dfu
    var usbPassthrough: [String]
}

```

Common invocations include `vphone-cli boot --cpus 4 --memory 8 --gpu windowed` for a standard graphical session, or `vphone-cli boot --gpu headless` for CI/automation scenarios.

### Phase 2: Hardware Model Resolution

Before constructing the VM, `VPhoneVirtualMachine` calls `VPhoneHardwareModel.make()` to obtain the required iPhone hardware model. This is where vphone-cli diverges from standard macOS virtualization.

In [`VPhoneHardwareModel.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneHardwareModel.swift), the code uses the **Dynamic** library (`https://github.com/mhdhejazi/Dynamic`) to call private `Virtualization.framework` APIs at runtime:

```swift
import Dynamic

class VPhoneHardwareModel {
    static func make() throws -> VZMacHardwareModel {
        // Load the PV=3 hardware model for Apple Silicon iOS VMs
        let modelData = try Data(contentsOf: Bundle.main.url(
            forResource: "vphone.entitlements",
            withExtension: nil
        )!)
        
        // Runtime invocation of private API via Dynamic
        let hardwareModel = Dynamic._VZMacHardwareModel(
            data: modelData,
            options: [:]
        )
        
        return hardwareModel.asAnyObject as! VZMacHardwareModel
    }
}

```

The `vphone.entitlements` file bundled in the app resources contains the device tree and entitlement blob that identifies this as an iPhone-class VM rather than a generic macOS guest.

### Phase 3: Configuration Assembly

The `VPhoneVirtualMachine.init(options:)` method in [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) assembles the complete `VZVirtualMachineConfiguration`:

```swift
import Virtualization

class VPhoneVirtualMachine {
    let virtualMachine: VZVirtualMachine
    let virtualMachineConfiguration: VZVirtualMachineConfiguration
    
    init(options: Options) throws {
        let config = VZVirtualMachineConfiguration()
        
        // Compute resources
        config.cpuCount = options.cpus
        config.memorySize = UInt64(options.memoryGB) * 1024 * 1024 * 1024
        
        // Hardware model (iOS-specific, via private API)
        config.hardwareModel = try VPhoneHardwareModel.make()
        
        // Graphics device configuration
        let graphicsConfiguration = VZMacGraphicsDeviceConfiguration()
        graphicsConfiguration.isHeadless = (options.gpuMode == .headless)
        config.graphicsDevices = [graphicsConfiguration]
        
        // Vsock device for host-guest control channel
        let vsockConfig = VZVirtioVsockDeviceConfiguration()
        vsockConfig.port = 1337
        config.serialPorts = [vsockConfig]
        
        // Optional USB controller for device passthrough
        if !options.usbPassthrough.isEmpty {
            let usbConfig = VZUSBControllerConfiguration()
            // USB device attachments configured per product/vendor ID
            config.usbControllers = [usbConfig]
        }
        
        // Validate before instantiation
        try config.validate()
        
        self.virtualMachineConfiguration = config
        self.virtualMachine = VZVirtualMachine(configuration: config)
    }
}

```

Each configuration property maps directly to Virtualization.framework capabilities:

- **`cpuCount` and `memorySize`**: Exposed hardware resources visible to the iOS guest
- **`hardwareModel`**: The critical iPhone device identity (PV=3) that enables iOS booting
- **`graphicsDevices`**: `VZMacGraphicsDeviceConfiguration` with headless/windowed toggle
- **`serialPorts`**: Actually configures `VZVirtioVsockDeviceConfiguration` for the control channel
- **`usbControllers`**: Optional passthrough for debugging hardware interaction

### Phase 4: VM Instantiation and Startup

With a validated configuration, the VM object is created and started asynchronously:

```swift
extension VPhoneVirtualMachine {
    func start(completion: ((Result<Void, Error>) -> Void)? = nil) {
        virtualMachine.start { result in
            completion?(result)
        }
    }
    
    var state: VZVirtualMachineState {
        virtualMachine.state
    }
}

```

The `VZVirtualMachine` state machine transitions through `.starting`, `.running`, `.stopped`, or `.error` states. `VPhoneVirtualMachineView` observes these through a delegate implementation.

### Phase 5: UI Integration and Event Forwarding

[`VPhoneVirtualMachineView.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachineView.swift) embeds the native `VZVirtualMachineView` into an AppKit window and forwards input:

```swift
import Cocoa

class VPhoneVirtualMachineView: NSView {
    private let vmView: VZVirtualMachineView
    
    init(virtualMachine: VZVirtualMachine) {
        self.vmView = VZVirtualMachineView()
        self.vmView.virtualMachine = virtualMachine
        super.init(frame: .zero)
        
        self.addSubview(vmView)
        // Auto-layout constraints...
    }
    
    override func mouseDown(with event: NSEvent) {
        vmView.send(event)
    }
    
    override func keyDown(with event: NSEvent) {
        vmView.send(event)
    }
}

```

This integration enables the interactive "boot (GUI)" target that users invoke with `make boot`.

## Host-Guest Communication via Vsock

A critical aspect of VM configuration is the **vsock control channel** on port 1337. [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift) implements a length-prefixed JSON protocol over this channel to communicate with `vphoned`, the daemon running inside the iOS guest:

```swift
import Foundation

class VPhoneControl {
    private let vsockDevice: VZVirtioVsockDevice
    
    init(vm: VPhoneVirtualMachine) {
        self.vsockDevice = vm.virtualMachineConfiguration.serialPorts
            .first { $0 is VZVirtioVsockDeviceConfiguration } as! VZVirtioVsockDevice
    }
    
    func send(json: [String: Any], completion: @escaping (Result<[String: Any], Error>) -> Void) {
        // Serialize JSON with length prefix
        let data = try! JSONSerialization.data(withJSONObject: json)
        var lengthPrefix = UInt32(data.count).bigEndian
        let packet = Data(bytes: &lengthPrefix, count: 4) + data
        
        // Transmit via vsock port 1337
        vsockDevice.write(packet, to: 1337) { result in
            // Handle response...
        }
    }
}

```

This channel supports operations like:

- Application installation (IPA sideloading)
- Screenshot capture
- System logs streaming
- Process lifecycle management

## Inspecting a Running VM Configuration

You can programmatically inspect the active configuration of a `VPhoneVirtualMachine` instance:

```swift
let vm = try VPhoneVirtualMachine(options: options)

let config = vm.virtualMachineConfiguration
print("CPU cores:    \(config.cpuCount)")
print("Memory:       \(config.memorySize / 1_073_741_824) GiB")

if let hwModel = config.hardwareModel {
    print("Hardware:     \(hwModel.dataRepresentation.count) bytes model data")
}

for (index, graphics) in config.graphicsDevices.enumerated() {
    if let macGraphics = graphics as? VZMacGraphicsDeviceConfiguration {
        print("Graphics [\(index)]: \(macGraphics.isHeadless ? "headless" : "windowed")")
    }
}

for (index, serial) in config.serialPorts.enumerated() {
    if let vsock = serial as? VZVirtioVsockDeviceConfiguration {
        print("Vsock [\(index)]: port \(vsock.port)")
    }
}

```

## Build Integration and Usage

The project uses a **Makefile** with Swift Package Manager targets. Key commands that exercise the VM configuration:

```bash

# Build the CLI

make build

# Boot with GUI (uses windowed GPU mode)

make boot

# Boot headless for automation

./.build/debug/vphone-cli boot --gpu headless

# Install IPA via vsock control channel

./.build/debug/vphone-cli install ./app.ipa

```

The Swift Package declares platform requirements as `.macOS(.v14)` since Virtualization.framework's iOS guest support requires macOS Sonoma or later.

## Summary

- **vphone-cli configures VMs through [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift)**, which constructs a `VZVirtualMachineConfiguration` with CPU, memory, hardware model, graphics, and vsock settings.
- **Hardware model resolution requires private APIs**, accessed via the Dynamic library in [`VPhoneHardwareModel.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneHardwareModel.swift) to obtain the iPhone-specific PV=3 model.
- **Graphics configuration supports headless and windowed modes** through `VZMacGraphicsDeviceConfiguration`, enabling both CI and interactive use cases.
- **The vsock channel on port 1337** provides structured host-guest communication for control operations via [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift).
- **UI integration in [`VPhoneVirtualMachineView.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachineView.swift)** wraps `VZVirtualMachineView` for touch and keyboard event forwarding to the iOS guest.

## Frequently Asked Questions

### What virtualization technology does vphone-cli use?

vphone-cli uses **Apple's Virtualization.framework**, specifically the private iOS guest support available on Apple Silicon Macs running macOS Sonoma or later. The framework provides the underlying `VZVirtualMachine`, `VZVirtualMachineConfiguration`, and `VZMacGraphicsDeviceConfiguration` APIs that vphone-cli wraps.

### Why does vphone-cli need private APIs for hardware model configuration?

Standard `Virtualization.framework` APIs only expose macOS guest support. iOS virtualization requires a **PV=3 hardware model** with specific device tree structures and entitlements that Apple does not publicly document. vphone-cli uses the Dynamic library to call these private APIs at runtime, loading the required model data from its bundled `vphone.entitlements` resource.

### How does the vsock control channel work between host and guest?

The VM configuration includes a **VZVirtioVsockDeviceConfiguration** on port 1337. The host-side `VPhoneControl` class implements a length-prefixed JSON protocol over this channel, while the iOS guest runs `vphoned` (a daemon inside the virtualized system) that receives and responds to commands. This enables IPA installation, screenshots, and log streaming without network stack dependencies.

### Can vphone-cli run on Intel Macs or older macOS versions?

No. iOS guest virtualization requires **Apple Silicon (M1/M2/M3)** and **macOS 14 (Sonoma)** or later. The Virtualization.framework APIs for iOS guests are unavailable on Intel hardware and were introduced in macOS 14. The [`Package.swift`](https://github.com/Lakr233/vphone-cli/blob/main/Package.swift) enforces these constraints through `.macOS(.v14)` platform requirements.