5 May 2025
Installing Windows for Dual Boot Without a USB, Using QEMU Drive Passthrough
Windows wanted to touch drives it had no business touching, I had no USB stick, and my BIOS couldn't help. So I installed it in a VM with full drive passthrough.
I wanted Windows on a second drive for occasional use, mostly games that anti-cheat refuses to run on Linux. The plan seemed simple enough: boot a USB installer, install to the second drive, done. It wasn't.
The problem stack
Three things conspired against the normal approach.
Windows will overwrite your EFI partition on a drive it has no business touching. My Linux install lives on an NVMe drive. The Windows target was a separate SATA SSD. Windows doesn't care about your intentions here. It scans every disk for an EFI System Partition and writes its bootloader to whichever one it feels like, regardless of which disk you told it to install to. If it picks your Linux drive, your existing boot entries get clobbered.
I didn't have a USB stick. The 8GB drive I would normally use was physically somewhere else, and I wasn't going to wait for a delivery just to install Windows.
I couldn't easily disconnect the Linux drive. My GPU is big enough that reaching the M.2 slot behind it means pulling the whole card. Not doing that for what should be a 20-minute job.
My BIOS (a mid-range ASUS board) can disable SATA ports, but not individual NVMe slots, so I couldn't tell the firmware to just pretend drive 0 didn't exist during the install. Out of easy options, then.
The actual solution: QEMU with full drive passthrough
The trick that saves the day: QEMU can pass a raw block device, an entire physical disk rather than a virtual disk image, straight through to a virtual machine. Windows running inside that VM sees the drive as real hardware, writes its bootloader to it, and lays out its partitions normally. The EFI boot entry Windows creates lands in the VM's own firmware, not your host UEFI. When the install is done, you boot the physical drive directly from your BIOS and it just works.
Preparing the target drive
First, wipe the drive and give it a fresh GPT partition table. Do this from Linux, before the VM ever sees the drive. It keeps Windows from making any creative decisions about your existing layout:
# Identify your target drive, double-check before wiping
lsblk
# Wipe existing partition table
sudo wipefs -a /dev/sdX
# Create new GPT layout (Windows needs GPT for UEFI install)
sudo parted /dev/sdX mklabel gpt
Leave the rest to the Windows installer. It will create its own EFI, MSR, and primary partitions.
Setting up the VM in virt-manager
Virtual Machine Manager (the virt-manager GUI for QEMU/KVM) makes drive passthrough pretty painless. When creating the new VM:
- Choose "Import existing disk image" as the install method (we're not actually using a disk image, we'll swap it out)
- Attach the Windows ISO as a virtual CD-ROM for the install media
- Add the physical disk via Add Hardware → Storage → Select or create custom storage
- Set device type to "Disk"
- Set bus to "VirtIO" or "SATA" (SATA is the safer bet for Windows compatibility)
- In the source field, type the raw device path:
/dev/sdX
The critical setting is the boot order: put the ISO (CD-ROM) first so the installer boots, with the physical disk sitting there as the install target.
Also make sure the VM uses UEFI firmware (OVMF), not legacy BIOS. Windows 11 requires it, and it's what your real hardware will boot anyway. In virt-manager: Overview → Firmware → UEFI x86_64: /usr/share/edk2/x64/OVMF.fd (package name varies by distro).
The install
Boot the VM and run through the Windows installer like normal, selecting the physical drive as the target. It partitions the disk, writes the bootloader, reboots the VM a few times, business as usual. The nice part is that Windows is writing to a real disk the whole time, just routed through the hypervisor.
One thing to watch out for: if you picked the VirtIO bus for the disk, the installer won't see the drive until you feed it the VirtIO drivers. Either stick with the SATA bus (slower but driver-free) or load the VirtIO driver ISO during the installer's "Load driver" step.
After the install: booting directly
Once Windows finishes installing inside the VM, shut it down. That's the last time you need the VM. From here on you boot the physical drive directly from your BIOS boot menu.
On real hardware, your motherboard's UEFI picks up the Windows Boot Manager entry on the SATA drive and boots straight into Windows. Your Linux bootloader on the NVMe drive is untouched, because Windows never even knew it existed during the install. That was the whole point.
From here, pick your favorite dual-boot arrangement:
- BIOS boot menu (F12 / F11): simplest, no shared bootloader config at all
- rEFInd: a graphical boot manager that auto-detects both OS entries
- GRUB with os-prober:
sudo grub-mkconfig -o /boot/grub/grub.cfgadds a Windows entry ifos-proberspots the drive
I went with GRUB. Running os-prober and regenerating the config picked up the Windows Boot Manager on the SATA drive automatically, so both entries show up at boot without any manual editing.
One-command reboots with grub-reboot-manager
The last bit of friction was rebooting into Windows. GRUB defaults to Linux, so switching meant either babysitting the boot menu or changing the default. I wrote a small helper script, grub-reboot-manager, to handle it.
It lists all GRUB menu entries, lets you pick one by number, then calls grub-reboot to set that entry as a one-time boot target before rebooting. The next boot goes to Windows (or whatever you picked), and after that GRUB falls back to the default again. No permanent config changes to forget about.
sudo grub-reboot-manager.sh
# lists entries, prompts for selection, confirms, reboots
Drop it in /usr/local/bin, give it an alias, and switching to Windows becomes a single command from the terminal.
Why this works better than it sounds
Drive passthrough mostly comes up in the context of fancy GPU passthrough builds, but it's useful any time you want to install an OS without gambling with your existing setup. The VM gives you isolation: Windows can't touch the Linux drive because the hypervisor simply never shows it. And what ends up on the physical disk is a completely native install that runs at full speed when booted directly.
One caveat worth knowing: Windows activation is tied to hardware fingerprints, and the fingerprint inside a VM differs from bare metal. If you activate inside the VM, you may need to reactivate on first direct boot. With a digital license tied to a Microsoft account this usually sorts itself out; with a volume key you may need the activation troubleshooter.
Total time from "I have no USB stick" to a working Windows install: about 45 minutes, most of it spent watching the installer copy files.
// comments