rss logo

How to Virtualize Windows 11 with QEMU and USB Device Support

Qemu logo

I've previously discussed how to set up a Windows virtual machine on an Arch Linux host to enable the use of a USB peripheral (specifically, the Canon CanoScan 4400F scanner). That article focused on Windows 10, which is now reaching its end of support. As a result, it's an opportune time to update that guide for Windows 11. Given that this newer version of Windows introduces significant changes—such as requirements for TPM, Secure Boot, specific CPU, and UEFI boot-several key aspects of the setup need to be reconsidered and adjusted accordingly.

QEMU Architecture

As mentioned in the introduction, this guide demonstrates how to virtualize a Windows 11 operating system. To achieve this, both TPM and UEFI need to be emulated. The system will be installed on a WIN11.cow virtual disk, and a USB scanner is connected to the Arch Linux host.

Diagram showing QEMU virtualizing Windows 11 on Arch Linux with TPM, UEFI, and USB scanner passthrough
Architecture of a QEMU virtual machine running Windows 11.

USB Device

To use the USB device, we first need to identify it and then assign the correct permissions. Specifically, we must ensure the current user is authorized to interact with it.

  • Install the cyme tool, which is an alternative to lsusb:
[root@host ~]# pacman -S cyme
  • List the USB devices and take note of the Bus and Device IDs:
[user@host ~]$ cyme -l | grep -i Canon
Bus 003 Device 002: ID 04a9:2228 Canon, Inc. CanoScan 4400F
  • As we can see, it is owned by root:
[user@host ~]$ ls -l /dev/bus/usb/003/002 
crw-rw-r--+ 1 root root 189, 257  4 mai   18:49 /dev/bus/usb/003/002

Temporary Solution

A temporary solution is to change the device owner manually from a root prompt. This change must be repeated after every reboot.

  • Change the owner to your current user:
[root@host ~]# chown user:user /dev/bus/usb/003/002

Permanent Solution

To make the change persistent, we will create a udev rule that automatically assigns the user as the device owner.

  • First, retrieve the main device attributes:
root@host:~# udevadm info --attribute-walk --path=$(udevadm info --query=path --name=/dev/bus/usb/003/002)
Udevadm info starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/devices/pci0000:00/0000:00:14.0/usb3/3-1':
    KERNEL=="3-10"
    SUBSYSTEM=="usb"
[…]
    ATTR{idProduct}=="2228"
    ATTR{idVendor}=="04a9"
[…]

Once the device attributes have been identified, we can create the corresponding udev rule.

  • Create and edit the file /etc/udev/rules.d/80-scanner.rules:
SUBSYSTEM=="usb", ATTR{idVendor}=="04a9", ATTR{idProduct}=="2228", OWNER="user", GROUP="user"
  • Reload the udev rules to apply the changes:
[root@host ~]# udevadm control --reload
  • Verify that the udev rules are correctly applied:
[root@host ~]# udevadm test $(udevadm info --query=path --name=/dev/bus/usb/003/002) | less
[…]
Reading rules file: /etc/udev/rules.d/80-scanner.rules
[…]
  • Finally, verify that the permissions have been correctly applied:
[user@host ~]$ ls -l /dev/bus/usb/003/002
crw-rw-r-- 1 user user 189, 129 31 oct.  09:20 /dev/bus/usb/003/002

QEMU

Initial Setup

Packages

  • Install the QEMU packages, along with the UEFI and TPM tools:
[root@host ~]# pacman -S qemu-full qemu-hw-usb-host edk2-ovmf swtpm wget

Virtual Disk

  • Create the virtual disk (add the -o nocow=on option if using a Btrfs file system):
[user@host ~]$ qemu-img create -f qcow2 WIN11.cow 80G
Formatting 'WIN11.cow', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=85899345920 lazy_refcounts=off refcount_bits=16
  • If needed, you can resize the virtual disk image:
[user@host ~]$ qemu-img WIN11.cow +10G

VirtIO

VirtIO is a virtualization standard for network and disk device drivers where just the guest's device driver "knows" it is running in a virtual environment, and cooperates with the hypervisor. This enables guests to get high performance network and disk operations, and gives most of the performance benefits of paravirtualization. (source: https://wiki.libvirt.org/Virtio.html).

[user@host ~]$ wget "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso"

Secure Boot

Since Arch does not currently provide its own OVMF_VARS.secboot.4m.fd file with pre-enrolled keys, we need to obtain it from a distribution that does—such as Fedora. To do this, download the appropriate RPM package and extract the OVMF_VARS.secboot.4m.fd file from it.

  • Create a directory to store the Secure Boot files:
[user@host ~]$ mkdir secboot
  • Install the necessary RPM extraction tools:
[root@host ~]# pacman -S rpmextract
[user@host ~]$ wget "https://kojipkgs.fedoraproject.org/packages/edk2/20241117/5.fc42/noarch/edk2-ovmf-20241117-5.fc42.noarch.rpm"
  • Extract the contents of the RPM package:
[user@host ~]$ rpmextract.sh edk2-ovmf-20241117-5.fc42.noarch.rpm
  • Convert the extracted OVMF_VARS_4M.secboot.qcow2 file to OVMF_VARS_4M.secboot.fd format:
