Setting Windows VM on Linux

· 16min · Dmitry Scherbakov
cover

Introduction

This article initially started up as a guide to configure KVM for Windows 10/11. Now, obviously, it is still a guide on configuring KVM for Windows 10/11, but there is more stuff on Windows such as debloating, software installation, configuration and etc (see below).

Examples

You can download some examples of configuration files here (zipped folder).

System requirements

You would need a processor with virtual machine acceleration support. Minimal system requirements for running windows VM:

  • 2.4+ Ghz CPU with virtualization support and 4+ cores (technically you can even use CPU with 2 cores, but windows guest and host performance issues would blame you).
  • 8+ GiB RAM (windows 10 requires at least 4 GiB RAM. Even debloated windows 10 with anti-malware services stopped still eats 3 GiB RAM on standby).
  • SSD or NVME (anything except for HDDs - they are slow, so you would literally spend DAYS installing windows or, presumably, any other OS) with 100+ GiB of free space.
  • VT-d (or iommu) support for your processor. This feature is required only if you are planning to do PCI/USB devices passthrough to your VM (for example, GPU passthrough). These settings are different for all firmware settings out there so just google how one looks like on your settings.

Firmware settings to enable virtualization

  • Enable virtualization:
    • Intel: enable vmx or Intel Virtualization Technology option.
    • AMD: enable AMD Virtualization Technology option.
  • If you are planning to passthrough PCI/USB devices, make sure to enable IOMMU passthrough:
    • Intel: enable VT-d option.
    • AMD: enable iommu option.

Warning! Make sure to reboot your system after this step.

Kernel settings to enable virtualization

  1. Open /etc/default/grub file in your preferred text editor.

  2. Add following options to GRUB_CMDLINE_LINUX_DEFAULT variable:

    • Intel: intel_iommu=on iommu=pt
    • AMD: amd_iommu=on iommu=pt
  3. If variables GRUB_CMDLINE_LINUX_DEFAULT or GRUB_CMDLINE_LINUX contain quiet argument, make sure to remove it (at least during the VM configuration, since it would help to indicate kernel issue during boot time if one appears).

  4. Regenerate grub configuration files and reboot the machine:

    grub-mkconfig -o /boot/grub/grub.cfg
    
  5. If you are planning to passthrough PCI devices (not USB), we need to add them to kernel commandline as well: Run the following script in your terminal (no elevated privileges required):

    #!/bin/bash
    shopt -s nullglob
    for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do
        echo "IOMMU Group ${g##*/}:"
        for d in $g/devices/*; do
            echo -e "\t$(lspci -nns ${d##*/})"
        done
    done
    

    Sample output of this script:

    IOMMU Group 0:
            00:02.0 VGA compatible controller [0300]: Intel Corporation CoffeeLake-S GT2 [UHD Graphics 630] [8086:3e98] (rev 02)
    IOMMU Group 1:
            00:00.0 Host bridge [0600]: Intel Corporation 8th/9th Gen Core 8-core Desktop Processor Host Bridge/DRAM Registers [Coffee Lake S] [8086:3e30] (rev 0d)
    IOMMU Group 2:
            00:01.0 PCI bridge [0604]: Intel Corporation 6th-10th Gen Core Processor PCIe Controller (x16) [8086:1901] (rev 0d)
            01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU106 [GeForce RTX 2060 SUPER] [10de:1f06] (rev a1)
            01:00.1 Audio device [0403]: NVIDIA Corporation TU106 High Definition Audio Controller [10de:10f9] (rev a1)
            01:00.2 USB controller [0c03]: NVIDIA Corporation TU106 USB 3.1 Host Controller [10de:1ada] (rev a1)
            01:00.3 Serial bus controller [0c80]: NVIDIA Corporation TU106 USB Type-C UCSI Controller [10de:1adb] (rev a1)
    

    Warning! If you want to pass a PCI device to VM, you need to pass all devices, which are in the same group with your device, otherwise nothing would work. For example, if I were to pass my GeForce RTX 2060 SUPER to VM, I would also need to pass other devices from IOMMU group 2 to VM (as long as they are available).

    Device ids can be found in [] brackets at the same line as the device name and description. For example, my GeForce RTX 2060 SUPER has device id 10de:1f06. Copy all these device ids and open back grub configuration.

    Append following option to GRUB_CMDLINE_LINUX_DEFAULT: vfio-pci.ids=<device1>,<device2>,<device3>,..., where device1, device2, device3 are ids of devices you have selected (comma separated). Example: vfio-pci.ids=8086:1901,10de:1f06,10de:10f9,10de:1adb.

  6. Open /etc/modprobe.d/vfio.conf in your preferred text editor (file might not exist).

  7. Append the following text:

    options vfio-pci ids=<device1>,<device2>,<device3>,...
    

    Where where device1, device2, device3 are ids of devices you have selected (comma separated, should look the same as in kernel commandline).

    If you are using NVIDIA GPU, append this as well:

    softdep nvidia pre: vfio-pci
    

    Warning! softdep nvidia pre: vfio-pci works only when you have proprietary nvidia driver installed (pacman -S nvidia). With open source nvidia driver (nouveau) this line should be changed to something like: softdep nouveau pre: vfio-pci (NOT TESTED!).

    Example:

    options vfio-pci ids=8086:1901,10de:1f06,10de:10f9,10de:1adb
    softdep nvidia pre: vfio-pci
    
  8. Regenerate grub configuration one more time and reboot your machine.

