Commit Graph
483 Commits
Author SHA1 Message Date
osy e50840634f apple: allow sound input and output to be enabled separately
Since the input and output streams were merged into a single
virtio-sound device, playing audio in the guest also opens the host
microphone, which switches Bluetooth headphones into headset mode.
Replace the "Enable Sound" toggle with a choice of input only, output
only, or both so users can avoid opening the microphone.

The existing "Audio" key keeps meaning output and a new "AudioInput"
key is added. When "AudioInput" is missing it defaults to "Audio", so
existing configs keep both streams and new configs still load on older
versions of UTM.

Resolves #7875

Assisted-by: Claude:claude-opus-5-5
2026-09-22 15:03:12 -05:00
osy f4a3c5ac7c snapshots: manage Apple VM snapshots
Apple virtualization reported snapshots as unsupported. It has no notion of
them, but the pieces are there: the disks can be layered and the saved
state and firmware storage are ordinary files.

Add a backend that freezes a layer per drive and keeps copies of the saved
state, the EFI variables and the macOS auxiliary storage beside them. The
layers under a disk that is attached cannot be changed, so a running VM may
only delete; everything else waits until it stops.

A layer sits beside the image it belongs to and is named after it, and the saved
state and firmware of a snapshot are copies named the same way. A bundle only
keeps the files its configuration names, so saving the configuration would take
all of them with it. Work out what the snapshots still need instead — the layer
being written to, the layers of the snapshots in the bundle, and whatever lies
underneath those — and keep exactly that, so anything left over is still cleaned
up. When that cannot be worked out, because the manifest or a layer cannot be
read, everything named after the file is kept instead.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:30 -05:00
osy 0086417b97 snapshots: manage QEMU snapshots through a backend
Snapshots were read straight out of the QEMU images by the scripting
commands, which only worked while the VM was off and knew nothing beyond
the tags in the image.

Put a backend behind the operations instead. Which one is chosen depends on
whether the VM is running, and each says what it can do in that state:

- A running VM goes through the QEMU monitor, which saves and loads the
  whole machine along with the disks.
- A VM that is off goes through qemu-img, which can only save and revert
  disk contents. Nothing may touch the images while QEMU has them open, so
  a snapshot of disks alone is left alone until the VM stops.

Either way a snapshot spans every writable image, the UEFI variable store
included, because QEMU refuses to load one that any of them is missing. A
snapshot that some of them lack, such as one taken before a drive was added,
is kept but cannot be restored, which is not the same as its state being
gone: reverting only some of the drives would leave them at different points
in time. Reclaiming space rebuilds an image without its snapshots, so it is
refused while there are any.

UTMSnapshotService sits above the backend and keeps the manifest and the
stored state consistent: it marks entries whose state has disappeared when
an operation fails, and the first time a VM is opened it adopts whatever
snapshots are already in the images so that snapshots taken by other tools
are not lost. Both wait until the VM is stopped, because a running QEMU
lists the snapshots of every drive together, removable ones included.

Suspending is folded into the same mechanism. A VM now suspends to a
snapshot of its own rather than always the same name, so a suspended state
can be kept as a snapshot without copying it, and restoring a snapshot
makes the VM resume from it. The state is deleted once nothing refers to
it, where it used to be left behind in the image. One that cannot be deleted
right away stays listed in the manifest and is tried again the next time.

Assisted-by: Claude:claude-fable-5-1
Assisted-by: Claude:claude-opus-5
2026-09-22 10:57:30 -05:00
osy 9e8bd13e32 snapshots: record snapshot metadata in the VM bundle
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
2026-09-22 10:57:29 -05:00
osy 2d48f084e6 apple(disk): stack disk image snapshots as layers
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
2026-09-22 10:57:29 -05:00
osy 855bc0d2df config: add Secure Boot option for Apple UEFI guests
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
2026-09-19 23:18:45 -05:00
osy 3b0da37c46 apple: run without saving changes on macOS 27
"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
2026-09-19 10:51:06 -05:00
osy fa92ca48ed asif: use DiskImageKit on macOS 27
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
2026-09-19 10:49:50 -05:00
osy 47eadda150 apple: make the vmnet modes predictable and simpler
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
2026-09-18 20:43:49 -04:00
lovon-spec 31b431f8b5 apple: let virtual machines connect to each other
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
2026-09-18 13:26:24 +02:00
osy 800dfc1f14 apple: add USB passthrough on macOS 27
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
2026-09-17 22:15:30 +02:00
osy f3645d5018 project: remove code for versions below the new minimum
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
2026-09-16 04:48:37 +02:00
osy e2e37cf9b2 config: use linear upscaling except on classic guests
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
2026-09-01 13:35:08 -07:00
osy e9dda5b250 config: always use GICv3
GICv2 has reduced performance at higher core counts (measured in CP2077)
2026-08-31 22:21:15 -07:00
osy f93a7470b6 project: revert minver bump
We can selectively support DXMT on macOS 13, iOS 16 and so we can revert
the minver bump.
2026-08-04 08:27:04 -07:00
osy 5f13bb356a project: add dxmt to iOS builds 2026-08-04 08:26:43 -07:00
osy 719108f0f7 qemu: fix hostmem=8G for iOS 2026-08-04 07:21:38 -07:00
osy e6436a83b0 project: add DirectX support
- 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
2026-07-30 18:31:26 -07:00
matapo 47840263de use single VZVirtioSoundDeviceConfiguration for Apple VM audio 2026-05-03 22:29:34 +02:00
osy a255260698 config(qemu): fixed incorrect comma escape on single argument 2026-01-19 13:51:37 -08:00
osy 878190d146 config(qemu): set hostmem=256M so it works on iOS 2026-01-10 16:20:58 -08:00
osy 85f3044b1f qemu: enable Vulkan support
Resolves #4551
2026-01-07 21:03:12 -08:00
osy 2a913cadb0 qemu: enable support for CGL backend
Thanks to @startergo for the changes. This should enable OpenGL 4.1 on Linux

