Skip to content

Instantly share code, notes, and snippets.

@nop-90
Last active December 21, 2021 21:23
Show Gist options
  • Save nop-90/5b2d5a4a686cdc0586cb2854126a9ec8 to your computer and use it in GitHub Desktop.
Save nop-90/5b2d5a4a686cdc0586cb2854126a9ec8 to your computer and use it in GitHub Desktop.
Configuration for VFIO-enabled virtual machine with MSI GL62 (i5 + 650m)

Instructions for Nvidia VFIO usage with Windows 10 for MSI GL62 series with libvirt on ArchLinux

Main sources

GUIDE Optimus laptop dGPU passthrough

jscinoz repository for Optimus VFIO

Reddit comment of jscinoz

Goal

The goal of this guide is to configure the NVIDIA discrete card on my MSI GL62 to be used by my Windows 10 virtual machine to be able to have much larger GPU performance than QXL or Intel GVT-g virtual GPU. Most of the difference with the original guide of Misairu-G is that I use only libvirt, use ArchLinux and don't have the NVIDIA Linux driver bothering me. That allows me to use only bbswitch for GPU power management to avoid bumblebee and nvidia module conflicts and avoid Qemu complicated commandline launch.

Procedure

Prerequisites

  1. Select a folder where you're going to keep your VM files (named [folder] below)
  2. Download packages pacman -S ovmf iasl bbswitch
  3. Add necessary modules to your mkinitcpio.conf : MODULES="vfio vfio_iommu_type1 vfio_pci vfio_virqfd"
  4. Regenerate your initrd : mkinitcpio -p linux

Extract Nvidia VBIOS firmware from system UEFI

Download NVflash

