Split the QEMU configs by host system and architecture

Replace qemu/<guest>-<arch>.ini with qemu/<guest>-<os>-<arch>.ini, where os is
linux or darwin, the name platform.system() reports. The accelerators move out
of the shared <guest>.ini into these files (KVM on Linux, HVF on macOS, TCG as
the fallback). The launchers pick the file from the host system and
architecture, and reject amd64 guests on macOS hosts, so no darwin-amd64 files
exist.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GuofangandClaude Sonnet 5.5 committed 2026-10-17 15:05:02 +08:00
1 parent c13ebc7d11
commit fd1d9d651d
24 files changed
+234 -96

No files matched your search

+12 -12
View File
@@ -26,13 +26,14 @@ original qcow2 image as its backing file. The base image therefore stays
unchanged. Run `./run-debian13.py --help` for the supported environment unchanged. Run `./run-debian13.py --help` for the supported environment
variables. variables.
The Debian VM hardware (accelerator, 8G memory, 8 CPUs, drives, network) is The Debian VM hardware (8G memory, 8 CPUs, drives, network) is
defined in the QEMU config file `qemu/debian13.ini`; the machine type and defined in the QEMU config file `qemu/debian13.ini`; the machine type and
architecture-specific devices are in `qemu/debian13-amd64.ini` and architecture-specific devices are in `qemu/debian13-<os>-<arch>.ini`
`qemu/debian13-arm64.ini`. Edit these files to change the settings. The (os `linux` or `darwin`, arch `amd64` or `arm64`), together with the
accelerators. Edit these files to change the settings. The
launcher fills in the `${...}` file path placeholders of `qemu/debian13.ini`, launcher fills in the `${...}` file path placeholders of `qemu/debian13.ini`,
writes the result to `.vm/debian13/qemu.ini` and starts QEMU with writes the result to `.vm/debian13/qemu.ini` and starts QEMU with
`-readconfig` for that file followed by the one for the guest architecture. `-readconfig` for that file followed by the one for the host system and guest architecture.
QEMU arguments given after `--` override the config files, for example QEMU arguments given after `--` override the config files, for example
`./run-debian13.py -- -m 4G -smp 4`. `./run-debian13.py -- -m 4G -smp 4`.
@@ -122,9 +123,8 @@ GNOME package group through its native package module, then reboots the guest.
Keep the VM running until this initial installation and reboot have completed. Keep the VM running until this initial installation and reboot have completed.
Like the Debian VM, the Fedora VM hardware (8G memory, 8 CPUs, drives, SSH Like the Debian VM, the Fedora VM hardware (8G memory, 8 CPUs, drives, SSH
port `2224`) is defined in `qemu/fedora44.ini`, with the machine type and port `2224`) is defined in `qemu/fedora44.ini`, with the accelerators, machine type and
architecture-specific devices in `qemu/fedora44-amd64.ini` and platform-specific devices in `qemu/fedora44-<os>-<arch>.ini`. Other Fedora settings use the `FEDORA_VM_` prefix.
`qemu/fedora44-arm64.ini`. Other Fedora settings use the `FEDORA_VM_` prefix.
Run `./run-fedora44.py --help` for the complete list of overrides. Run `./run-fedora44.py --help` for the complete list of overrides.
## Ubuntu 26.04 ## Ubuntu 26.04
@@ -151,8 +151,8 @@ guest. Keep the VM running until this initial installation and reboot have
completed. completed.
The VM hardware (8G memory, 8 CPUs, drives, SSH port `2225`) is defined in The VM hardware (8G memory, 8 CPUs, drives, SSH port `2225`) is defined in
`qemu/ubuntu2604.ini`, with the machine type and architecture-specific devices `qemu/ubuntu2604.ini`, with the accelerators, machine type and platform-specific
in `qemu/ubuntu2604-amd64.ini` and `qemu/ubuntu2604-arm64.ini`. Other Ubuntu devices in `qemu/ubuntu2604-<os>-<arch>.ini`. Other Ubuntu
settings use the `UBUNTU_VM_` prefix. Run `./run-ubuntu2604.py --help` for the settings use the `UBUNTU_VM_` prefix. Run `./run-ubuntu2604.py --help` for the
complete list of overrides. complete list of overrides.
@@ -175,9 +175,9 @@ passwordless administrator login. The installer includes the VirtIO drivers, SPI
and QEMU Guest Agent. Connect with `ssh guofang@localhost -p 2222`. The launcher and QEMU Guest Agent. Connect with `ssh guofang@localhost -p 2222`. The launcher
exposes the vdagent channel for host/guest clipboard integration and the QEMU Guest Agent at exposes the vdagent channel for host/guest clipboard integration and the QEMU Guest Agent at
`.vm/windows11/qemu-guest-agent.sock`. Change the password after first login. `.vm/windows11/qemu-guest-agent.sock`. Change the password after first login.
The Windows VM hardware (accelerator, 8G memory, 8 CPUs, system disk, devices) The Windows VM hardware (8G memory, 8 CPUs, system disk, devices)
is defined in `qemu/windows11.ini`, with the machine type in is defined in `qemu/windows11.ini`, with the accelerators and machine type in
`qemu/windows11-amd64.ini`; the launcher renders the former to `qemu/windows11-<os>-<arch>.ini`; the launcher renders the former to
`.vm/windows11/qemu.ini` and loads both with `-readconfig`. Only the network `.vm/windows11/qemu.ini` and loads both with `-readconfig`. Only the network
and the installation media are still set by the launcher. QEMU arguments after and the installation media are still set by the launcher. QEMU arguments after
`--` override the config files, for example `./run-windows11.py -- -m 4G -smp 4`. `--` override the config files, for example `./run-windows11.py -- -m 4G -smp 4`.
-4
View File
@@ -1,4 +0,0 @@
# amd64 part of the Debian 13 QEMU configuration; read after debian13.ini.
[machine]
type = "q35"
@@ -1,4 +1,11 @@
# arm64 part of the Ubuntu 26.04 QEMU configuration; read after ubuntu2604.ini. # macOS host, arm64 part of the Debian 13 QEMU configuration; read after debian13.ini.
# Accelerators are tried in order: HVF on macOS, else emulation.
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[machine] [machine]
type = "virt" type = "virt"
+11
View File
@@ -0,0 +1,11 @@
# Linux host, amd64 part of the Debian 13 QEMU configuration; read after debian13.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine]
type = "q35"
@@ -1,4 +1,11 @@
# arm64 part of the Debian 13 QEMU configuration; read after debian13.ini. # Linux host, arm64 part of the Debian 13 QEMU configuration; read after debian13.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine] [machine]
type = "virt" type = "virt"
+3 -12
View File
@@ -1,6 +1,7 @@
# QEMU configuration for the Debian 13 virtual machine, shared by all # QEMU configuration for the Debian 13 virtual machine, shared by all
# architectures. The machine type and architecture-specific devices are in # architectures. The accelerators, machine type and
# debian13-<arch>.ini, which QEMU reads after this file. # platform-specific devices are in debian13-<os>-<arch>.ini (os is linux or darwin),
# which QEMU reads after this file.
# #
# run-debian13.py fills in the file path placeholders below, writes the result # run-debian13.py fills in the file path placeholders below, writes the result
# to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that # to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that
@@ -10,16 +11,6 @@
[name] [name]
guest = "debian13" guest = "debian13"
# Accelerators are tried in order: KVM on Linux, HVF on macOS, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[memory] [memory]
size = "8G" size = "8G"
-4
View File
@@ -1,4 +0,0 @@
# amd64 part of the Fedora 44 QEMU configuration; read after fedora44.ini.
[machine]
type = "q35"
@@ -1,4 +1,11 @@
# arm64 part of the Fedora 44 QEMU configuration; read after fedora44.ini. # macOS host, arm64 part of the Fedora 44 QEMU configuration; read after fedora44.ini.
# Accelerators are tried in order: HVF on macOS, else emulation.
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[machine] [machine]
type = "virt" type = "virt"
+11
View File
@@ -0,0 +1,11 @@
# Linux host, amd64 part of the Fedora 44 QEMU configuration; read after fedora44.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine]
type = "q35"
+24
View File
@@ -0,0 +1,24 @@
# Linux host, arm64 part of the Fedora 44 QEMU configuration; read after fedora44.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine]
type = "virt"
# Unlike q35, the "virt" machine has no default GPU or USB input devices.
[device "gpu0"]
driver = "virtio-gpu-pci"
[device "usb0"]
driver = "qemu-xhci"
[device "kbd0"]
driver = "usb-kbd"
[device "tablet0"]
driver = "usb-tablet"
+3 -12
View File
@@ -1,6 +1,7 @@
# QEMU configuration for the Fedora 44 virtual machine, shared by all # QEMU configuration for the Fedora 44 virtual machine, shared by all
# architectures. The machine type and architecture-specific devices are in # architectures. The accelerators, machine type and
# fedora44-<arch>.ini, which QEMU reads after this file. # platform-specific devices are in fedora44-<os>-<arch>.ini (os is linux or darwin),
# which QEMU reads after this file.
# #
# run-fedora44.py fills in the file path placeholders below, writes the result # run-fedora44.py fills in the file path placeholders below, writes the result
# to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that # to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that
@@ -10,16 +11,6 @@
[name] [name]
guest = "fedora44" guest = "fedora44"
# Accelerators are tried in order: KVM on Linux, HVF on macOS, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[memory] [memory]
size = "8G" size = "8G"
-4
View File
@@ -1,4 +0,0 @@
# amd64 part of the Ubuntu 26.04 QEMU configuration; read after ubuntu2604.ini.
[machine]
type = "q35"
+24
View File
@@ -0,0 +1,24 @@
# macOS host, arm64 part of the Ubuntu 26.04 QEMU configuration; read after ubuntu2604.ini.
# Accelerators are tried in order: HVF on macOS, else emulation.
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[machine]
type = "virt"
# Unlike q35, the "virt" machine has no default GPU or USB input devices.
[device "gpu0"]
driver = "virtio-gpu-pci"
[device "usb0"]
driver = "qemu-xhci"
[device "kbd0"]
driver = "usb-kbd"
[device "tablet0"]
driver = "usb-tablet"
+11
View File
@@ -0,0 +1,11 @@
# Linux host, amd64 part of the Ubuntu 26.04 QEMU configuration; read after ubuntu2604.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine]
type = "q35"
+24
View File
@@ -0,0 +1,24 @@
# Linux host, arm64 part of the Ubuntu 26.04 QEMU configuration; read after ubuntu2604.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine]
type = "virt"
# Unlike q35, the "virt" machine has no default GPU or USB input devices.
[device "gpu0"]
driver = "virtio-gpu-pci"
[device "usb0"]
driver = "qemu-xhci"
[device "kbd0"]
driver = "usb-kbd"
[device "tablet0"]
driver = "usb-tablet"
+3 -12
View File
@@ -1,6 +1,7 @@
# QEMU configuration for the Ubuntu 26.04 virtual machine, shared by all # QEMU configuration for the Ubuntu 26.04 virtual machine, shared by all
# architectures. The machine type and architecture-specific devices are in # architectures. The accelerators, machine type and
# ubuntu2604-<arch>.ini, which QEMU reads after this file. # platform-specific devices are in ubuntu2604-<os>-<arch>.ini (os is linux or darwin),
# which QEMU reads after this file.
# #
# run-ubuntu2604.py fills in the file path placeholders below, writes the result # run-ubuntu2604.py fills in the file path placeholders below, writes the result
# to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that # to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that
@@ -10,16 +11,6 @@
[name] [name]
guest = "ubuntu2604" guest = "ubuntu2604"
# Accelerators are tried in order: KVM on Linux, HVF on macOS, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[memory] [memory]
size = "8G" size = "8G"
@@ -1,4 +1,11 @@
# arm64 part of the Windows 11 QEMU configuration; read after windows11.ini. # macOS host, arm64 part of the Windows 11 QEMU configuration; read after windows11.ini.
# Accelerators are tried in order: HVF on macOS, else emulation.
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[machine] [machine]
type = "virt" type = "virt"
@@ -1,4 +1,11 @@
# amd64 part of the Windows 11 QEMU configuration; read after windows11.ini. # Linux host, amd64 part of the Windows 11 QEMU configuration; read after windows11.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine] [machine]
type = "q35" type = "q35"
+34
View File
@@ -0,0 +1,34 @@
# Linux host, arm64 part of the Windows 11 QEMU configuration; read after windows11.ini.
# Accelerators are tried in order: KVM on Linux, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "tcg"
[machine]
type = "virt"
# The "virt" machine has no IDE. NVMe and USB mass storage (used by the
# installation media of --install-from-iso) both have inbox Windows drivers.
[device "system_disk-dev"]
driver = "nvme"
drive = "system_disk"
serial = "win11disk"
bootindex = "1"
# Windows has no inbox driver for virtio-net; the guest tools installed by
# Configure-Windows.ps1 provide it.
[device "nic0"]
driver = "virtio-net-pci"
netdev = "net0"
# Unlike q35, "virt" has no default GPU or keyboard. ramfb is used rather than
# virtio-gpu because the firmware's virtio-gpu output freezes at the Windows
# boot manager; Windows drives either one through its basic display driver.
[device "gpu0"]
driver = "ramfb"
[device "kbd0"]
driver = "usb-kbd"
+3 -12
View File
@@ -1,5 +1,6 @@
# QEMU configuration for the Windows 11 virtual machine. The machine type is in # QEMU configuration for the Windows 11 virtual machine. The accelerators and machine type
# windows11-<arch>.ini, which QEMU reads after this file. # are in windows11-<os>-<arch>.ini (os is linux or darwin), which QEMU reads after
# this file.
# #
# run-windows11.py fills in the file path placeholders below, writes the result # run-windows11.py fills in the file path placeholders below, writes the result
# to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that # to <state dir>/qemu.ini and passes it to QEMU with -readconfig. Options that
@@ -9,16 +10,6 @@
[name] [name]
guest = "windows11" guest = "windows11"
# Accelerators are tried in order: KVM on Linux, HVF on macOS, else emulation.
[accel]
accel = "kvm"
[accel]
accel = "hvf"
[accel]
accel = "tcg"
[memory] [memory]
size = "8G" size = "8G"
+8 -5
View File
@@ -69,7 +69,10 @@ native_arch = normalize_arch(platform.machine())
host_arch = normalize_arch(env("VM_IMAGE_ARCH") or native_arch) host_arch = normalize_arch(env("VM_IMAGE_ARCH") or native_arch)
qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64" qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64"
qemu_config_template = Path(env("VM_QEMU_CONFIG") or script_dir / "qemu" / "debian13.ini") qemu_config_template = Path(env("VM_QEMU_CONFIG") or script_dir / "qemu" / "debian13.ini")
qemu_arch_config = script_dir / "qemu" / f"debian13-{host_arch}.ini" host_os = platform.system().lower()
if host_os == "darwin" and host_arch == "amd64":
die("amd64 guests are not supported on macOS hosts; use an arm64 image")
qemu_platform_config = script_dir / "qemu" / f"debian13-{host_os}-{host_arch}.ini"
def pick_firmware(override, *candidates): def pick_firmware(override, *candidates):
@@ -124,7 +127,7 @@ Start the Debian 13 virtual machine. A writable overlay is created in the state
directory (default: .vm/debian13/), so the downloaded base image is never directory (default: .vm/debian13/), so the downloaded base image is never
modified. The VM hardware (memory, CPUs, SSH port forward, ...) is defined in modified. The VM hardware (memory, CPUs, SSH port forward, ...) is defined in
qemu/debian13.ini, which is rendered to qemu.ini in the state directory and qemu/debian13.ini, which is rendered to qemu.ini in the state directory and
loaded with QEMU's -readconfig, followed by qemu/debian13-<arch>.ini. Later loaded with QEMU's -readconfig, followed by qemu/debian13-<os>-<arch>.ini (os is linux or darwin, arch is amd64 or arm64). Later
QEMU arguments override them, e.g. `-- -m 4G -smp 4`. QEMU arguments override them, e.g. `-- -m 4G -smp 4`.
Options: Options:
@@ -251,7 +254,7 @@ for key, value in config_values.items():
# QEMU's config file parser has no escape syntax for quoted values. # QEMU's config file parser has no escape syntax for quoted values.
if any(char in str(value) for char in '"\n'): if any(char in str(value) for char in '"\n'):
die(f"{key} must not contain double quotes or newlines: {value}") die(f"{key} must not contain double quotes or newlines: {value}")
for config_file in (qemu_config_template, qemu_arch_config): for config_file in (qemu_config_template, qemu_platform_config):
if not config_file.is_file(): if not config_file.is_file():
die(f"QEMU config file was not found: {config_file}") die(f"QEMU config file was not found: {config_file}")
try: try:
@@ -263,7 +266,7 @@ qemu_config.write_text(qemu_config_text)
qemu_args = [ qemu_args = [
"-readconfig", str(qemu_config), "-readconfig", str(qemu_config),
"-readconfig", str(qemu_arch_config), "-readconfig", str(qemu_platform_config),
# "max" is the host CPU under KVM/HVF and the fullest model under TCG. # "max" is the host CPU under KVM/HVF and the fullest model under TCG.
"-cpu", "max", "-cpu", "max",
# The config file's [netdev] does not stop QEMU from adding its default # The config file's [netdev] does not stop QEMU from adding its default
@@ -273,7 +276,7 @@ qemu_args = [
] ]
print(f"Starting {host_arch} VM from {qemu_config_template} " print(f"Starting {host_arch} VM from {qemu_config_template} "
f"and {qemu_arch_config}.", flush=True) f"and {qemu_platform_config}.", flush=True)
# The SSH port forward lives in the config file, e.g. hostfwd = "tcp::2222-:22". # The SSH port forward lives in the config file, e.g. hostfwd = "tcp::2222-:22".
ssh_forward = re.search(r'hostfwd\s*=\s*"tcp:[^:"]*:(\d+)-[^:"]*:22"', qemu_config_text) ssh_forward = re.search(r'hostfwd\s*=\s*"tcp:[^:"]*:(\d+)-[^:"]*:22"', qemu_config_text)
if ssh_forward: if ssh_forward:
+8 -5
View File
@@ -70,7 +70,10 @@ host_arch = normalize_arch(env("VM_IMAGE_ARCH") or native_arch)
qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64" qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64"
qemu_config_template = Path( qemu_config_template = Path(
env("FEDORA_VM_QEMU_CONFIG") or script_dir / "qemu" / "fedora44.ini") env("FEDORA_VM_QEMU_CONFIG") or script_dir / "qemu" / "fedora44.ini")
qemu_arch_config = script_dir / "qemu" / f"fedora44-{host_arch}.ini" host_os = platform.system().lower()
if host_os == "darwin" and host_arch == "amd64":
die("amd64 guests are not supported on macOS hosts; use an arm64 image")
qemu_platform_config = script_dir / "qemu" / f"fedora44-{host_os}-{host_arch}.ini"
def pick_firmware(override, *candidates): def pick_firmware(override, *candidates):
@@ -126,7 +129,7 @@ base image through the shared image helper and creates a writable overlay
in the state directory, leaving the base image unchanged. The VM hardware in the state directory, leaving the base image unchanged. The VM hardware
(memory, CPUs, SSH port forward, ...) is defined in qemu/fedora44.ini, which is (memory, CPUs, SSH port forward, ...) is defined in qemu/fedora44.ini, which is
rendered to qemu.ini in the state directory and loaded with QEMU's -readconfig, rendered to qemu.ini in the state directory and loaded with QEMU's -readconfig,
followed by qemu/fedora44-<arch>.ini. Later QEMU arguments override them, e.g. followed by qemu/fedora44-<os>-<arch>.ini (os is linux or darwin, arch is amd64 or arm64). Later QEMU arguments override them, e.g.
`-- -m 4G -smp 4`. `-- -m 4G -smp 4`.
Options: Options:
@@ -253,7 +256,7 @@ for key, value in config_values.items():
# QEMU's config file parser has no escape syntax for quoted values. # QEMU's config file parser has no escape syntax for quoted values.
if any(char in str(value) for char in '"\n'): if any(char in str(value) for char in '"\n'):
die(f"{key} must not contain double quotes or newlines: {value}") die(f"{key} must not contain double quotes or newlines: {value}")
for config_file in (qemu_config_template, qemu_arch_config): for config_file in (qemu_config_template, qemu_platform_config):
if not config_file.is_file(): if not config_file.is_file():
die(f"QEMU config file was not found: {config_file}") die(f"QEMU config file was not found: {config_file}")
try: try:
@@ -265,7 +268,7 @@ qemu_config.write_text(qemu_config_text)
qemu_args = [ qemu_args = [
"-readconfig", str(qemu_config), "-readconfig", str(qemu_config),
"-readconfig", str(qemu_arch_config), "-readconfig", str(qemu_platform_config),
# "max" is the host CPU under KVM/HVF and the fullest model under TCG. # "max" is the host CPU under KVM/HVF and the fullest model under TCG.
"-cpu", "max", "-cpu", "max",
# The config file's [netdev] does not stop QEMU from adding its default # The config file's [netdev] does not stop QEMU from adding its default
@@ -275,7 +278,7 @@ qemu_args = [
] ]
print(f"Starting Fedora 44 ({host_arch}) from {qemu_config_template} " print(f"Starting Fedora 44 ({host_arch}) from {qemu_config_template} "
f"and {qemu_arch_config}.", flush=True) f"and {qemu_platform_config}.", flush=True)
# The SSH port forward lives in the config file, e.g. hostfwd = "tcp::2224-:22". # The SSH port forward lives in the config file, e.g. hostfwd = "tcp::2224-:22".
ssh_forward = re.search(r'hostfwd\s*=\s*"tcp:[^:"]*:(\d+)-[^:"]*:22"', qemu_config_text) ssh_forward = re.search(r'hostfwd\s*=\s*"tcp:[^:"]*:(\d+)-[^:"]*:22"', qemu_config_text)
if ssh_forward: if ssh_forward:
+8 -5
View File
@@ -70,7 +70,10 @@ host_arch = normalize_arch(env("VM_IMAGE_ARCH") or native_arch)
qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64" qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64"
qemu_config_template = Path( qemu_config_template = Path(
env("UBUNTU_VM_QEMU_CONFIG") or script_dir / "qemu" / "ubuntu2604.ini") env("UBUNTU_VM_QEMU_CONFIG") or script_dir / "qemu" / "ubuntu2604.ini")
qemu_arch_config = script_dir / "qemu" / f"ubuntu2604-{host_arch}.ini" host_os = platform.system().lower()
if host_os == "darwin" and host_arch == "amd64":
die("amd64 guests are not supported on macOS hosts; use an arm64 image")
qemu_platform_config = script_dir / "qemu" / f"ubuntu2604-{host_os}-{host_arch}.ini"
def pick_firmware(override, *candidates): def pick_firmware(override, *candidates):
@@ -126,7 +129,7 @@ created in the state directory (default: .vm/ubuntu2604/), so the downloaded
base image is never modified. The VM hardware (memory, CPUs, SSH port forward, base image is never modified. The VM hardware (memory, CPUs, SSH port forward,
...) is defined in qemu/ubuntu2604.ini, which is rendered to qemu.ini in the ...) is defined in qemu/ubuntu2604.ini, which is rendered to qemu.ini in the
state directory and loaded with QEMU's -readconfig, followed by state directory and loaded with QEMU's -readconfig, followed by
qemu/ubuntu2604-<arch>.ini. Later QEMU arguments override them, e.g. qemu/ubuntu2604-<os>-<arch>.ini (os is linux or darwin, arch is amd64 or arm64). Later QEMU arguments override them, e.g.
`-- -m 4G -smp 4`. `-- -m 4G -smp 4`.
Options: Options:
@@ -253,7 +256,7 @@ for key, value in config_values.items():
# QEMU's config file parser has no escape syntax for quoted values. # QEMU's config file parser has no escape syntax for quoted values.
if any(char in str(value) for char in '"\n'): if any(char in str(value) for char in '"\n'):
die(f"{key} must not contain double quotes or newlines: {value}") die(f"{key} must not contain double quotes or newlines: {value}")
for config_file in (qemu_config_template, qemu_arch_config): for config_file in (qemu_config_template, qemu_platform_config):
if not config_file.is_file(): if not config_file.is_file():
die(f"QEMU config file was not found: {config_file}") die(f"QEMU config file was not found: {config_file}")
try: try:
@@ -265,7 +268,7 @@ qemu_config.write_text(qemu_config_text)
qemu_args = [ qemu_args = [
"-readconfig", str(qemu_config), "-readconfig", str(qemu_config),
"-readconfig", str(qemu_arch_config), "-readconfig", str(qemu_platform_config),
# "max" is the host CPU under KVM/HVF and the fullest model under TCG. # "max" is the host CPU under KVM/HVF and the fullest model under TCG.
"-cpu", "max", "-cpu", "max",
# The config file's [netdev] does not stop QEMU from adding its default # The config file's [netdev] does not stop QEMU from adding its default
@@ -275,7 +278,7 @@ qemu_args = [
] ]
print(f"Starting Ubuntu 26.04 ({host_arch}) from {qemu_config_template} " print(f"Starting Ubuntu 26.04 ({host_arch}) from {qemu_config_template} "
f"and {qemu_arch_config}.", flush=True) f"and {qemu_platform_config}.", flush=True)
# The SSH port forward lives in the config file, e.g. hostfwd = "tcp::2225-:22". # The SSH port forward lives in the config file, e.g. hostfwd = "tcp::2225-:22".
ssh_forward = re.search(r'hostfwd\s*=\s*"tcp:[^:"]*:(\d+)-[^:"]*:22"', qemu_config_text) ssh_forward = re.search(r'hostfwd\s*=\s*"tcp:[^:"]*:(\d+)-[^:"]*:22"', qemu_config_text)
if ssh_forward: if ssh_forward:
+7 -4
View File
@@ -79,7 +79,10 @@ def normalize_arch(arch):
host_arch = normalize_arch(env("VM_IMAGE_ARCH") or platform.machine()) host_arch = normalize_arch(env("VM_IMAGE_ARCH") or platform.machine())
qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64" qemu_binary = "qemu-system-aarch64" if host_arch == "arm64" else "qemu-system-x86_64"
qemu_arch_config = script_dir / "qemu" / f"windows11-{host_arch}.ini" host_os = platform.system().lower()
if host_os == "darwin" and host_arch == "amd64":
die("amd64 guests are not supported on macOS hosts; use an arm64 image")
qemu_platform_config = script_dir / "qemu" / f"windows11-{host_os}-{host_arch}.ini"
def pick_firmware(override, *candidates): def pick_firmware(override, *candidates):
@@ -136,7 +139,7 @@ If the system disk (DIR/disk.qcow2, see --state-dir) is missing, create it from
the Windows 11 QCOW2 base image. the Windows 11 QCOW2 base image.
The VM hardware (accelerator, memory, CPUs, drives, devices) is defined in The VM hardware (accelerator, memory, CPUs, drives, devices) is defined in
qemu/windows11.ini, which is rendered to qemu.ini in the state directory and qemu/windows11.ini, which is rendered to qemu.ini in the state directory and
loaded with QEMU's -readconfig, followed by qemu/windows11-<arch>.ini (amd64 or arm64, chosen from the host loaded with QEMU's -readconfig, followed by qemu/windows11-<os>-<arch>.ini (os is linux or darwin, arch is amd64 or arm64, chosen from the host system and
architecture or VM_IMAGE_ARCH). Later QEMU arguments override them, e.g. -- -m 4G -smp 4. architecture or VM_IMAGE_ARCH). Later QEMU arguments override them, e.g. -- -m 4G -smp 4.
Use --install-from-iso to perform an automatic ISO installation instead. Use --install-from-iso to perform an automatic ISO installation instead.
If it exists, start Windows normally without attaching installation media. If it exists, start Windows normally without attaching installation media.
@@ -327,7 +330,7 @@ for key, value in config_values.items():
# QEMU's config file parser has no escape syntax for quoted values. # QEMU's config file parser has no escape syntax for quoted values.
if any(char in str(value) for char in '"\n'): if any(char in str(value) for char in '"\n'):
die(f"{key} must not contain double quotes or newlines: {value}") die(f"{key} must not contain double quotes or newlines: {value}")
for config_file in (qemu_config_template, qemu_arch_config): for config_file in (qemu_config_template, qemu_platform_config):
if not config_file.is_file(): if not config_file.is_file():
die(f"QEMU config file was not found: {config_file}") die(f"QEMU config file was not found: {config_file}")
try: try:
@@ -352,7 +355,7 @@ for label, host_port, guest_port in (("RDP", rdp_port, 3389), ("SSH", ssh_port,
qemu_args = [ qemu_args = [
"-readconfig", str(qemu_config), "-readconfig", str(qemu_config),
"-readconfig", str(qemu_arch_config), "-readconfig", str(qemu_platform_config),
# "max" is the host CPU under KVM/HVF and the fullest model under TCG. # "max" is the host CPU under KVM/HVF and the fullest model under TCG.
"-cpu", "max", "-cpu", "max",
# A config file section cannot hold two hostfwd entries, so the network # A config file section cannot hold two hostfwd entries, so the network