Home > Linux, Server stuff > How to boot Windows partition virtually under KVM with UEFI firmware

How to boot Windows partition virtually under KVM with UEFI firmware

It is actually quite easy to boot Windows virtualized using KVM. But to properly use the UEFI bootloader, suitable QEMU arguments are required. Here is a lightly commented QEMU command I use to boot virtual Windows 10 I have on a separate partition.

sudo qemu-system-x86_64 --enable-kvm -cpu host -m 2048 \
-smp 4,sockets=1,cores=2,threads=2 -mem-path /dev/hugepages \
-vga qxl -display none -serial mon:stdio \
-rtc clock=host,base=localtime \
-device qemu-xhci,id=xhci \
-device virtio-tablet,wheel-axis=true \
-soundhw ac97 \
-netdev user,id=vmnic,smb=/ \
-device virtio-net,netdev=vmnic \
-drive file=/usr/share/ovmf/x64/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
-drive file=$HOME/.config/qemu-windows.nvram,if=pflash,format=raw,unit=1 \
-drive file=/dev/sdb,index=0,media=disk,driver=raw \
-cdrom /opt/UefiShell.iso

For now I use sudo, because QEMU needs to access raw partitions from /dev/sdb. The other, maybe better way would be assigning a group to /dev/sdb, setting up proper group permissions and adding me to that group.

-m 2048 -smp 4,sockets=1,cores=2,threads=2 says to allocate 2GB of RAM for the guest and use CPU threads (1 CPU socket, with 2 cores, each core having 2 threads).

-mem-path /dev/hugepages is better described in Arch wiki.

-display sdl -vga qxl Use SDL for rendering and window management in the host and QXL GPU device in the guest (there are QXL drivers for Windows).

-device qemu-xhci,id=xhci Enable USB3 support by emulating an XHCI controller

-device virtio-tablet,wheel-axis=true Emulate a tablet pointing device with mouse scroll support

-soundhw ac97 Emulate ac97. You can then use Realtek driver. It worked better in QEMU than Intel hda for me.

netdev stuff Is for setting up network interface

-drive file=/usr/share/ovmf/x64/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on This is a very important part. It loads OVMF UEFI firmware read-only as the first Flash device. This firmware implements a UEFI bios and allows running UEFI Shell or booting .efi bootloader for Windows (bootmgfw.efi). This OVMF can be downloaded directly from the OVMF project repo or if you are using Arch Linux, just install ovmf package.

-drive file=$HOME/.config/qemu-windows.nvram,if=pflash,format=raw,unit=1 this loads a read-write NVRam flash image as the second virtual flash chip. OVMF firmware uses this to store UEFI variables, .efi boot order, etc. The default image can be copied from the OVMF setup (at /usr/share/ovmf/x64/OVMF_VARS.fd in ovmf Arch linux package). It must be a writable copy.

-drive file=/dev/sdb,index=0,media=disk,driver=raw Attaches my raw sdb block device to the virtual machine. That is used as a HDD for the guest, it has Windows pre-installed there together with EFI partition.

-cdrom /opt/UefiShell.iso UEFI shell iso as a CDROM. Before OVMF nvram is properly configured to boot Windows by default, this will result in booting into the EFI shell which allows to run .efi executables manually. Windows can be run by just navigating into the EFI partition and running the Windows efi loader – blkX:\EFI\Microsoft\Boot\bootmgfw.efi.

I don’t know how to force Windows to write UEFI boot order. There doesn’t seem to be a tool like efibootmgr on Windows. It would set the UEFI boot order up randomly during Windows Updates (mostly when you don’t want it to touch your EFI setup). If TianoCore fails to find your Windows installation, you can try pressing ESC during TianoCore EFI boot to get to boot menu. Or you can always boot Linux using the -cdrom command and use efibootmgr to force the OVMF to boot the Windows loader entry for this virtual machine by default. Usage of the efibootmgr command is out of scope of this article and can be found in many online resources elsewhere.

You can even use SPICE to connect to the booted VM remotely. To do that, add these options:

-spice port=5900,addr=127.0.0.1,disable-ticketing -device virtserialport,chardev=spicechannel0,name=com.redhat.spice.0 -chardev spicevmc,id=spicechannel0,name=vdagent \ -chardev spicevmc,name=usbredir,id=usbredirchardev1 -device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \ -chardev spicevmc,name=usbredir,id=usbredirchardev2 -device usb-redir,chardev=usbredirchardev2,id=usbredirdev2 \ -chardev spicevmc,name=usbredir,id=usbredirchardev3 -device usb-redir,chardev=usbredirchardev3,id=usbredirdev3 \

