The empty disk problem
You downloaded the Windows 11 ISO, opened virt-manager, and clicked through the wizard. The installer boots, but when it reaches the disk selection screen, the list is empty. Or the VM installs fine, runs at a crawl, and Device Manager shows a yellow triangle on the network adapter. You are not missing a step. You are missing the VirtIO drivers. Windows does not ship with paravirtualized drivers, and Fedora's KVM stack expects them for anything beyond toy performance.
What is actually happening under the hood
KVM turns your Linux kernel into a hypervisor. It hands off CPU and memory management directly to the guest operating system. Storage and networking, however, still need drivers. The default emulated devices mimic old hardware like IDE controllers and e1000 network cards. They work everywhere, but they add a translation layer that chokes on modern I/O. Every disk read and network packet passes through QEMU's emulation loop, which adds latency and burns host CPU cycles.
VirtIO removes that layer. It gives the guest a direct pipe to the host's storage and network stack. The guest driver speaks a standardized protocol, and the host kernel handles the actual hardware. Think of it like swapping a dial-up modem for a fiber optic cable. The connection is the same, but the throughput and latency change completely. Without the VirtIO ISO, Windows installs on emulated hardware, and you pay the performance tax forever.
Run the host stack first. The guest cannot speak VirtIO until the host provides the interface.
Install the host stack and fetch the drivers
Fedora groups the virtualization components into a single meta-package. Installing it pulls in QEMU, libvirt, virt-manager, and the SPICE protocol stack. The virtio-win package drops the driver ISO into a read-only system directory. You will mount that ISO inside the VM during installation.
Here is how to install the host components and prepare your user account:
sudo dnf install -y @virtualization virtio-win
# @virtualization pulls QEMU, libvirt, virt-manager, and SPICE
# virtio-win places the driver ISO in /usr/share/virtio-win/
sudo systemctl enable --now libvirtd
# libvirtd manages VM lifecycle, networks, and storage pools
sudo usermod -aG libvirt $(whoami)
# adds your user to the libvirt group for unprivileged VM control
Log out and log back in. Group membership changes do not apply to running sessions. The libvirt group grants your user permission to talk to the libvirtd socket without typing sudo for every VM action.
Fedora convention places user-modified configuration in /etc/libvirt/. Package-managed files live in /usr/lib/libvirt/. Never edit files in /usr/lib/. They will be overwritten on the next dnf upgrade. Keep your custom XML definitions in /etc/libvirt/qemu/ or let virt-manager handle them.
Check that the daemon is running before you proceed.
systemctl status libvirtd
# shows active (running) state and recent journal lines
If the service fails to start, run journalctl -xeu libvirtd to read the actual error. The x flag adds explanatory context and the e flag jumps to the end. Read the failure reason before guessing.
Create the virtual machine
You can build the VM through the virt-manager GUI or via the virt-install CLI. Both methods produce identical libvirt XML definitions under the hood. The CLI approach is faster for scripting and leaves a clear audit trail.
Here is the complete virt-install command for a modern Windows 11 guest:
virt-install \
--name win11 \
--ram 8192 \
--vcpus 4 \
--disk path=/var/lib/libvirt/images/win11.qcow2,size=64,bus=virtio \
--cdrom /path/to/Win11.iso \
--disk /usr/share/virtio-win/virtio-win.iso,device=cdrom \
--os-variant win11 \
--network network=default,model=virtio \
--graphics spice \
--boot cdrom,hd
# --name sets the VM identifier in libvirt
# --ram and --vcpus allocate host resources
# --disk bus=virtio enables paravirtualized storage
# --cdrom points to your Windows installation media
# --disk device=cdrom mounts the VirtIO driver ISO
# --os-variant tells libvirt to apply Windows 11 defaults
# --network model=virtio enables paravirtualized networking
# --graphics spice enables clipboard sharing and dynamic resizing
# --boot cdrom,hd ensures the installer loads first
The --os-variant win11 flag is important. It tells libvirt to enable UEFI firmware, secure boot, and the correct ACPI tables. Windows 11 refuses to install on legacy BIOS. The --graphics spice flag replaces VNC. SPICE supports clipboard sharing, dynamic display resizing, and better audio passthrough.
If you prefer the GUI, open virt-manager, click the plus icon, select local install media, and attach both the Windows ISO and the VirtIO ISO as separate CD-ROM drives. Set the disk bus to VirtIO and the network model to VirtIO in the customization step before boot.
Boot the VM immediately. The installer will hang on the disk selection screen until you load the storage driver.
Load the drivers during Windows setup
When the Windows installer reaches the "Where do you want to install Windows?" screen, the disk list will be empty. Click Load driver at the bottom of the window. The installer will prompt you for a location. Browse to the VirtIO CD-ROM drive. You will see a folder tree organized by Windows version and architecture.
Navigate to viostor\w11\amd64 for the storage driver. Select it and click Next. The installer will now detect the VirtIO disk and allow you to format and partition it. Continue with the standard Windows installation.
During the out-of-box experience (OOBE), the network adapter will still show as missing. Open File Explorer, navigate to the VirtIO CD-ROM drive, and run virtio-win-guest-tools.exe. This installer drops the remaining drivers onto the guest, including the network adapter, display driver, and SPICE guest agent. Reboot the VM when prompted.
The guest tools package also installs the Windows service that handles clipboard sharing and dynamic resolution changes. Without it, SPICE only provides a static framebuffer.
Run the guest tools installer before you configure the network. The OOBE screen will fail to reach Microsoft's activation servers without a working adapter.
Verify the paravirtualized stack
A successful installation shows VirtIO devices in Windows Device Manager. Open Device Manager and expand Disk drives. You should see VirtIO Disk Device. Expand Network adapters and look for VirtIO Ethernet Adapter. If you see Standard IDE/ATAPI or Intel PRO/1000, the VM is still using emulated hardware.
Here is how to verify the SPICE agent is communicating with the host:
virsh domstate win11
# confirms the VM is running and not paused
virsh dominfo win11
# shows uptime, vCPU count, and memory allocation
Inside Windows, open Services and locate VirtIO Windows Guest Agent. The status should be Running and the startup type should be Automatic. If the service is stopped, clipboard sharing and dynamic resizing will not work. Restart the service and test by copying text from Fedora to the Windows guest.
Check the host logs if the agent fails to connect.
journalctl -xeu libvirtd | grep spice
# filters libvirt logs for SPICE channel initialization
The SPICE protocol relies on a Unix socket inside the VM. If Windows Defender or a third-party firewall blocks the agent, the channel drops. Allow spice-vdagent.exe through the firewall if you see connection timeouts.
Verify the disk bus type in Device Manager. Emulated disks will never match host IOPS.
Common pitfalls and exact error symptoms
Windows installation on KVM fails in predictable ways. Recognizing the exact symptom saves hours of trial and error.
The installer prints Error 0x80070003: The system cannot find the path specified when you try to load the VirtIO driver. This happens when you browse to the wrong subfolder. The viostor folder contains storage drivers. The NetKVM folder contains network drivers. The Balloon folder contains memory management drivers. Select the folder that matches your current installation phase.
The VM boots to a blue screen with INACCESSIBLE_BOOT_DEVICE. This occurs when the disk bus changes between the installation phase and the first boot. If you installed on ide or sata and later switched the XML to virtio, Windows cannot find the boot volume. Keep the bus type consistent. Edit the libvirt XML to match the installation media, or reinstall.
The network adapter shows as Unknown Device after the guest tools install. This usually means Secure Boot is blocking an unsigned driver. Windows 11 enables Secure Boot by default. The VirtIO drivers are signed, but older virtio-win packages sometimes ship with expired certificates. Update the package with sudo dnf upgrade virtio-win and reboot the host. If the problem persists, disable Secure Boot in the VM's UEFI firmware.
The SPICE viewer shows a black screen after resizing. The guest agent is not running, or the display driver is still the Microsoft Basic Display Adapter. Run the guest tools installer again and force a reboot. The qxl or virtio-gpu driver must be active for dynamic resolution to work.
Read the Device Manager status codes before reinstalling. Code 28 means the driver is missing. Code 52 means the driver is corrupted. Code 43 means the hardware reported a failure. Fix the specific code instead of guessing.
Choose your management tool
Use virt-manager when you want a visual interface for creating, starting, and debugging VMs. Use virt-install when you need reproducible, scriptable VM creation for testing or deployment. Use Cockpit when you are managing multiple hosts and want a web-based dashboard with built-in monitoring. Use raw libvirt XML when you require fine-grained control over CPU pinning, NUMA topology, or custom PCI passthrough.
Stick to one management layer. Mixing CLI edits with GUI changes creates XML drift and breaks VM startup.