Running macOS in a virtual machine on Apple silicon
Install and run macOS in a virtual machine using the Virtualization framework.
Overview
This sample code project demonstrates how to install and run macOS virtual machines (VMs) on Apple silicon. The Xcode project includes two separate apps:
InstallationTool, a command line utility that installs macOS from a restore image, which is a file with a.ipswfile extension, onto a VM. You can use this tool to download the restore image of the most current macOS release from the network, or with your own restore image. The utility creates a VM bundle and stores the resulting VM images in your Home directory.macOSVirtualMachineSampleAppis a Mac app that runs the macOS VM thatInstallationToolinstalls. You usemacOSVirtualMachineSampleAppto launch and control the macOS VM that loads and runs macOS from the VM bundle. This app includes entitlements to enable it to use Virtualization and access the VM’s’ audio input, such as the microphone.
There are four build targets in this project that represent the InstallationTool and the macOSVirtualMachineSampleApp, one set of targets each for Swift and Objective-C versions of the apps. You can use either version, they’re functionally identical.
Configure the sample code project
You need to install the virtual machine, and VM.bundle needs exist before launching the sample app.
Set up code signing for each of the project’s targets by navigating to the Signing & Capabilities settings and selecting your team from the drop-down menu.
Run
InstallationToolfrom within Xcode or in Terminal to download the latest available macOS restore image from the network and create a macOS VM image on disk.InstallationToolcreates aVM.bundlepackage in your Home directory, containing:Disk.img— The main disk image of the installed OS.AuxiliaryStorage— The auxiliary storage for macOS.MachineIdentifier— The data representation of theVZMacMachineIdentifierobject.HardwareModel— The data representation of theVZMacHardwareModelobject.RestoreImage.ipsw— The restore image downloaded from the network (this file exists only if the tool runs without arguments).
Launch
macOSVirtualMachineSampleAppto run the macOS guest operating system. The sample app starts the VM and configures a graphical view that you interact with. The virtual Mac continues running until you shut it down from inside the guest OS, or quit the app.To reinstall the virtual machine, delete the
VM.bundlepackage and runInstallationToolagain.
Install macOS from a restore image
After downloading a restore image, you can install macOS from that restore image.
Set up the virtual machine
The sample app uses a VZVirtualMachineConfiguration object to configure the basic characteristics of the guest, such as the CPU count, memory size, various device configurations, and a VZMacOSBootLoader object to load the operating system from the disk image, as the following example shows:
Inside the createVirtualMachine method, the app also creates a platform configuration for the VM. VZMacPlatformConfiguration configures important macOS-specific data that the macOS guest needs to run, including the specific hardwareModel that the image supports, as well as a machineIdentifier that uniquely identifies the current VM instance and differentiates it from any others.
After creating the platform configuration, the app creates an instance of VZVirtualMachineConfiguration and adds video, virtual drives, and other devices to the system.
The Virtualization framework checks the configuration to make sure it supports saving and restoring.
Start the VM
After building the configuration data for the VM, the sample app uses the VZVirtualMachine object to start the execution of the macOS guest operating system.
Before calling the start(completionHandler:) or restoreMachineStateFrom(url:completionHandler:) methods, the sample app configures a delegate object to receive messages about the state of the virtual machine. When the macOS guest operating system shuts down, the virtual machine calls the delegate’s guestDidStop(_:) method. In response, the delegate method prints a message and exits the app. If the macOS guest stops for any reason other than a normal shutdown, the delegate prints an error message and the app exits.
If the virtual machine was running when the sample app last exited, the app calls restoreVirtualMachine to restore the state. If the virtual machine was in a shutdown state, the app calls startVirtualMachine to reboot the machine. Both methods start the VM asynchronously in the background. The VM loads the system image and boots macOS. After macOS starts, the user interacts with a VZVirtualMachineView window that displays the macOS UI and handles keyboard and mouse input through a VZMacGraphicsDeviceConfiguration as though the user is interacting directly with the Mac hardware. The VZVirtualMachineView automatically resizes the virtual machine display when window size changes, and to capture system keys such, as the Globe key on a Mac keyboard.
The startVirtualMachine method calls the VM’s start(completionHandler:) method.
Or, if the app previously had the VM save its state to SaveFile.vzvmsave, restoreVirtualMachine calls the VM’s restoreMachineStateFrom(url:completionHandler:) and resume(completionHandler:) methods.
If the restore fails, the framework causes the virtual machine to reboot. In either case, the framework deletes SaveFile.vzvmsave after restore completes because the VM disk no longer matches the state in the file.
Save the VM
When you close the sample app, it calls the VM’s pause(completionHandler:) and saveMachineStateTo(url:completionHandler:) methods. This captures the runtime state of the VM to SaveFile.vzvmsave, which the app uses when calling startOrRestoreVirtualMachine to resume running the VM at the same point when you relaunch the sample app.
The system defers app termination until the saveMachineStateTo(url:completionHandler:) method completes.