Windows 10 as Virtual Machine Guest not Host

The Problem

Most companies I’ve worked for in the last decade end up giving me a laptop with Windows on it. This is great for productivity software (Email, Word Processing, etc.) but it’s really horrible for anyone used to Linux and Open Source tooling to do their jobs.

In today’s market, Docker, Kubernetes and containerisation is big business and having the tools to work with that more freely is just more efficient in day-to-day workflows. After wasting so much time with this I decided to put together a solution and blog about it.

The solution

I want to install PopOS! as my host environment. I’m going to leave the original disk intact with Windows on it and use a boot disk/drive to supplant this and then use KVM (Kernel Virtual Machine) pass through to run Windows when I need to (for any Windows only supported tasks).

Step By Step Guide

Installing Host Environment

Create Boot Disk

  • Download your Linux OS of choice. I’m using PopOS!
  • Once the ISO has been download, write it to a USB drive (this is easier from another machine if you can). I used Balena Etcher to do this.

Boot from LiveCD of PopOS!

Boot from the newly created USB drive on the machine with Windows on it.

IMPORTANT:
If this is not possible, you will need BIOS access to change the boot order or boot configuration.

Once the LiveCD has booted, insert a memory stick or preferably a USB housing / M.2 drive for use as the new storage device which will run Linux. For this I’ve used a 1TB M.2 over USB-C. The housing I used is here is a Plugable USB C to M.2 NVMe Tool-free Enclosure.

Installing PopOS!

Install PopOS! as usual ensuring that the existing storage device on the machine is untouched and the new USB drive (the 1TB drive in my case) is what is installed to.

Remove the LiveCD for PopOS! at the time it reboots.

The new distro should come up. To get back to Windows at any point, shutdown PopOS! and unplug the USB drive before booting the machine up.

KVM Setup

Hardware Requirements

The first thing we need to do is to make sure virtualisation is available and enabled in the BIOS. Often this is turned off by default. Without this, nothing further is possible.

Depending on if you’re doing this on an Intel or AMD chipset, the jargon and instructions vary slightly.

Status of Virtualisation Directed IO (IOMMU)

IMPORTANT:
If the output is not displayed, it’s not enabled and the boot options need updating.
If the boot options are already in place then your hardware does not support this feature!

To check if IOMMU is supported, you can run the following commands and see the output below.

# For AMD
$ sudo dmesg | grep AMD-Vi
...
[    0.428867] AMD-Vi: Enabling IOMMU at 0000:00:00.2 cap 0x40
[    0.428867] AMD-Vi: Lazy IO/TLB flushing enabled
[    0.428867] AMD-Vi: Initialized for Passthrough Mode

# For Intel
$ sudo dmesg | grep "Virtualization Technology for Directed I/O"
[    0.428867] DMAR: Intel(R) Virtualization Technology for Directed I/O

Enabling Virtualisation Directed IO (IOMMU)

The boot options need to include an iommu option to turn this feature on. For PopOS! systemd-boot is used to manage this (not GRUB). The default config should look like this:

$ sudo vi /boot/efi/loader/entries/Pop_OS-current.conf
...
title Pop!_OS
linux /EFI/Pop_OS-c0a37251-a457-4766-8be5-e8ed0b04d506/vmlinuz.efi
initrd /EFI/Pop_OS-c0a37251-a457-4766-8be5-e8ed0b04d506/initrd.img
options root=UUID=c0a37251-a457-4766-8be5-e8ed0b04d506 ro quiet loglevel=0 systemd.show_status=false splash

While editing this, add to the iommu setting end of the options line.

AMD

amd_iommu=on

Intel

intel_iommu=on

Now reboot the machine.

Installing QEMU / KVM

First install the core tools to manage virtual machines:

$ sudo apt install qemu-kvm bridge-utils

Next, install virt-manager, a GUI for managing virtual machines:

$ sudo apt install virt-manager

To allow the current $USER to manage virtual machines without requiring sudo virt-manager and so on, we need to add the current $USER to to the kvm and libvirt groups. We can also check the service status:

$ sudo usermod $(id -un) -a -G kvm,libvirt
$ sudo systemctl status libvirtd

Configuring QEMU / KVM

Start virt-manager if not already started. If this does not work without using sudo, you will need to re-login or start a new bash shell for the usermod changes to be effective.

$ virt-manager

Right click on the QEMU/KVM and select New. This will present a window. Select Manual Install:

Select the operating system type as Microsoft Windows 10 (win10):

Set the resources you want to give the VM.

Uncheck the Enable storage for this virtual machine option, we’re going to pass-through the disk used on the machine with Windows already installed on it.

On the final stage, check the Customize configuration before install option and click Next.

Set the Firmware to be UEFI.

Click Apply.

Pass-through the disk for Windows by clicking on Add Hardware, then in the dialog that pops up, click on the PCI Host Device and select the physical disk that you want Windows to boot with. In my case, I’m using an Kingston M.2 SSD – not to be confused with the M.2 drive we installed PopOS! onto. Click Finish when done.

Now the VM can be started and used as normal.