Resolves #4285
2026-01-04 21:54:36 -08:00
osy 863cdc7fc3 Merge pull request #7446 from nikolan123/main
Properly escape commas in disk paths
2026-01-02 16:48:09 -08:00
nikolan e65ad0b844 config(qemu): properly escape commas in disk paths 2026-01-02 16:47:00 -08:00
osy c50daa63a1 config(qemu): fix error when lock is disabled and no disk is mounted
Fixes #7527
2026-01-02 12:58:06 -08:00
osy 0f138b8af4 config(apple): fixed crash caused by serial being too long
Fixes #7355
2025-08-19 10:38:43 -07:00
osy 4a833cc945 Merge pull request #7290 from gabefair/main
Add Network Details to VM Details Screen
2025-08-18 18:08:09 -07:00
osy 4c963f833d home: improved display of network IP addresses
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.
2025-08-18 17:45:54 -07:00
osy d086134ef1 config(qemu): add serial number to VirtIO block devices
Resolves #7332
2025-08-17 20:34:52 -07:00
osy 1cf095067f config(qemu): support custom arguments with quotes
Only strip quotes if the entire argument is wrapped in quotes.

Fixes #6343
2025-08-17 18:47:16 -07:00
osy 2f3e57f4b3 Merge pull request #7336 from hyunwook13/fix/typos-in-comments
chore: fix grammar in code comments
2025-08-12 11:39:30 -07:00
osy 1330cc4356 config(qemu): more sane defaults for legacy pc hardware
Should be compatible with Windows 9x
2025-08-12 00:45:00 -07:00
osy a7103d3c82 config(qemu): do not create USB HID devices when PS/2 is used 2025-08-11 23:09:38 -07:00
osy 862c507a26 config(qemu): preloading UEFI keys is optional
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 #7005
Resolves #7257
2025-08-10 23:00:24 -07:00
Hyunwook 29254bfe89 chore: fix grammar in code comments 2025-08-07 18:44:07 +09:00
osy fe6f0165c7 config(qemu): support virtio drives on m68k
Resolves #7008
2025-08-03 19:28:51 -07:00
osy 434a777c9a build: TCI: add m68k, remove arm, riscv32
There isn't any good use for arm32 and riscv32. Remove them to
reduce the app size.
2025-08-03 19:08:21 -07:00
osy 006e00589f Revert "config(qemu): support manual bus location for IDE and SCSI"
This reverts commit b2b88d9424.
2025-08-03 09:32:51 -07:00
osy 203f5261dd wizard: create classic Mac OS machine
Also add support for classicvirtio.

Resolves #6520
2025-08-03 09:32:51 -07:00
osy fcb537f52c asif: implement resize and image info
Also works with RAW images.

Resolves #6891
2025-07-26 16:50:40 -07:00
osy b2b88d9424 config(qemu): support manual bus location for IDE and SCSI
On some older operating systems such as NeXTSTEP, this is needed.

Resolves #6529
2025-07-25 17:48:38 -07:00
osy a935bce8e3 config(qemu): unify config for pc*, isapc, q35
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
2025-07-24 10:34:52 -07:00
osy 0b6a3ab296 config(qemu): disable bootindex when boot-device is used in prom-env
Fixes #6436
2025-07-24 10:21:06 -07:00
osy bcb5b0f161 config(qemu): enable UEFI support for RISCV64 and LoongArch64
Resolves #7183
2025-07-23 14:56:51 -07:00
osy 7ccf4c43a6 settings: add file lock setting
Can be used to disable locking on filesystems that does not support
it.

Resolves #7211
2025-07-23 14:17:46 -07:00
osy a16db438e7 home: use notifications for guest tools install
Fixes #7297
2025-07-19 00:01:31 -07:00
osy c2c90da484 config(macOS): add support for creating ASIF drives 2025-07-08 22:38:55 -07:00
osy ad0002928c Merge pull request #6186 from Schamper/main
Initial support for external/multiple networks in vmnet host mode
2025-07-08 10:49:54 -07:00
osy d5db1a1d6b build: update QEMU to v10.0.2
Resolves #2353
2025-07-07 01:46:59 -07:00