Windows target
Windows target — CloudBootTarget=windows
cloud-boot’s loader can chain-load the Windows Boot Manager
instead of a Linux kernel or a BSD loader.efi. The mechanism is the
same as the BSD targets — LoadImage(DevicePath, SourceBuffer=NULL) with a composite EFI_DEVICE_PATH so the chained
binary’s LoadedImage.FilePath is populated.
Selecting the Windows target
Set the EFI variable CloudBootTarget to windows. The loader
routes the FAT-ESP lookup to:
- Vendor path:
\EFI\Microsoft\Boot\bootmgfw.efi— whereSetup.exewrites the Boot Manager on every supported edition (Windows 10, 11, Server 2016+). - Fallback path:
\EFI\BOOT\BOOTX64.EFIon amd64,\EFI\BOOT\BOOTAA64.EFIon arm64 — where Windows-To-Go sticks, recovery media, and PE-based installers put the binary.
The cascade is identical in shape to the FreeBSD two-step,
and the self-handle skip in tryAllHandles prevents the obvious
infinite loop against our own BOOTAA64.EFI / BOOTX64.EFI.
Why it shares the BSD code path
Windows Boot Manager introspects its own LoadedImage.FilePath
to find the NTFS partition that holds \Windows\System32\winload.efi
and the BCD store. Without a populated FilePath (which is what
LoadImage(SourceBuffer=…) gives you), the Boot Manager walks
through disks blindly looking for a BCD — exactly the failure mode
FreeBSD’s loader hits.
So the gate in tryLoadFromHandle is the semantic
wantsFilePathHandoff() =
isBSDTarget() || isWindowsTarget(). Linux UKIs stay on the
SourceBuffer path (the EFI stub doesn’t introspect FilePath); BSDs
and Windows go through the DevicePath branch.
Status
| What | State |
|---|---|
| Loader routing | ✅ committed (windowsTag, isWindowsTarget, vendor + fallback cascade in _start) |
| Unit test of the gate | ☐ pending (would add to loader/cmd/efi-loader/main_test.go if there were one) |
| E2E QEMU boot to Windows desktop | ☐ pending — see Test recipe below |
| Apple VZ E2E | ☐ pending (same reasoning as BSD: Linux works on VZ, structurally nothing blocks Windows) |
Test recipe (QEMU/OVMF, arm64)
There’s no “official Windows cloud image” in qcow2/raw form, but two free legit paths exist:
| Source | Format | Free? | Notes |
|---|---|---|---|
| VHDX (Hyper-V) | — | Retired. developer.microsoft.com/…/microsoft-edge/tools/vms/ returns 404 (checked with a browser user-agent too, 2026-09-23). Use the Eval Center row. | |
| Windows Server eval (Eval Center) | ISO | 180-day eval | Need to install once, then commit the qcow2 |
| Hyper-V Server 2019 | ISO | gratis perpetual | Lite — headless, smallest image |
Windows-To-Go via WinToUSB | raw partition | personal use OK | Reproduces the \EFI\BOOT\BOOT<arch>.EFI fallback path |
For the loader’s CloudBootTarget=windows smoke test the dev VMs
used to be the path of least resistance — they booted directly
without a manual install. With that programme retired, the Eval
Center ISO is the remaining free route, and it needs one install
before the qcow2 can be committed.
The routing itself does not need Windows at all: the
windows-stub is a
~3 KiB PE32+ that mimics Boot Manager’s handoff, and exercises the
same LoadImage(DevicePath) path with no Microsoft bytes involved.
One-shot test script
loader/scripts/test-windows.sh automates the dev-VM smoke test:
# 1. Obtain a Windows VHDX once, manually, after agreeing to whatever
# eval terms it carries. The Edge dev-VM programme this used to
# name is retired; the Eval Center is the remaining free route.
# Place the VHDX at $HOME/Downloads/MSEdge-Win11.vhdx (or pass
# --vhdx <path>).
loader/scripts/test-windows.sh --vhdx ~/Downloads/MSEdge-Win11.vhdx
# 2. The script:
# - Converts the VHDX to raw via qemu-img convert.
# - Builds the loader (task -d ../ link-amd64) into BOOTX64.EFI.
# - Stages a tiny FAT ESP containing our BOOTX64.EFI + a NVRAM
# seed that pre-sets CloudBootTarget=windows.
# - Launches qemu-system-x86_64 with OVMF, the ESP, and the
# Windows disk.
# - Tails the serial console for the magic strings
# "LoadImage(DevicePath) OK" (our loader handed off) and
# "Loading kernel..." or "Windows" (Boot Manager started).
# - Times out after 4 minutes if either marker doesn't appear.Expected serial output
our DeviceHandle captured
target from EFI var CloudBootTarget: windows
trying UKI \EFI\Microsoft\Boot\bootmgfw.efi
skipping self device handle
found UKI, size = 0x...
LoadImage(DevicePath) OK, child handle = 0x...
StartImage...
(Windows Boot Manager takes over — graphics console blanks the serial)If the vendor path missed (e.g. the disk image is Windows-To-Go
style with the binary at \EFI\BOOT\BOOTX64.EFI):
windows: vendor path missed, trying fallback \EFI\BOOT\boot<arch>.efi
trying UKI \EFI\BOOT\BOOTX64.EFI
...The windows-stub shortcut for routing tests
The cloud-boot org publishes a tiny BSD-licensed PE32+ binary
that mimics Windows Boot Manager’s first ~10 ms of startup — just
enough to test the loader’s CloudBootTarget=windows routing
end-to-end without any Microsoft binary on disk.
Source: cloud-boot/windows-image/stub/.
Published OCI artifact:
ghcr.io/cloud-boot/windows-stub:latest, built and published by cloud-boot/windows-image.
The stub:
- Opens
LoadedImageProtocolon its own ImageHandle. - Asserts
LoadedImage.FilePathis non-NULL — proves the loader didLoadImage(DevicePath, SourceBuffer=NULL)rather than the SourceBuffer path. (A regression inbuildFilePath()upstream would surface here as a hard fail instead of silently passing.) - Prints
Windows Boot Manager (cloud-boot stub)to ConOut — matchestest-windows.sh’s grep regex. - Calls
ResetSystem(EfiResetShutdown)so QEMU exits cleanly.
Use it via --stub mode of the test script:
loader/scripts/test-windows.sh --stub
# Pulls ghcr.io/cloud-boot/windows-stub, stages a 64 MiB FAT disk
# with the stub at \EFI\Microsoft\Boot\bootmgfw.efi, runs the
# full QEMU + loader handoff sequence, greps the serial for both
# "LoadImage(DevicePath) OK" and "Windows Boot Manager".For real-Windows runs (full Boot Manager startup, BCD parsing,
graphics console), use the same script with --vhdx <path> after
downloading a dev VM under your own EULA.
What’s NOT done yet
- Live boot to Windows desktop. The routing code paths Windows-style; the LoadImage handoff is the same as FreeBSD’s (verified end-to-end). No structural reason Windows wouldn’t reach the Boot Manager graphics under OVMF — but no run has been captured yet.
- TPM / Secure Boot. Modern Windows (Server 2022+, 11) refuses
to install without a TPM and a Secure Boot key chain. Booting
an already-installed image like a dev VM doesn’t require this
at runtime, so the test recipe above sidesteps the issue. For
fresh Windows installs under QEMU the operator needs to add
-tpm-tis-device+ the Microsoft UEFI CA keys to OVMF_VARS. - Apple VZ. Untested. The Linux path works on VZ; the
protocol set VZ exposes (
BlockIO+SimpleFileSystem) is exactly what the FilePath-handoff branch needs. No code difference, just no runner script yet.
See also
- BSD targets — the parent design pattern.
- Three boot paths — where the Windows branch sits in the overall architecture.
loader/README.mdfor the implementation-level commentary.