# How to Boot a Virtual iPhone Using Virtualization.framework with vphone-cli

> Learn how vphone-cli boots a virtual iPhone using Apple's Virtualization.framework. Discover its pure Swift implementation for orchestrating virtual device lifecycles.

- Repository: [Lakr/vphone-cli](https://github.com/Lakr233/vphone-cli)
- Tags: how-to-guide
- Published: 2026-09-05

---

**vphone-cli boots a virtual iPhone by constructing a PV=3 hardware model, configuring a `VZVirtualMachine` with kernel and ramdisk assets, and orchestrating the complete lifecycle through Apple's Virtualization.framework using pure Swift.**

The open-source tool vphone-cli demonstrates how to leverage Apple's Virtualization.framework to run iOS firmware in a virtualized environment on macOS. This article examines the precise sequence of steps the CLI tool follows to boot a virtual iPhone, from parsing command-line arguments to establishing host-guest communication channels.

## Parsing CLI Arguments and Boot Options

The boot process begins in [`VPhoneCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneCLI.swift) and related command-line handlers such as [`VPhoneVMLaunchCLI.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVMLaunchCLI.swift). These components parse user-specified options including the **firmware variant**, RAM allocation, and display settings.

The parsed configuration is stored in a `VPhoneVirtualMachine.Options` structure, which serves as the single source of truth for the VM's hardware and boot parameters. This options object propagates through the initialization chain to configure the virtual hardware accurately.

## Constructing the Hardware Model

Before the Virtualization.framework can instantiate a VM, it requires a valid hardware model descriptor. The file [`VPhoneHardwareModel.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneHardwareModel.swift) generates a **PV=3** hardware model using the Dynamic library to access private API surfaces.

This model supplies essential device descriptors for the **CPU**, **GPU**, and other virtualized components required by the framework. Without this specific hardware model construction, the Virtualization.framework would reject the configuration when attempting to boot iOS firmware.

## Configuring the Virtual Machine

The core configuration logic resides in [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift). Here, the tool creates a `VZVirtualMachineConfiguration` and populates it with critical parameters:

- **`configuration.hardwareModel`** is set to the PV=3 model constructed earlier
- **Boot resources** include the kernel and ramdisk derived from the selected firmware files
- **Graphics configuration** uses `VZMacGraphicsDeviceConfiguration` to enable high-resolution display and touch input forwarding
- **Network communication** is established via a **vsock** listener on port **1337** for host-guest communication

This configuration object encapsulates the complete virtual hardware environment before instantiation.

## Instantiating and Starting the VM

Once configured, [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) creates the actual `VZVirtualMachine` instance. Because UI-related actions require the main thread, this creation occurs on the **@MainActor**.

The `boot()` method initiates execution by calling `virtualMachine.start(completionHandler:)`. The completion handler logs success or failure, and upon successful boot, initializes the **vsock** client ([`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift)) to communicate with the guest daemon.

```swift
import VPhoneCLI

let options = VPhoneVirtualMachine.Options(
    firmwareVariant: .regular,
    ramSizeGB: 4,
    displayScale: 2.0
)

let vm = try VPhoneVirtualMachine(options: options)
try vm.boot()  // Starts the VZVirtualMachine

```

## Rendering the Display and Handling Input

User interaction requires two specialized components. [`VPhoneVirtualMachineView.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachineView.swift) provides a subclass of `VZVirtualMachineView` that renders the VM's framebuffer to the screen.

[`VPhoneWindowController.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneWindowController.swift) embeds this view within an `NSWindow` and attaches `VPhoneKeyHelper` to forward host keyboard events and hardware-key signals into the virtual iPhone. This creates a seamless bridge between physical input devices and the virtualized iOS environment.

## Communicating with the Guest Daemon

After the VM boots, the host-side `VPhoneControl` class opens a vsock connection to the guest daemon (**vphoned**). This daemon launches automatically via the VM's init scripts and exposes a control interface for advanced operations.

Through this channel, vphone-cli issues commands for **IPA installation**, **screen recording**, and **location synchronization**. The vsocket connection on port 1337 serves as the primary command-and-control interface throughout the VM's lifecycle.

```swift
let control = VPhoneControl()
control.connect { result in
    switch result {
    case .success:
        control.send(json: ["command": "ping"])
    case .failure(let error):
        print("Failed to connect:", error)
    }
}

```

## Lifecycle Management and Cleanup

The [`VPhoneAppDelegate.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneAppDelegate.swift) file manages the application's main run-loop and monitors for termination signals. When the user sends **SIGINT** or closes the window, the delegate invokes `virtualMachine.stop()` to gracefully shut down the guest.

This cleanup sequence ensures proper resource deallocation and prevents corruption of the virtual disk images. The tool exits cleanly only after the Virtualization.framework confirms the VM has terminated.

To build and run the tool from source:

```bash

# Build the signed binary (required entitlements)

make build

# Boot the VM with the default (regular) firmware

./.build/release/vphone-cli boot

```

## Summary

- **vphone-cli** uses [`VPhoneHardwareModel.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneHardwareModel.swift) to generate a PV=3 hardware model required by Virtualization.framework for iOS boot compatibility.
- The [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) file constructs a complete `VZVirtualMachineConfiguration` including graphics, storage, and vsock networking on port 1337.
- VM instantiation occurs on **@MainActor** due to UI requirements, with the `boot()` method calling `start(completionHandler:)` to begin execution.
- Input handling combines [`VPhoneVirtualMachineView.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachineView.swift) for framebuffer rendering and `VPhoneKeyHelper` for keyboard event forwarding.
- Host-guest communication relies on [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift) connecting to the **vphoned** daemon via vsock for runtime management commands.

## Frequently Asked Questions

### What hardware model does vphone-cli use for virtual iPhone compatibility?

vphone-cli generates a **PV=3** hardware model through [`VPhoneHardwareModel.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneHardwareModel.swift) using the Dynamic library. This private-API-friendly approach provides the specific CPU, GPU, and device descriptors that Virtualization.framework requires to boot iOS firmware rather than macOS.

### Why must the VZVirtualMachine be created on @MainActor?

The `VZVirtualMachine` instance requires the main thread because it interacts with UI components such as `VZVirtualMachineView` and window management systems. [`VPhoneVirtualMachine.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneVirtualMachine.swift) ensures all initialization and boot sequences run on **@MainActor** to satisfy these framework constraints.

### How does the host communicate with the virtual iPhone after boot?

Once running, the host opens a **vsock** connection on port **1337** via [`VPhoneControl.swift`](https://github.com/Lakr233/vphone-cli/blob/main/VPhoneControl.swift) to reach the guest **vphoned** daemon. This daemon, launched by the VM's init scripts, handles commands for installing IPAs, recording the screen, and synchronizing location data between host and guest.