[user@host ~]$ qemu-img convert -O raw -f qcow2 usr/share/edk2/ovmf/OVMF_VARS_4M.secboot.qcow2 OVMF_VARS_4M.secboot.fd
  • Finally, copy the OVMF_CODE.secboot.4m.fd and OVMF_VARS_4M.secboot.fd files from the edk2-ovmf package into the secboot directory:
[user@host ~]$ cp /usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd ./secboot
[user@host ~]$ cp OVMF_VARS_4M.secboot.fd ./secboot

TPM

We will later use the swtpm command to create a UNIX socket that QEMU will connect to.

  • Create a directory to store the TPM data:
[user@host ~]$ mkdir tpm

Directory Organization

Organize all downloaded or created files in a clear structure.

  • I personally chose the following organization:
    • secboot directory: contains the OVMF_VARS_4M.secboot.fd and OVMF_CODE.secboot.4m.fd files
    • tpm directory: contains swtpm-sock (created when running the swtpm socket command)
    • WIN11.cow: the virtual disk image
    • virtio-win.iso: the VirtIO driver ISO
File structure showing required QEMU VM files: OVMF UEFI firmware, TPM state, disk image, and ISO files on Arch Linux

Windows 11 Installation

We are now ready to launch the virtual machine and begin the installation of Windows 11.

  • Run the following command to create the UNIX socket:
[user@host ~]$ swtpm socket --tpm2 --tpmstate dir=./tpm --ctrl type=unixio,path=./tpm/swtpm-sock
  • From another terminal, verify that the following files are present in the tpm directory:
[user@host ~]$ ls tpm/
swtpm-sock  tpm2-00.permall
  • Run the following command from your main QEMU directory using these parameters:
    • -machine q35: required for Secure Boot
    • -m 8192: allocates 8 GB of RAM to the VM
    • -smp cores=4: assigns 4 virtual CPU cores
    • -boot order=d: boots from the CD-ROM drive

Note: If needed, you can connect to the VM using a VNC client—for example, with the following command: vncviewer -PreferredEncoding tight 127.0.0.1:5900

[user@host ~]$ qemu-system-x86_64 -machine q35 -m 8192 \
-cpu host -enable-kvm -smp cores=4 \
-net nic,model=virtio-net-pci,macaddr=52:54:00:12:34:56 -net user,id=mynet0,net=192.168.76.0/24,dhcpstart=192.168.76.9 \
-cdrom ./Win11_24H2_English_x64.iso \
-drive file=./virtio-win.iso,media=cdrom,index=3 \
-boot order=d \
-drive file=./WIN11.cow,index=0,media=disk,if=virtio,format=qcow2 \
-chardev socket,id=chrtpm,path=./tpm/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 \
-drive if=pflash,format=raw,readonly=on,file=./secboot/OVMF_CODE.secboot.4m.fd -drive if=pflash,format=raw,file=./secboot/OVMF_VARS_4M.secboot.fd
  • At the disk selection stage, you must load the VirtIO storage drivers manually:
Windows 11 setup screen showing the Load Driver button during disk selection in QEMU virtual machine
  • Navigate to viostor > w11, select the amd64 directory, and click OK:
Windows 11 setup showing selection of VirtIO driver path: viostor > w11 > amd64 during installation on QEMU VM
  • Select the VirtIO driver and click Install:
Windows 11 setup displaying Red Hat VirtIO SCSI controller driver selected for installation in QEMU virtual machine
  • Once Windows 11 is installed, proceed to install the VirtIO drivers:
Windows File Explorer showing virtio-win ISO contents with virtio-win-gt-x64 installer highlighted for VirtIO drivers

Post-Installation

  • Once Windows 11 is installed, you no longer need the installation media or the VirtIO ISO. You can also:
    • Enable RDP redirection to allow remote connections via RDP using: hostfwd=tcp::5555-:3389
    • Add -boot order=c to boot directly from the virtual hard drive
    • Enable USB pass-through for a host device using: -device usb-host,hostdevice=/dev/bus/usb/003/002
[user@host ~]$ qemu-system-x86_64 -machine q35 -m 8192 \
-cpu host -enable-kvm -smp cores=4 \
-net nic,model=virtio-net-pci,macaddr=52:54:00:12:34:56 -net user,id=mynet0,net=192.168.76.0/24,dhcpstart=192.168.76.9,hostfwd=tcp::5555-:3389 \
-boot order=c \
-drive file=./WIN11.cow,index=0,media=disk,if=virtio,format=qcow2 \
-chardev socket,id=chrtpm,path=./tpm/swtpm-sock -tpmdev emulator,id=tpm0,chardev=chrtpm -device tpm-tis,tpmdev=tpm0 \
-drive if=pflash,format=raw,readonly=on,file=./secboot/OVMF_CODE.secboot.4m.fd -drive if=pflash,format=raw,file=./secboot/OVMF_VARS_4M.secboot.fd \
-device qemu-xhci,id=xhci -device usb-host,hostdevice=/dev/bus/usb/003/002
  • You can then connect to the virtual machine via RDP and verify the presence of the USB device:
[user@host ~]$ xfreerdp3 /v:127.0.0.1:5555 /w:1080 /h:720 /u:"USER" /p:"PASSWORD" /cert:ignore
Windows 11 Device Manager showing Canon CanoScan scanner detected under Other devices via USB passthrough in QEMU
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Contact :

contact mail address