Installing required packages

  1. On Arch linux (or any Arch-derived distributive) run:

    pacman -S qemu-full virt-manager virt-viewer dnsmasq vde2 bridge-utils openbsd-netcat libguestfs
    

    If you are using any other other distributive, you can figure out yourself how these packages are called for your package manager, it is not that complicated.

    Warning! On Artix linux, you should also install libvirt package for your specific init system, for example: libvirt-openrc

  2. After installation, make sure to enable and start libvirtd daemon:

    systemctl enable libvirtd.service
    systemctl start libvirtd.service
    

    Or

    rc-update add libvirtd
    rc-service libvirtd start
    
  3. Configure libvirtd by modifying /etc/libvirt/libvirtd.conf file: Make sure that settings, presented in following lines exist (if not, insert them) and are NOT commented (if so, uncomment them) and set to the correct values:

    unix_sock_group = "libvirt"
    unix_socket_ro_perms = "0777"
    unix_socket_rw_perms = "0770"
    
  4. Add yourself to the libvirt group:

    useradd -aG libvirt <username>
    

    Where <username> stands for your username (you can use $USER environment variable instead).

  5. Restart libvirtd service by running:

    systemctl restart libvirtd.serice
    

    Or

    rc-service libvirtd restart
    
  6. Open application, called Virtual Machine Manager (included in virt-manager package) and do the following:

    • Open Edit => Preferences and tick Enable XML editing feature.
    • Open Edit => Connection Details => Virtual Networks. Make sure to set Autostart (on boot) property.
  7. If you are installing Windows 11 (which requires TPM device), make sure to install following package to emulate TPM:

    pacman -S swtpm
    

Warning! Make sure to logout and login back or reboot your system to make sure you have got added to the libvirt group.

Downloading required ISOs

  1. Download Windows 10 ISO from Microsoft website or use 3rd party ISO downloader.
  2. Download Qemu VirtIO drivers for Windows from github repository. I recommend choosing Stable version instead of latest. Also make sure that you are downloading ISO, not RPM or any other package.