It says to listen on port 5900 (localhost-only), adds SPICE channel between host and guest (to allow remote copy-paste) and 4 remotelly-attachable USB devices.

You can then use SPICE client like remote-viewer to connect to the VM. If the original local VM graphical output is not needed, add -display none parameter.

Have fun with virtualized Windows and remember – Windows is good for games only and for stuff like government PDFs which use proprietary Adobe XFA forms and are therefore supported in official Adobe Reader which has the best support in this platform only. Windows definitely shouldn’t be used on servers or anything serious! By default it is very limited (maximum number or RAM, maximum number of CPU cores, maximum number of listening socket connections, etc) until you pay huge amounts of money to Microsoft. Wise people use Linux and lazy people who don’t care about privacy or freedom use Mac OS X.

Categories: Linux, Server stuff Tags:
Subscribe
Notify of
guest

17 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
defb

I’m attempting to run this with debian testing (at the moment deb10), but unfortunately, the ovmf package in the deb repos don’t have /usr/share/ovmf/x64/OVMF_CODE.fd. Also, by OVMF_CODE.fd, do you mean copy it over to .config and renaming it qemu-windows.nvram? Other than that, I’m impressed at how you can virtualize a physical install of windows when virtual box has trouble doing it.

Björn Carlsson

Where did you find UefiShell.iso

Ivan Avery Frey

Thank you for these instructions. My Linux install is on the same disk as my Windows install. Is there a way to boot Windows virtually when Linux and Windows are on the same physical device?

rp

Thank you very much for these instructions. I was able to boot up my windows partition. However I only get a 800×600 resolution. I suspect it must be something to do with the fact that I don’t have virtio drivers installed in my windows guest. I am not clear how to go about doing this and more specifically what drivers to install from the fedora repository. Could you please give some additional details on virtio driver installation in the windows guest?

Jez

Thanks for this. Saved me a ton of time. Used it to boot a copy of the Win10-Edge MS developer ova after converting it to qemu.

If you do have to do any boot diagnostics, then the refind cdrom iso https://sourceforge.net/projects/refind/ can be used as a ready replacement in place of the EFI Shell iso.

Muhammed Unais P

@rp

any update on resolution ?

Necktwi

I’m using Gentoo, I did mount -t hugetlbfs hugetlbfs /dev/hugepages/ and then executed

$ sudo qemu-system-x86_64 –enable-kvm -cpu host -m 2048 -smp 3 -mem-path /dev/hugepages -device qemu-xhci,id=xhci -device virtio-tablet,wheel-axis=true -soundhw hda -netdev user,id=vmnic,smb=/temp -device virtio-net,netdev=vmnic -drive file=/usr/share/edk2-ovmf/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on -drive file=$HOME/.config/qemu-windows.nvram,if=pflash,format=raw,unit=1 -drive file=/dev/sda,index=0,media=disk,driver=raw -cdrom /usr/share/edk2-ovmf/UefiShell.iso

qemu-system-x86_64: unable to map backing store for guest RAM: Cannot allocate memory
qemu-system-x86_64: falling back to regular RAM allocation.
audio: Failed to create voice `adc’

and the window displays guest has not initiated the display (yet).

Ben

Thanks for this article, had to tweak a bit but this helped point me in the right direction. Was considering whether I wanted to dual boot or simply run Windows in a VM and this gives me the flexibility to do both. For those curious, here is my modification that got it working while testing if possible from a Kubuntu 20.04 live disk (where bios.bin is OVMF.fd, reference flags in this readme https://github.com/tianocore/edk2/blob/master/OvmfPkg/README )

sudo qemu-system-x86_64 –enable-kvm -cpu host -m 4096 \
-smp 4,sockets=1,cores=2,threads=2 -mem-path /dev/hugepages \
-vga qxl -serial mon:stdio \
-rtc clock=host,base=localtime \
-device virtio-tablet,wheel-axis=true \
-drive file=/usr/share/OVMF/OVMF_CODE.fd,if=pflash,format=raw,unit=0,readonly=on \
-pflash /home/kubuntu/vm/bios.bin
-drive file=/dev/nvme0n1,index=0,media=disk,driver=raw

chmedly

Any way to set this up from the GUI (Virtual Machine Manager)? As much as I love really long terminal commands, it seems like this would be a bit easier in a Desktop style of operation. Especially when I only need to boot windows every few months…

17
0
Would love your thoughts, please comment.x
()
x
deadly laser