Create Windows VM using libvirt

Introduction

This is a simple guide about setting up a Windows guest using KVM. This guide will mainly focuse on using the GUI tool virt-manager with some minor tweak directly in the XML template.

There are many similar guides which you can find online. For example

    # the unraid documentation
    https://wiki.unraid.net/UnRAID_6/VM_Guest_Support

and

    # a useful blog post
    http://bkanuka.com/posts/windows-10-libvirt/

basic requirement

  1. Host machine: Ubuntu 20.04 with KVM installed.
  2. Windows system images(iso files).
  3. VirtIO drivers(in a iso file.)

Create the VM

  1. Open the virt-manager and select create a new virtual machine and then use local install media(ISO). Also, if it can’t detect the guest system from the iso file, you should manually set it to

        win(10) # or Microsoft Windows 10

    Note: you may find this Microsoft Windows 10(win 10) system type at the end of life operating systems category.

  2. Keep forward, you can set the memory and number of CPUs for this VM.

  3. You can create a disk image for this VM. This is a simpler choice. Also, you can choose not to create a disk image and passthrough a whole hard drive to your VM(which will not be covered in this guide).

    Note: this disk image can not be easily expanded(as far as I know) after creation. A post about [resizing disk image](/post/change-virtual-disk-image/) has been posted. So set its volumn wisely.(But actually you can always set up additional network storage or passthrough addtional disk space to your VM later.)

  4. In the final step, you can setup the name of your VM. Also remember to check Customize configuration before install so you can adjust some addtional settings before the VM fires up.

  5. In the configuration panel:

    1. In Overview, choose firmware to UEFI OVMF. I choose ‘OVMF_CODE.fd’. For chipset, I prefer Q35, but you can always try i440fx, their difference are quite subtle and depending on the very host machine setup.

    2. In CPUs, you should check the Copy host CPU configuration and in the Topology section. There are three options:

         - Sockets: consider it as the number of physical CPUs, most of the time Windows will support NO MORE THAN 2. I always set this to 1.
         - Cores: this is the number of physical cores in one CPU.
         - Threads: this is the number of threads in one physical core.

      If the virt-manager don’t get this topology right, you can always set them manually. In my laptop, I set them as 1-3-2, which means 1 CPU, with 3 cores and each core has 2 threads. These will take 6 cores(including hyperthreaded ones) in my host machine.

    3. Add the VirtIO dirver(iso file) into your VM. You can choose Add Hardware -> Storage -> Select or Create custom storage remember to set the device type to CDROME device. If you want to use VirtIO disk for your VM, then you must add this driver image so that Windows can grab it during the installation. Otherwise, you can add this and update the virtIO driver after the windows installation is finished.

    4. In Display Spice, make sure it’s set to Spice not VNC.

    5. In Video QXL, make sure the model is QXL and set the RAM up to 64MB if you want high-resolution display(like 4K). For this you’ll have to edit the XML template:

      1. In virt-manager panel, choose Edit -> Preference -> Enable XML editing.
      2. In Video QXL, go to XML tab and change vgamem value from 16384 to 65536.
    6. Add a “Watchdog” device with action Gracefully shutdown the guest.

    7. (Settings suggested by others) Under “SATA Disk 1” open the Advanced options and change Disk bus to VirtIO, and optionally change Cache mode to “writeback”.

      • Writeback means that when the Windows VM makes a write to disk, the host OS will cache this write in memory and tell the VM that the write is complete, before the write is saved to the host HDD. This is dangerous because it can corrupt the Windows VM if there is an incomplete write, but is faster than the default settings. If you never have a long running VM and take backups ofthen, then you can use writeback.
    8. (Settings suggested by others) Under “NIC” change device model to virtio.(Personally, I use the default e1000e.)

    9. (Settings suggested by others) Add hardware again and add an “Input” device with type EvTouch USB Graphics Tablet.

    10. (Settings suggested by others) Add hardware and add a “Channel” with name org.qemu.guest_agent.0. Leave the other settings as a default.

  6. After these configuration, you can choose Begin Installation at the top of the setting panel. The focus point may be grabbed by the VM window, you can use

       Ctrl(Left) + Alt(Left)

    to get the focus back to the host machine so you can move the mouse, etc. Also it’s possible you end up in a UEFI Interactive Shell, normally just type

       exit

    since you won’t be using any start up script. Then you’ll probably be prompted to a UEFI management page, just hit Continue if you don’t need to any modification.

  7. If you want to use the VirtIO driver, then during the windows installation, you have to choose to load the additianl drivers. Also, you should enable non-compatible drivers to see those VirtIO drivers. Besides that, the installation is just like a bare metal one.

  8. Normally the installed VM will have display 800*600, which can be changed after you install the VirtIO driver. After the first installation, you can go to device manager and find there are some unknown devices. You can choose update driver -> browse my compute -> choose VirtIO driver disk -> include subfolder to update the drivers. Normally there are four VirtIO devices (Ethernet, SCSI Controller, Balloon, and Serial).

  9. You can also iterate through the VirtIO driver disk folder by folder to intall the drivers. Remember to choose the w10(windows 10) folder, and choose the architecture according to your guest system. You navagate through the main driver folder, then w10, and then find the file with the type “Setup Information” - it should be a file with a gear icon. Right click on this and then click “Install”. An installer window will pop up and you just click through it. Some recommended ones are:

    • guest-agent: the QUME guest agent, to resize the guest screen
    • virtio-win-guest-tools: VirtIO windows guest tools
    • virtio-win-gt: a driver installation wizard
  10. (Optional) Desktop integration.

    With the VM open, open the menubar on the host and go to View -> Scale Display -> and check the box “Auto resize VW with window”. You will now be able to resize the VM window to any size and the Windows Desktop will automatically fit the window. This really helps to make Windows 10 feel like an application.

    You can also create the file ~/.local/share/applications/windows.desktop with the following content:

         [Desktop Entry]
         Version=1.0
         Name=Windows 10
         Comment=Starts the Windows 10 VM
         Exec=bash -c 'virsh start Windows10 && virt-viewer --wait -c qemu:///system Windows10 && virsh shutdown Windows10'
         Icon=windows
         Type=Application

    In the Exec section, replace Windows10 with the name of your VM in virt-manager.

    After logging out and back in, you will now have Windows 10 as an “application” that you can run from your launcher (Unity or Gnome Shell or whatever it is). If you shutdown the VM, the window will automatically close, and if you close the window without shutting down the VM, the Windows VM will safely shutdown in the background. This saves you from having to go into virt-manager to start your VM.

  11. (Optional) Performance tuing:

    1. Disable Fast Startup

    2. Disable Hiberfil.sys:

      1. Open a Windows command prompt as an administrator and enter this command:

             powercfg -h off
      2. Reboot your VM and the hiberfil.sys file should no longer remain (this step may not be necessary for certain versions of Windows).

    3. Disable Windows Indexing:

      1. Open a Run window(win + R) and type services.msc inside, then press Enter.
      2. Right-click the Windows Search service from the next window and then click Stop.
      3. Double-click the Windows Search item from the list and in the next window, change the Startup type to Disabled.
    4. Disable Automatic Disk Defragmenting:

      1. Use Windows Explorer to browse to where you can see the C: drive, then right-click on the device and select Properties.
      2. Click on the Tools tab at the top, then click Optimize.
      3. Click on the Change settings button.
      4. UNCHECK Run on a schedule from the next window.
    5. Enable High Performance Power Mode

    6. CPU topology finetune: On the host system, you can use lscpu to check the details of your CPU. On my i7-8565U laptop, it outputs

       lscpu -ae
       # below are the output
       #CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE    MAXMHZ   MINMHZ
       #  0    0      0    0 0:0:0:0          yes 4600.0000 400.0000
       #  1    0      0    1 1:1:1:0          yes 4600.0000 400.0000
       #  2    0      0    2 2:2:2:0          yes 4600.0000 400.0000
       #  3    0      0    3 3:3:3:0          yes 4600.0000 400.0000
       #  4    0      0    0 0:0:0:0          yes 4600.0000 400.0000
       #  5    0      0    1 1:1:1:0          yes 4600.0000 400.0000
       #  6    0      0    2 2:2:2:0          yes 4600.0000 400.0000
       #  7    0      0    3 3:3:3:0          yes 4600.0000 400.0000

      Pay attention to CPU, NODE, SOCKET and CORE columns. One can see the CPU0 and CPU4 in my machine comes from the same physical CORE. Naturally, it’s better to assign cpu from the same cores to the guest system. Especially for AMD Ryzen CPUs, it’s better the assign cores from the same CCX to the guest system.
      After the <vcpu></vpu> section in the XML you can manually add a <cputune></cputune> section which looks like

       <vcpu placement="static">6</vcpu>
       <cputune>
           <vcpupin vcpu='0' cpuset='1'/>
           <vcpupin vcpu='1' cpuset='2'/>
           <vcpupin vcpu='2' cpuset='3'/>
           <vcpupin vcpu='3' cpuset='5'/>
           <vcpupin vcpu='4' cpuset='6'/>
           <vcpupin vcpu='5' cpuset='7'/>
       </cputune>

      Here vcpu means virtual CPU and cpuset represents where you want to set it to the host CPU. One can see I’m reserving physical CORE 0 for the host machine.

    7. iothread: to be added. One can check Arch wiki about OVMF performance tuning and A useful blog post

    8. CPU model information: by default, virt-manager uses predefined host-model information for the guest system. At the <cpu> section of the XML, it may look like

            <cpu mode="host-model" check="none">
                <topology sockets="1" cores="3" threads="2"/>
            </cpu>

      For QEMU 3.1 and above, one can use the mode host-passthrough instead of the host-model.

    9. BSOD for Windows 10 later than 1803 – “System Thread exception not handled”:
      Add the ignore_msrs=1 to either kernel paramter of modprobe. Therefore, it’s either

           kvm.ignore_msrs=1

      in GRUB_CMDLINE_LINUX_DEFAULT of file /etc/default/grub. or

           options kvm ignore_msrs=1

      in a kvm.conf file located under /etc/modprobe.d/. More details of this type of setting can be found in [this blog post about device passthrough](/post/device-passthrough-in-kvm/).

  12. Enable Hibernation. It’s possible in the windows guest VM there aren’t any hibernation nor fast startup option in the power setting menu. If you run powercfg /a in an administrative command line, it will prompt to you that these different power states are not available. If you want to enable them,

    1. Edit or add the following settings in to your VM’s XML, at the <pm> </pm> section

           <suspend-to-disk enabled='yes'/>
           <suspend-to-mem enabled='yes'/>
    2. For hibernate from host, you shoudl install the qemu guest agent in Windows guest like mentioned before.

    3. For hibernate from host, you need to add a qemu-ga “channel” to your VM like mentioned before.

    4. Enable hibernate in your windows guest VM by

           powercfg.exe /hibernate on

      This should be run in a command line with administrative privillege.

    You can send hibernate through host using virsh

          virsh dompmsuspend disk <vm name>

Passthrough

In my personal use case, there are mainly two types of device passthrough

  1. USB device passthrough/redirection
  2. PCIE device passthrough

For USB device, you can use the host device redirection to add the host USB device to your VM. But if you want something like USB hot-plug in your VM, then you have to passthrough a USB controller to your VM. We will talk about more details in [a different guide](/post/device-passthrough-in-kvm/).

Chao Cheng
Chao Cheng
Statistician

My research interests include applied statistics and machine learning.

Related