Creating VM

  1. Open application, called Virtual Machine Manager (included in virt-manager package). Hit File => New Virtual Machine and configure your virtual machine. I recommend giving it at least 2 CPU cores and 4 GiB of RAM. On the last page, click Configure Before Installation and hit Finish.
  2. Set firmware type to UEFI.
  3. Open CPUs section and hit Manually set CPU topology. Make sure that socket count is 1 (do not know why virt manager does this by default). Adjust the CPU topology for optimal performance. If your host machine has more than 1 logical core per physical core, specify this in topology.
  4. Add TPM device if you are installing Windows 11. Click Add Hardware => TPM. Make sure to set type to Emulated.
  5. Remove USB Redirector #... devices from your VM (if they exist). They are useless.
  6. If you are installing Windows 11, remove network adapter from VM (you would add it later, after installation).
  7. Now launch your VM and install Windows. After installation is complete, shut the VM down and remove the installation (windows) ISO.
  8. Add ISO for qemu virtio drivers and boot Windows.
  9. Add temporary virtio disk. Add Hardware => Storage. Nobody actually cares about this disk, so you can just leave its size to 1GiB. If you can change the disk type to virtio, do that, otherwise open XML properties for this disk and modify following:
    1. In target field change bus option to virtio.
    2. In address field change type option to pci.
  10. Boot the VM. Open ISO folder and launch virtio-win-guest-tools application.
  11. After installation is complete, power off the VM. Remove the qemu virtio drivers installation media as well as temporary virtio drive.
  12. Open XML properties for windows virtual disk (the one, which contains windows installation):
    1. In target field change bus option from sata to virtio.
    2. In address field change type option from drive to pci.
    3. In driver field add discard="unmap" option (if does not exist already).
  13. Open NIC (Network Interface Card)properties and change Device model to virtio (If you are installing Windows 11 and you have deleted the NIC, just create new one).