Extract your VBIOS as root with nvflash_linux --save [folder]\video.rom (Probably can't put it on GitHub but I can send it to you if you need)

Copy OVMF efi vars

cp /usr/share/ovmf/x64/OVMF_VARS.fd [folder path]

Custom ACPI table for Qemu

Download ssdt1.asl wget https://raw.githubusercontent.com/jscinoz/optimus-vfio-docs/master/asl/ssdt1.asl

Compile the ACPI table for Qemu iasl ssdt1.asl

Copy the binary to your folder cp ssdt1.aml [folder]

Create hard drive for your VM and download the drivers for virtio devices

Create disk with at minimum 20G (you can resize it afterwards) qemu-img create -f raw Windows10VFIO.img 50G

Download Virtio Drivers ISO on Fedora's wiki

Change paths in libvirt config

Replace every folder path containing my custom path (/home/nop-90/Documents/images) with yours in win10-efi.xml

Located at :

  • line 20 : UEFI VARS
  • line 57 : Hard Drive location
  • line 64 : Virtio ISO on CD Drive
  • line 171 : location of Nvidia Firmware
  • line 187 : custom ACPI table compiled

Load libvirt XML to the libvirt server

Load win10-efi.xml virsh define win10-efi.xml

Preload nvidia on vfio

echo "10de 139b" | sudo tee /sys/bus/pci/drivers/vfio-pci/new_id

Then launch your VM and install Windows and the Virtio drivers to be able to see all your peripherals

Next...

Most of what you need to do after is written here on Misairu-G's guide.

Notes

  • Do not use acpi_call method to power off the NVIDIA GPU, it cannot power it on again without rebooting
  • Let Windows 10 install it's own NVIDIA drivers, they are old but I didn't succeed to install the latest driver even when modifying the INF file for MSI (nvmii.inf)
  • Cohabitation with the GVT modules loaded (kvmgt,vfio_mdev) seems to cause some problems when powering on the NVIDIA card with vfio_pci
  • My performance when playing a strategy game was 25 fps in average with a 1600x900 resolution. That is usable but not incredible comparing with the native performance. I'll update if I find a way to gain some FPS
<!--
WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
virsh edit win10-efi
or other application using the libvirt API.
-->
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
<name>win10-efi</name>
<uuid>51f873b7-317b-41f2-be59-839875c1414c</uuid>
<memory unit='KiB'>3145728</memory>
<currentMemory unit='KiB'>3145728</currentMemory>
<vcpu placement='static'>4</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-q35-2.10'>hvm</type>
<loader readonly='yes' type='pflash'>/usr/share/ovmf/x64/OVMF_CODE.fd</loader>
<nvram>/home/nop-90/Documents/images/WIN_VARS.fd</nvram>
</os>
<features>
<acpi/>
<apic/>
<hyperv>
<relaxed state='on'/>
<vapic state='on'/>
<spinlocks state='on' retries='8191'/>
<vendor_id state='on' value='jscinoz42137'/>
</hyperv>
<kvm>
<hidden state='on'/>
</kvm>
<vmport state='off'/>
<ioapic driver='qemu'/>
</features>
<cpu mode='host-passthrough' check='none'>
<topology sockets='1' cores='4' threads='1'/>
</cpu>
<clock offset='localtime'>
<timer name='rtc' tickpolicy='catchup'/>
<timer name='pit' tickpolicy='delay'/>
<timer name='hpet' present='no'/>
<timer name='hypervclock' present='yes'/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='yes'/>
</pm>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='raw' discard='unmap'/>
<source file='/var/lib/libvirt/images/Windows10VFIO.img'/>
<target dev='sda' bus='scsi'/>
<boot order='2'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<disk type='file' device='cdrom'>
<driver name='qemu' type='raw'/>
<source file='/home/nop-90/Documents/images/virtio-win-0.1.141.iso'/>
<target dev='sdb' bus='usb' removable='on'/>
<readonly/>
<shareable/>
<boot order='1'/>
<address type='usb' bus='0' port='2'/>
</disk>
<controller type='usb' index='0' model='nec-xhci'>
<address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
</controller>
<controller type='sata' index='0'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pcie-root'/>
<controller type='pci' index='1' model='pcie-root-port'>
<model name='ioh3420'/>
<target chassis='1' port='0x1'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
</controller>
<controller type='pci' index='2' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='2' port='0x9'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<controller type='pci' index='3' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='3' port='0xa'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='pci' index='4' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='4' port='0xb'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x3'/>
</controller>
<controller type='pci' index='5' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='5' port='0xc'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x4'/>
</controller>
<controller type='pci' index='6' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='6' port='0xd'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x5'/>
</controller>
<controller type='pci' index='7' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='7' port='0xe'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x6'/>
</controller>
<controller type='pci' index='8' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='8' port='0xf'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x7'/>
</controller>
<controller type='pci' index='9' model='pcie-root-port'>
<model name='pcie-root-port'/>
<target chassis='9' port='0x10'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</controller>
<controller type='virtio-serial' index='0'>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</controller>
<controller type='scsi' index='0' model='virtio-scsi'>
<address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
</controller>
<interface type='network'>
<mac address='52:54:00:50:ab:ba'/>
<source network='default'/>
<model type='virtio'/>
<address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
</interface>
<channel type='spicevmc'>
<target type='virtio' name='com.redhat.spice.0'/>
<address type='virtio-serial' controller='0' bus='0' port='1'/>
</channel>
<channel type='unix'>
<target type='virtio' name='org.qemu.guest_agent.0'/>
<address type='virtio-serial' controller='0' bus='0' port='2'/>
</channel>
<channel type='spiceport'>
<source channel='org.spice-space.webdav.0'/>
<target type='virtio' name='org.spice-space.webdav.0'/>
<address type='virtio-serial' controller='0' bus='0' port='4'/>
</channel>
<input type='keyboard' bus='virtio'>
<address type='pci' domain='0x0000' bus='0x07' slot='0x00' function='0x0'/>
</input>
<input type='tablet' bus='virtio'>
<address type='pci' domain='0x0000' bus='0x09' slot='0x00' function='0x0'/>
</input>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='spice' autoport='yes'>
<listen type='address'/>
<gl enable='no'/>
</graphics>
<sound model='ich9'>
<address type='pci' domain='0x0000' bus='0x00' slot='0x1b' function='0x0'/>
</sound>
<video>
<model type='qxl' ram='65536' vram='65536' vgamem='16384' heads='1' primary='yes'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</video>
<hostdev mode='subsystem' type='pci' managed='yes'>
<source>
<address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
</source>
<rom bar='off' file='/home/nop-90/Documents/images/video.rom'/>
<address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0' multifunction='on'/>
</hostdev>
<hub type='usb'>
<address type='usb' bus='0' port='1'/>
</hub>
<memballoon model='virtio'>
<address type='pci' domain='0x0000' bus='0x06' slot='0x00' function='0x0'/>
</memballoon>
</devices>
<qemu:commandline>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-pci-sub-vendor-id=4318'/>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-pci-sub-device-id=4971'/>
<qemu:arg value='-acpitable'/>
<qemu:arg value='file=/home/nop-90/vfio/ssdt1.aml'/>
<qemu:arg value='-debugcon'/>
<qemu:arg value='file:/tmp/ovmf-debug.log'/>
</qemu:commandline>
</domain>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment