Files
2026-09-15 15:24:03 -04:00

115 lines
6.6 KiB
Markdown

# The Windows base image
Unlike Ubuntu, this one is installed by hand. There is no unattended path here
and that is deliberate: Windows licensing, edition choice and the out-of-box
experience are all decisions for the operator, not for a script.
## What is already prepared
/var/lib/owuivm/iso/Win11_25H2_English_x64_v2.iso the media you supplied
/var/lib/owuivm/iso/virtio-win.iso the driver disc
Both are recorded in `windows.manifest` and `virtio.manifest` with their
SHA-256. **Recorded, not verified** - unlike Ubuntu, there is no published
checksum list to compare a Windows ISO against, so the manifest says what the
file hashed to and nothing stronger. That difference is real and is not papered
over.
## Three things Windows needs that Ubuntu does not
All three are already in the launcher, applied only when the image is named
`windows`:
| Requirement | What is provided | What happens without it |
|---|---|---|
| **TPM 2.0** | `swtpm` on a unix socket, `tpm-tis` device | Setup stops at "This PC can't run Windows 11" |
| **Secure Boot** | `OVMF_CODE_4M.secboot.fd` + a variable store seeded from `OVMF_VARS_4M.ms.fd`, with `property=secure,value=on` so the guest cannot rewrite it | Same message. Microsoft's keys have to be *enrolled*, not just the firmware present |
| **virtio drivers** | `virtio-win.iso` attached as a second CD during the install only | Setup reports no drives to install to, which looks like a broken VM |
| **Hyper-V enlightenments** | fourteen `hv-*` flags on `-cpu`, Windows only | The machine is simply slow, and the host looks busy while the guest looks idle - measured at 347% CPU on an idle installer with the cgroup neither short of memory nor throttled |
| **`-rtc base=localtime`** | Windows only | The clock is hours out, so TLS verification fails and every download breaks in a way that reads as a network fault |
`swtpm` also needed an AppArmor exception: Ubuntu's shipped profile permits
libvirt's paths and nothing else, so the socket was refused with
`Could not open UnixIO socket: Permission denied` - a policy denial wearing a
permission error's clothes, with nothing in dmesg. See
`vm/host/apparmor-local-swtpm`.
## Installing it
1. Finish the Ubuntu image first, or close it. Only one maintenance machine
runs at a time and the prepare step refuses the second.
Starting a *frozen* image is always safe, at any time: it boots a throwaway
copy and cannot change what is on disk. That is the way to check that an
image still comes up before handing it to the agent.
2. **Tool Server VM Maintenance** on the desktop -> the Windows row ->
**Install from ISO**.
A blank 60 GB disk is created, the media is attached, and the console opens.
3. **Two prompts eat keystrokes before Windows does, in this order.** OVMF shows
its own "press a key for boot options" window for about five seconds - any
key there drops you into the firmware menu, not the installer (if that
happens: **Boot Manager** -> **UEFI QEMU DVD-ROM QM00001**, which is the
Windows ISO; QM00003 is virtio-win). Then the ISO itself shows "Press any
key to boot from CD or DVD" for about five seconds, and *that* one has to be
answered or the machine falls through to an EFI shell. So: let the firmware
window pass untouched, then press a key.
4. When setup asks where to install and shows no drives, choose **Load driver**,
browse the second CD, and take `amd64\w11` (or `amd64\2k25`). The disk
appears immediately afterwards.
5. Install normally. A local account is simplest - the machine has no way to
reach a Microsoft account sign-in that needs a phone, and nothing about this
image should depend on one.
## Before you shut down
The equivalents of what the Ubuntu image needed, and for the same reasons:
- **`qemu-guest-agent`** from the driver disc (`virtio-win-guest-tools.exe`, or
`guest-agent\qemu-ga-x86_64.msi`). This is the entire control channel; without
it the machine boots and is unreachable, which looks identical to a machine
that failed to boot.
- **Static networking**: address `10.0.2.15/24`, gateway `10.0.2.2`, DNS
`1.1.1.1`. DHCP hands out SLIRP's own resolver at `10.0.2.3`, which relays to
*this host's* resolver and is correctly blocked by the sandbox filter - giving
a machine with working TCP and no name resolution.
- **Auto-logon** for the admin account, so a GUI session has a desktop from boot
with no human. `netplwiz`, or `Set-LocalUser` plus the `AutoAdminLogon`
registry values.
- **The rest of virtio-win**, not just the storage driver setup needed: NetKVM
for the network, and the display driver in particular. Until it is installed
`virtio-vga` is a plain VGA framebuffer to Windows and every redraw is a full
repaint - which is most of what "the VM feels slow" turns out to be once the
enlightenments are on.
- **Turn off Windows Update's automatic reboots** and anything else that changes
the machine between sessions. Every session starts from this frozen disk, so
background change here is change in every future run.
## Then
Press **Shut down**. The guest is asked to power off over ACPI and systemd waits
for it, so this is the machine shutting itself down rather than the plug coming
out. The variable store is copied back on the way - a UEFI boot entry added by
setup is otherwise lost and the disk will not boot.
Then press **Freeze**, which is the operator's own button and is not done for
you: nothing re-freezes an image behind your back any more. Freezing sets `0444`
and records the checksum, and until it is done no agent session will start -
vmd refuses to open one on a writable base and says so.
Then press **Installed — remove disc**, which appears on the row while an
install is in progress and wakes up once the machine is stopped. That is what
says the install is finished: until it is pressed the installer media is still
attached at every boot, deliberately, because a machine shut down halfway
through setup needs its disc to be finished and nothing here can tell the two
cases apart. The disc first, the disk second - the boot order tries the disk and
falls through to the media, so an installed system boots itself either way and
the only cost of leaving it attached is the ISO staying open.
## Not yet done
Nothing on this page has been run. The Ubuntu path was measured end to end;
this one is written from the same code paths plus the documented Windows
requirements, and the first real install will find something. The argv it will
be given *is* asserted, by `tests/test_vm_launch_argv.sh`, which checks that the
Windows machine gets secure-boot firmware, a TPM and a protected variable store
while the Ubuntu one gets none of them.