GPU passthrough

  1. Open virtual machine settings and click Add Hardware => PCI Host Device. For each device id that you have configured kernel to isolate and use virtio driver in kernel settings to enable virtualization step, add it to virtual machine.

  2. Boot your virtual machine. You should not use your GPU output port for now, since it is not configured properly. Download nvidia drivers (I suggest downloading game ready driver, since it appears to be NVIDIA's general purpose solution for its GPUs) using this link.

    If your mouse stops working after driver installation, it is totally ok, fixing this in further steps.

    Now your GPU is fully configured. Make sure to connect your monitor with it.

  3. Open Overview section in your VM settings. Open XML editor. Find and delete all properties which have spice or vnc or vga (case-insensitive). Delete all SPICE and VGA related stuff from your virtual machine settings (both XML and UI). Remove USB redirectors from your settings (can be done with UI).

  4. Now you can boot your virtual machine (not recommended yet!). Video would now be displayed through GPU.

Known issues with GPU passthrough

  • XFCE4: When switching between VM and host Display (Display settings) window pops up:
    1. Navigate to Settings => Display => Advanced.
    2. Set property When new displays are connected (in the Connecting Displays section) to Do nothing.
  • XFCE4: When switching between VM and host resolution resets to monitor default:
    1. Instead of changing monitor resolution, use scaling. Example: monitor has default resolution 3840x2160; instead of chaning it to 1920x1080, set scale to 0.5x0.5.

Setting up EVDEV for input device management

  1. Open Overview section in your VM settings. Open XML editor. Replace first line in XML content with the following text:

    <domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0" type="kvm">
    
  2. Clone evdev repository (it is not recommended to delete it after installation for further configuration, so place it somewhere safe):

    git clone --depth 1 https://github.com/pavolelsig/evdev_helper.git
    cd evdev_helper
    

    Run the run_ev_helper.sh script:

    chmod a+x run_ev_helper.sh
    ./run_ev_helper.sh
    

    This script would create file named evdev.txt. Evdev would configure qemu so that:

    • To redirect input from keyboard/mouse to VM, you should press left and right CTRL keys simultaneously.
    • To switch input from keyboard/mouse back to host, you should press left and right CTRL simultaneously.

    This script also creates qemu backup configuration - stored in .backup.qemu.conf file.

    Copy all contents of evdev.txt file except for first line (you have already inserted that at step 1) and insert it in your VM XML configuration (open Overview => XML) at the very end of the configuration - below </devices> and above </domain>.

  3. Copy following XML and insert it in your VM XML configuration (open Overview => XML) at the very end of the configuration - below </devices> and above </domain>:

    <qemu:capabilities>
      <qemu:del capability="usb-host.hostdevice"/>
    </qemu:capabilities>
    
  4. Now you can start virtual machine (make sure to switch monitor signal input to the GPU you have passed through).

Further performance optimizations

  • Enable IO threads (disk might work faster).

    1. Insert following XML under domain property in virtual machine XML configuration (open Overview => XML):
      <iothreads>1</iothreads>
      
      You can have more io threads, but it is not recommended to have more than one.
    2. Open XML properties for windows virtual disk (the one, which contains windows installation) And append following parameters to driver property (remove duplicates):
      • cache="none"
      • io="threads"
      • queues="6" (set to whatever vCPUs you have provided VM with).
  • Enable static CPU placement (not recommended for standart installation, unless you want to maximum performance):

    1. Add placement="static" option in vcpu property in virtual machine XML configuration (open Overview => XML):

    2. Under vcpu property add cputune section. This section would specify, which virtual processor would be bound to which physical (or logical) core. Specify binding with the following XML:

      <vcpupin vcpu="<virtual cpu index>" cpuset="<physical cpu index>"/>
      

      Where virtual cpu index and physical cpu index are just integers. You must mention all virtual CPUs in binding settings.

      Example:

      <cputune>
        <vcpupin vcpu="0" cpuset="1"/>
        <vcpupin vcpu="1" cpuset="5"/>
        <vcpupin vcpu="4" cpuset="3"/>
        <vcpupin vcpu="5" cpuset="7"/>
      </cputune>
      

      You can also add emulatorpin property to set affinity for qemu emulator (multiple cores can be specified):

      <emulatorpin cpuset="0,4"/>
      

      If you are using iothreads, you can setup binding for iothread as well by adding iothreadpin property (multiple cores can be specified):

      <iothreadpin iothread="1" cpuset="0,4"/>
      

      Example with iothreadpin and emulatorpin:

      <cputune>
        <vcpupin vcpu="0" cpuset="1"/>
        <vcpupin vcpu="1" cpuset="5"/>
        <vcpupin vcpu="4" cpuset="3"/>
        <vcpupin vcpu="5" cpuset="7"/>
        <emulatorpin cpuset="0,4"/>
        <iothreadpin iothread="1" cpuset="0,4"/>
      </cputune>
      

      Make sure to separate VM-related cores and stuff-related cores (qemu emulator or io threads) to maximize performance.

    3. Replace the entire <hyperv> tree configuration settings with the following:

      <hyperv mode="custom">
        <relaxed state="on"/>
        <vapic state="on"/>
        <spinlocks state="on" retries="8191"/>
        <vpindex state="on"/>
        <synic state="on"/>
        <stimer state="on">
          <direct state="on"/>
        </stimer>
        <reset state="on"/>
        <frequencies state="on"/>
        <reenlightenment state="on"/>
        <tlbflush state="on"/>
        <ipi state="on"/>
      </hyperv>
      

Bluetooth

Since bluetooth is USB-bus device (even motherboard-integrated bluetooth uses USB bus), you do not need to configure it same as PCI devices. Open VM settings, click Add Hardware, click USB Host Device, select and add your bluetooth device to VM.

Windows configuration

  • Both windows 10 and 11 contain a lot of bloatware out of the box. Since we are configuring virtual machine, most of this bloatware would never be used, such as camera, cortana, diagnostic centre etc. For Windows 11 installation (would also work on windows 10, but not recommended) you can use this debloat script collection. For Windows 10 installation you can use this script (project is abandoned, but is still useful).
  • You can also use free tool O&O ShutUp10++: Free antispy tool for Windows 10 and 11. It allows to tweak some windows telemetry/spy/data collection settings. Download link. When configuring windows using this app, make sure to apply settings both for current user and entire system.
  • You can also use Chris Titus Windows Tool, which combines A LOT OF functionality, including debloating stuff, software removal, all kinds of tweaks, automated software install and many more. Configuration system is also supported.
  • Completely remove Microsoft Edge:
    1. Open Command Prompt with Administrator privileges.
    2. Navigate to C:\Program Files (x86)\Microsoft\Edge\Application\<edge-version-here>\Installer. <edge-version-here> stands for current edge version, which typically looks like this: 92.0.902.67. If you have many different edge versions installed, you should repeat uninstall process for each version.
    3. Execute following (make sure to do this as an administrator):
      setup.exe -uninstall -system-level -verbose-logging -force-uninstall
      
    4. Open task manager and kill all tasks, which are related to edge. Since we had already uninstalled it, you should mostly look for processes like EdgeUpdater... etc. Make sure to destroy all of them.
    5. Open services management page (both on windows 10 and windows 11 you can do this via task manager). Find services related to edge (typically those are auto-update services). Open their properties and make sure to set Autostart Type to Disabled.
    6. Remove all related to edge folders in C:\Program Files (x86)\Microsoft. Those being: Edge, EdgeWebView, EdgeCore and some others (might depend on your windows installation). This process would require administrator privileges.
  • Adjust Windows Performance settings:
    1. Open Settings => System => About.
    2. Open System Protection men. For Windows 10 it is located on the right. For Windows 11 it is located on the bottom.
    3. Select Advanced tab in newly opened menu.
    4. Open Performance settings.
    5. Here you can remove basically all checked marks (since they not really usable much), except maybe for Smooth Edges of Screen Fonts (which basically enables font Anti-Aliasing for you). The best thing you can do is to adjust it depending on what exactly are you planning to do.

Warning! All this optimizations might not have good affect at your installation. Apply them at your own risk!

Windows activation

  1. Select your product key (same keys apply for both windows 10 and windows 11):

    EditionProduct Key
    HomeTX9XD-98N7V-6WMQ6-BX7FG-H8Q99
    Home N3KHY7-WNT83-DGQKR-F7HPR-844BM
    Home Single Language7HNRX-D7KGG-3K4RQ-4WPJ4-YTDFH
    Home Country SpecificPVMJN-6DFY6–9CCP6–7BKTT-D3WVR
    ProfessionalW269N-WFGWX-YVC9B-4J6C9-T83GX
    Professional NMH37W-N47XK-V7XM9-C7227-GCQG9
    EducationNW6C2-QMPVW-D7KKK-3GKT6-VCFB2
    Education N2WH4N-8QGBV-H22JP-CT43Q-MDWWJ
    EnterpriseNPPR9-FWDCX-D2C8J-H872K-2YT43
    Enterprise NDPH2V-TTNVB-4X9Q3-TJR4H-KHJW4

    By the way, the "N" in Windows stands for "Not with Media Player." As the name implies, the only difference between Windows N and other Windows editions is that it does not come with built-in multimedia features.

  2. Install KMS client key:

    slmgr /ipk <license-key>
    
  3. Connect to KMS server:

    slmgr /skms kms8.msguides.com
    
  4. Activate Windows

    slmgr /ato
    

    If your Windows didn't get activated, you can try another license key. Also check your internet connection.

Windows software installation

The majority of the software most people need can be installed via again, Chris Titus Windows Tool, as it was already mentioned in Windows configuration section. However, there are still programs that are either not covered by this tool, or those you want to install manually. We will not go though all of them, here are the common ones:

  • VMware Workstation. Product copies can be acquired from Broadcom website. You will to create an account. However, broadcom will not allow you to download anything, if it detects that you are trying to register or log in from country, sanctioned by the US. Unfortunately, VPNs (both private and public) do not solve this issue, so the best way to access and do anything on Broadcom website, unfortunately, is to use Tor. Don't forget to disable NoScript extension for all Broadcom website subdomains.
  • Microsoft Office. There is a guide on how to install Microsoft Office here. In short: Legit office configuration with volume licenses can be generated at config.office.com (click Create button in the bottom left corner). Detailed video can be found here. The video describes how to download and install Office 2021, but with config.office.com you can try to install whatever version you want. If you end up with error, try a different version. My recommendation is to select LTSC (long time support) releases.