A snapshot has a title, a date, a size, a screenshot and the snapshot it
was based on. None of that fits in the image formats the backends use, so
keep it in a new `snapshots.plist` in the VM bundle where each entry links
to the state in the backend by identifier.
The file also remembers which snapshot the current state came from and
which state the VM resumes from while it is suspended, along with the
states that are no longer needed but could not be deleted yet.
Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
DiskImageKit can put a copy-on-write layer on an image and remembers what
each layer sits on. Use that to freeze the contents of a drive: the layer
holding what the guest has written so far is closed off under the name of a
snapshot and a fresh one is opened above it for further writes.
Layers are kept beside the image as `<image>.<name>.asif`. A layer whose
snapshot is deleted cannot be merged away while other layers are stacked on
it, so it is only marked as unlinked and is swept once nothing needs it.
Attachments are built through the same path so that a drive with layers is
opened as the whole stack, and a disposable run adds its throwaway layer on
top of it.
A stack is only ever opened whole. When one of its layers cannot be read the
drive is not attached at all: opening the rest without it would hide what it
holds, and falling back to the bare image would write underneath every layer
stacked on it. For the same reason a layer to write to is always put in place
before the one it replaces goes, and the image under a stack cannot be resized.
Nor can a drive with layers be attached read only, which a stack cannot be, or
before macOS 27, which cannot read the layers: the image alone is the drive as
it was before the first snapshot. Removable media never has layers.
Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
macOS 27 lets the host manage Secure Boot state in the EFI variable
store. Add a persisted flag and a toggle in the Boot settings so generic
UEFI guests on the Apple backend can opt in. The state is reconciled when
the configuration is saved, using the default platform key and the
default Microsoft signatures so that mainstream Linux distributions boot
unmodified. The store is only written when its state differs from the
configuration, and a virtual machine with the option off never fails to
save because of it. The option defaults to off because guests without a
Microsoft-signed bootloader would otherwise stop booting.
Assisted-by: Claude:claude-fable-5-1
"Run without saving changes" has only been available for QEMU, where it
maps to `-snapshot`. Apple Virtualization has no such option, but
DiskImageKit on macOS 27 can stack a copy-on-write layer on top of an
image and Virtualization accepts the stacked image as a storage
attachment.
When started with the disposable option, the Apple backend now creates a
temporary directory in the sandbox and gives every writable drive an
ephemeral ASIF overlay there. The base image is opened read-only and is
never touched. The EFI variable store and the macOS auxiliary storage are
cloned into the same directory so firmware settings are not persisted
either. The directory is deleted when the guest stops or when start
fails, any leftover from a previous start is discarded before the next
start, and directories orphaned by a crash are swept at app launch.
Removable drives attached at start or hot-plugged during the run are
covered as well.
A disposable run boots fresh and leaves any saved suspend state and the
modification date alone, and reports the save/restore path as
unsupported so closing the window offers to kill the VM instead of
suspending it, matching the QEMU behaviour. The stop paths that delete a
saved suspend state skip that while running disposably.
The context menu, the Start intent and the menu bar extra now check the
backend capability instead of assuming QEMU, and the Apple display window
shows the same "Disposable Mode" subtitle as QEMU.
Assisted-by: Claude:claude-fable-5-1
ASIF drives for Apple Virtualization are created, inspected and resized
through the private DiskImages2 framework, loaded by path and called via
NSInvocation. macOS 27 ships DiskImageKit, a public Swift-only framework
that covers the same operations and is what Virtualization.framework now
consumes directly.
Add UTMAppleDiskImage, a Swift wrapper that uses DiskImageKit on macOS 27
and later and falls back to the existing UTMASIFImage helper on macOS 13
through 26. The legacy path is confined to one private extension so it
can be deleted together with UTMASIFImage once the minimum host is
macOS 27. DiskImageKit is weak linked because the deployment target is
below macOS 27.
Callers switch to the wrapper; the resize path no longer force-unwraps
the helper.
Assisted-by: Claude:claude-fable-5-1
Follow-up to the vmnet networking modes:
- Rename "Shared Network (VM to VM)" to "NAT Network" (config value
"NATNetwork", scripting term "nat network") so the picker does not offer
two "Shared" modes that differ only by a suffix.
- Request a fixed subnet per mode outside of the ranges vmnet hands out by
default. Those ranges are also used by NAT attachments and QEMU, so guest
addresses depended on what else was running whenever the network was
(re)created. Fall back to a vmnet chosen subnet when ours is taken.
- Show the mode description with DetailedSection. The bare Text row widened
the form and clipped the labels and controls in the settings window.
- Only require macOS 26 when a network is actually created, so a VM using
one of these modes can still be edited and saved on older hosts.
- Do not apply locale digit grouping to the vmnet error code.
- Fold the validation flag into the existing one that skipped drives and
leave the device unattached instead of using a NAT placeholder, remove
the unused reverse mapping, key the networks by vmnet_mode_t, and isolate
the manager to the main actor in place of a lock with no concurrent users.
Use .1 as the host-side address within each preferred /24. As reproduced
in PR #7865, vmnet accepts .0 during network creation but the interface
fails later at startup.
Assisted-by: Claude:claude-fable-5-1
Assisted-by: ChatGPT:GPT-6-Astra-Pro
Apple Virtualization's existing Shared Network uses a separate NAT
attachment per VM, so guests cannot use it to reach each other. macOS 26
adds VZVmnetNetworkDeviceAttachment, which lets multiple VMs attach to the
same process-owned vmnet network.
Add two macOS 26+ modes:
- "Shared Network (VM to VM)": guests share a NAT-backed vmnet network and
can reach each other, the host, and external networks.
- "Host Only": guests share a host-only vmnet network and can reach each
other and the host without external routing.
UTMAppleVmnetNetworkManager keeps a weak attachment cache per mode while
Virtualization configuration and runtime objects own the attachment and its
native network. The network therefore follows the actual VZ object lifetime
rather than UTM's presentation state, including failure paths where a VZ VM
can remain alive after UTM reports it stopped. Configuration validation uses
a side-effect-free placeholder so saving a VM does not create a live vmnet
network.
Hide both modes before macOS 26 and add matching scripting enumerators and
round-trip parsing.
Resolves#6975.
Related to #7418 and #7380.
Assisted-by: Claude:claude-fable-5-1
Assisted-by: ChatGPT:GPT-6-Pro
Assisted-by: ChatGPT:GPT-5.6-Sol
Apple Virtualization VMs could not share host USB devices. macOS 27 adds
public APIs for this: AccessoryAccess.framework reports devices the user
assigned to UTM in the system "Virtual Machine Accessories" menu bar item and
VZUSBPassthroughDevice captures them, so the private API approach from the
abandoned branch is no longer needed.
Devices are reported once per process to UTMAppleUSBManager. A newly assigned
device is connected to the only running VM, or to the VM whose window is in
front when several are running, so the user does not have to select it twice.
The USB menu of the Apple VM window lists assigned devices and can move a
device from another VM after confirmation. A device the user disconnects from
the menu stays assigned to UTM but is not connected again until asked, since
the system reports it again right after it is detached. The VM label is set so
the system menu names the VM.
Connected devices are recorded with their UUID when the VM state is saved and
added to the configuration before the state is restored, so the guest keeps
the device across a suspend. A device that is missing at restore is skipped
and the guest sees it unplugged; the restore itself still succeeds.
Requires the com.apple.developer.accessory-access.usb entitlement.
Assisted-by: Claude:claude-fable-5-1
Now that the deployment targets are iOS 15 and macOS 12, every guard,
fallback and workaround for an older release is dead code that only
obscures what the supported path is. Remove them:
- Drop the `@available` attributes for iOS 15, macOS 11 and macOS 12, and
unwrap the matching `#available`/`#unavailable` guards in Swift and the
`@available`/`API_AVAILABLE`/`NS_AVAILABLE_IOS` ones in Objective-C.
- Delete the legacy-only views and helpers left unreachable by that:
NumberTextFieldOld, VMConfigNetworkPortForwardLegacyView,
VMContextMenuModifier.bodyBigSur, the nonbrokenSheet, uniqued,
customBadge, borderedList and legacySettingsToolbar shims, the
.unsupported BootloaderSelection case, and the iOS 14 sacrificial
version Section in the QEMU settings list.
- jb_has_cs_execseg_allow_unsigned() has returned false for every host
since iOS 14.4, so drop it along with the is_device_A12_or_newer()
helper that only it used. The entitlement parser no longer needs to
copy the blob either, since that copy existed only so the psychic paper
needle could be blanked in place.
- VMDisplayTerminalViewController tracked the keyboard frame by hand for
iOS 14. `useAutoLayout` is a constant that cannot be overridden, so
nothing ever registered the notification observers and only the
keyboardLayoutGuide path is reachable.
- VMConfigQEMUView's additionalArguments is now referenced on iOS only,
which leaves its macOS branch, and the macOS 11 ForEach crash
workaround inside it, unreachable.
- Raise the Cydia package floor and the postinst/prerm helpers to match
the new minimum.
Two of the removed guards dropped an error path rather than just a
branch. The shared directory `featureNotSupported` throw covered
VZVirtioFileSystemDeviceConfiguration and friends being macOS 12+, which
no longer applies to any supported host. The macOS guest
`platformUnsupported` throw when decoding a boot config on Intel only
fired on macOS 11; the Apple Silicon requirement it really guards is
enforced unconditionally in
UTMAppleConfigurationSystem.fillVZConfiguration, which both the start and
the save path go through.
Assisted-by: Claude:claude-opus-5
The nearest-neighbour default (ba5f7f7f, #3371) was chosen for
low-resolution guests, where linear washes out already-chunky text. It is
the wrong choice everywhere else: a modern guest rarely upscales by an
integer ratio, so nearest duplicates source pixels unevenly and looks
blocky rather than sharp -- the complaint behind #6209 and #6572.
Default to linear and let the wizard select nearest for the guests the
original change was about: Classic Mac OS, Windows 7 and below, and any OS
configured for legacy hardware. Legacy hardware is checked on its own
rather than folded into the Windows case so that choosing a legacy machine
opts in under any OS, and because the summary page can enable it after the
Windows page has already latched isWindows10OrHigher.
Existing VMs are unaffected: upscalingFilter is a required coding key, so
a saved configuration always carries its own value. The UTM 2.x migration
path is likewise unchanged, since an absent displayUpscaler already
defaulted to linear.
Assisted-by: Claude:claude-opus-5
- virglrenderer uses shmem for texture import/export so we need App Group for both iOS and macOS
- Add QEMURenderServer for new process model rendering (both Venus and Neptune)
- macOS: add DXMT and D3DMetal-Native backends
- We require 8G hostmem for Neptune but iOS currently fails > 256M
1. Network interfaces are refreshed every 10s rather than manually.
2. Removed host IP for emulated VLAN because it has little use and can
cause confusion amongst users.
3. Display guest IP for each interface separately.
When resetting UEFI vars, add an option to preload Secure
Boot keys (previously this was always done). This allows for
the user to load their own UEFI keys.
Also update the preloaded UEFI keys to Microsoft 2023 keys.
Resolves#7005Resolves#7257
We have inconsistent logic for identifying "is this a PC" in various
settings. This results in bug fixes for one machine not working when
a different PC machine model is used.
Fixes#7166
For reasons still unknown, in the App Store build, we can no longer read the
BIOS from /Applications/UTM.app/Contents/Resources/qemu as a bookmark even
though this had worked fine in the past. As a workaround, we will now copy
all the data files to the App Sandbox's Cache and then share a bookmark to
that.
Resolves#6861
We cannot use "-cpu max" because it causes BSOD issues (see #2368). QEMU
documentation suggests choosing a CPU model that matches the generation of
the host. Luckily for us, XNU already did the difficult work of mapping the
CPUID to the generation. Note that Rosetta returns Westmere but AMD based
Hackintoshes will still be unsupported and will default to the old CPU
model.
This change is needed to both improve performance of virtualized CPUs on
Intel Macs as well as enable Windows 11 24H2 to be booted as it now requires
SSE4.2 support.
Fixes#6325Fixes#6772