[tutorial] The Ultimate Linux Laptop for PC Gamers — feat. KVM and VFIO
Demo and Video Tutorial
Overview
This laptop has the ability to play modern AAA games with reasonably demanding graphics and stable performance but it also solves the biggest problem facing a Linux enthusiast and PC gamer.
Switching back and forth between Linux and Windows
Phase 1 — Laptop Purchase and Initial Testing
The Purchase
ASUS TUF Gaming F15 FX507ZE-RS73 15.6" Laptop Computer
Reasons
- Integrated GPU: CPU has “Intel® Iris® Xe Graphics” shown here
- Dedicated GPU: NVIDIA GeForce RTX 3050 Ti
- GPU MUX Switch: Shown on ASUS Page
- CPU Supports IOMMU: VT-D=YES shown here
- Motherboard supports IOMMU and has good group isolation: IOMMU Group 15 only includes the two devices for the GPU, shown here
Initial Testing
Press Power Button
Answer a few questions
Plug in ethernet cable with network access
Unplug ethernet cable when it asks for a Microsoft account
Process without network connection and create a local login
Let the installer finish
Uninstall McAfee programs
Install OBS for Windows using instructions here (download link)
Install Steam for Windows from here (download link)
Download a game and play it
Phase 2 Installing Linux and GPU Drivers
Shrink windows partition by 300GB (307200MB)
Download Fedora Media Writer from here (download link) to create a Linux live USB install disk with Fedora 37
Insert USB Drive
Create Fedora installation media
Reboot
Press F2 while the computer starts to launch UEFI/BIOS
Disable Fastboot
Save and edit
Press F2 while the computer starts to launch UEFI/BIOS
Select Boot Menu
Boot from the newly created Linux live USB
Test the media
Start the installer
Create Linux partitions in the empty space
Verify that the installer is not deleting any partitions
Run through the rest of the installer
Once it boots into fedora, click through any menus
With internet connected, update all software
sudo dnf update
Reboot
Install nvidia drivers from rpmfusion instructions here
sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
sudo dnf install akmod-nvidia
sudo dnf install xorg-x11-drv-nvidia-cuda
Use the following command to see if the drivers are done building
modinfo -F version nvidia
Reboot -> F2 to get to UEFI/BIOS -> disable SecureBoot
Install OBS from rpmfusion from instructions here
sudo dnf install obs-studio
Install steam which is also available via the non-free rpmfusion repos we enabled above (or follow the instructions here)
sudo dnf install steam
Download and play a game using GPU
Phase 3: Getting Ready for Gaming VMs
Install virtualization software
sudo dnf groupinstall --with-optional virtualization
Install KDE Plasma Workspaces
sudo dnf groupinstall "KDE Plasma Workspaces"
Install gedit
sudo dnf install gedit
Run this command to view GPU PCI IDs
lspci -nnk
Run this command to open the grub configuration
sudo gedit /etc/sysconfig/grub
Add this stuff to the GRUB_CMDLINE_LINUX arguments
intel_iommu=on iommu=pt rd.driver.pre=vfio-pci rd.driver.blacklist=nouveau modprobe.blacklist=nouveau nvidia-drm.modeset=1 vfio-pci.ids=10de:25a0,10de:2291 module_blacklist=nouveau
So the file looks like this
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="rd.driver.blacklist=nouveau modprobe.blacklist=nouveau nvidia-drm.modeset=1 rhgb quiet intel_iommu=on iommu=pt rd.driver.pre=vfio-pci rd.driver.blacklist=nouveau modprobe.blacklist=nouveau nvidia-drm.modeset=1 vfio-pci.ids=10de:25a0,10de:2291 module_blacklist=nouveau"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
Regenerate grub configuration
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
Create a new file with gedit
sudo gedit /etc/dracut.conf.d/local.conf
Add the following content to this new file
add_drivers+=" vfio vfio_iommu_type1 vfio_pci vfio_virqfd "
Regenerate initramfs with dracut
sudo dracut -f --kver `uname -r`
Reboot -> F2 to get to UEFI/BIOS -> Enable anything that looks like it has to do with virtualization or VT-d if it isn’t already enabled
Next time you login select Plasma (Wayland) as the display environment using the settings icon in the bottom right of the screen before you enter your password
Right now the GPU is detached and ready to be used in a VM. We can see the “Kernel driver in use” is vfio-pci by running the following command
lspci -nnk
Lets practice reattaching it so we can play some games on Linux
sudo virsh nodedev-reattach pci_0000_01_00_0
sudo rmmod vfio_pci vfio_pci_core vfio_iommu_type1
sudo modprobe -i nvidia_modeset nvidia_uvm nvidia
Now lets disable it again so the GPU is ready to be used in a VM
sudo rmmod nvidia_modeset nvidia_uvm nvidia
sudo modprobe -i vfio_pci vfio_pci_core vfio_iommu_type1
sudo virsh nodedev-detach pci_0000_01_00_0
These are things we want to do repeatedly so lets add them to our .bashrc file
Run this command
gedit ~/.bashrc
Add these things to the end of the file
alias hows-my-gpu='echo "NVIDIA Dedicated Graphics" | grep "NVIDIA" && lspci -nnk | grep "NVIDIA Corporation GA107M" -A 2 | grep "Kernel driver in use" && echo "Intel Integrated Graphics" | grep "Intel" && lspci -nnk | grep "Intel.*Integrated Graphics Controller" -A 3 | grep "Kernel driver in use" && echo "Enable and disable the dedicated NVIDIA GPU with nvidia-enable and nvidia-disable"'
alias nvidia-enable='sudo virsh nodedev-reattach pci_0000_01_00_0 && echo "GPU reattached (now host ready)" && sudo rmmod vfio_pci vfio_pci_core vfio_iommu_type1 && echo "VFIO drivers removed" && sudo modprobe -i nvidia_modeset nvidia_uvm nvidia && echo "NVIDIA drivers added" && echo "COMPLETED!"'
alias nvidia-disable='sudo rmmod nvidia_modeset nvidia_uvm nvidia && echo "NVIDIA drivers removed" && sudo modprobe -i vfio_pci vfio_pci_core vfio_iommu_type1 && echo "VFIO drivers added" && sudo virsh nodedev-detach pci_0000_01_00_0 && echo "GPU detached (now vfio ready)" && echo "COMPLETED!"'
So it should now look like this
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
if [ -d ~/.bashrc.d ]; then
for rc in ~/.bashrc.d/*; do
if [ -f "$rc" ]; then
. "$rc"
fi
done
fi
unset rc
alias hows-my-gpu='echo "NVIDIA Dedicated Graphics" | grep "NVIDIA" && lspci -nnk | grep "NVIDIA Corporation GA107M" -A 2 | grep "Kernel driver in use" && echo "Intel Integrated Graphics" | grep "Intel" && lspci -nnk | grep "Intel.*Integrated Graphics Controller" -A 3 | grep "Kernel driver in use" && echo "Enable and disable the dedicated NVIDIA GPU with nvidia-enable and nvidia-disable"'
alias nvidia-enable='sudo virsh nodedev-reattach pci_0000_01_00_0 && echo "GPU reattached (now host ready)" && sudo rmmod vfio_pci vfio_pci_core vfio_iommu_type1 && echo "VFIO drivers removed" && sudo modprobe -i nvidia_modeset nvidia_uvm nvidia && echo "NVIDIA drivers added" && echo "COMPLETED!"'
alias nvidia-disable='sudo rmmod nvidia_modeset nvidia_uvm nvidia && echo "NVIDIA drivers removed" && sudo modprobe -i vfio_pci vfio_pci_core vfio_iommu_type1 && echo "VFIO drivers added" && sudo virsh nodedev-detach pci_0000_01_00_0 && echo "GPU detached (now vfio ready)" && echo "COMPLETED!"'
Open a new terminal and you can now use these commands
nvidia-enable
nvidia-disable
hows-my-gpu
Phase 4: Creating our first VM
Download Windows 10 iso from here
Download Windows 10 virtio driver is from here (download link)
Open virt-manager
Create a new VM
Select an amount of CPU and RAM
Create a new 100GB Virtual Disk
Give the VM a unique name
Check the box for advanced configuration
Ensure the VM is set for KVM, Q35, and UEFI
Set CPU Topology with one socket and multiple threads
Set the windows 10 install disk to bootable
Remove the network interface card (so it doesnt make you connect to a Microsoft account during the install)
Start the VM and run through the windows 10 installer
Press any key
Install Now
I dont have a product key
Windows 10 Home
Accept terms and conditions
Install to the newly created 100GB virtual drive
Its going to reboot
Answer some questions
Disable all this unnecessary stuff like usage metrics, location tracking, and the virtual assistant
Should take a few minutes and its done! We’ve got a windows 10 VM
Shutdown the VM
Make the main disk bootable
Remove the windows 10 install disk
Add the downloaded virtio driver disk
Create a new small virtual disk with virtio as the bus type
Boot the VM, find the driver disk and install the drivers
Open device manager and verify that the small virtio device is visbile under storage devices
Power down the VM
In Virtual Machine Manager: Click Edit > Preferences and check Enable XML Editing
For the main disk, we want to change from SATA type bus to virtio
In the config window for your VM, open the XML tab for the storage device and change the bus type from sata to “virtio” and the address to “pci”. When you click “Apply” it should look like this
<disk type="file" device="disk">
<driver name="qemu" type="qcow2"/>
<source file="/var/lib/libvirt/images/win10-vm1.qcow2"/>
<target dev="sda" bus="virtio"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x0e" function="0x0"/>
</disk>
Remove the virtio driver disk
Remove the small newly created virtio drive and delete associated file
Boot the VM again and everything should still work
Shutdown the VM
Add the network interface card
Add the PCI devices for the GPU
Plug in an external monitor
Start the VM
Navigate to the NVIDIA webpage and install nvidia drivers from here (download link)
Phase 5: Looking Glass and usability upgrades
Find out which devices are your mouse and keyboard
ls /dev/input/by-id/
ls /dev/input/by-path/
When I run this command and move my mouse around I get lots of info coming out so I know that’s the right device
sudo cat /dev/input/by-id/usb-PixArt_Lenovo_USB_Optical_Mouse-event-mouse
Press Ctrl-C to get out of that
When I run this command and touch things on the keyboard I get lots of info coming out so I know that’s the right device
sudo cat /dev/input/by-path/platform-i8042-serio-0-event-kbd
Press Ctrl-C to get out of that
Add the following XML to your VM config
<input type="evdev">
<source dev="/dev/input/by-id/usb-PixArt_Lenovo_USB_Optical_Mouse-event-mouse"/>
</input>
<input type="evdev">
<source dev="/dev/input/by-path/platform-i8042-serio-0-event-kbd" grab="all" grabToggle="ctrl-ctrl" repeat="on"/>
</input>
Remove the tablet input device because now you have a better one and you don’t want these confusing each other
Build Looking Glass from Source according to instructions here
Download the stable release source code for the Looking Glass Client from here (download link)
Unzip the looking glass source code
cd Downloads
tar -xzvf looking-glass-B6.tar.gz
cd looking-glass-B6
Install dependencies required to build/install Looking Glass (from the list here )
sudo dnf install cmake gcc gcc-c++ libglvnd-devel fontconfig-devel spice-protocol make nettle-devel \
pkgconf-pkg-config binutils-devel libXi-devel libXinerama-devel libXcursor-devel \
libXpresent-devel libxkbcommon-x11-devel wayland-devel wayland-protocols-devel \
libXScrnSaver-devel libXrandr-devel dejavu-sans-mono-fonts
sudo dnf install pipewire-devel libsamplerate-devel
sudo dnf install pulseaudio-libs-devel libsamplerate-devel
Build the Looking Glass Client
mkdir client/build
cd client/build
cmake ../
make
Install the Looking Glass Client
sudo make install
Now you can run the Looking Glass Client
looking-glass-client
Configure looking glass using the instructions here
Create a new file
sudo gedit /etc/tmpfiles.d/10-looking-glass.conf
Give it the following contents
# Type Path Mode UID GID Age Argument
f /dev/shm/looking-glass 0660 steeve qemu -
Run the following command
sudo semanage fcontext -a -t svirt_tmpfs_t /dev/shm/looking-glass
Reboot
Check that the file was created with the correct selinux context
ls -alZ /dev/shm/looking-glass
Add the following to your VM XML
<shmem name='looking-glass'>
<model type='ivshmem-plain'/>
<size unit='M'>32</size>
</shmem>
Start the VM
Download the Looking Glass Host application inside the VM from here (download link)
Install the looking glass host applicaiton
Run the looking glass host application (in the future it should run automatically on boot)
On the host connect ot the VM with the Looking Glass client
looking-glass-client -s
Set the default audio to spekers in the VM
Make sure the spice display is open but minimized
On the host connect ot the VM with the Looking Glass client but this time with hotkeys bound to right control
looking-glass-client -s -m 97
Save this as another alias command to ~/.bashrc
gedit ~/.bashrc
So now it looks like this
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# User specific environment
if ! [[ "$PATH" =~ "$HOME/.local/bin:$HOME/bin:" ]]
then
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
fi
export PATH
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
if [ -d ~/.bashrc.d ]; then
for rc in ~/.bashrc.d/*; do
if [ -f "$rc" ]; then
. "$rc"
fi
done
fi
unset rc
alias hows-my-gpu='echo "NVIDIA Dedicated Graphics" | grep "NVIDIA" && lspci -nnk | grep "NVIDIA Corporation GA107M" -A 2 | grep "Kernel driver in use" && echo "Intel Integrated Graphics" | grep "Intel" && lspci -nnk | grep "Intel.*Integrated Graphics Controller" -A 3 | grep "Kernel driver in use" && echo "Enable and disable the dedicated NVIDIA GPU with nvidia-enable and nvidia-disable"'
alias nvidia-enable='sudo virsh nodedev-reattach pci_0000_01_00_0 && echo "GPU reattached (now host ready)" && sudo rmmod vfio_pci vfio_pci_core vfio_iommu_type1 && echo "VFIO drivers removed" && sudo modprobe -i nvidia_modeset nvidia_uvm nvidia && echo "NVIDIA drivers added" && echo "COMPLETED!"'
alias nvidia-disable='sudo rmmod nvidia_modeset nvidia_uvm nvidia && echo "NVIDIA drivers removed" && sudo modprobe -i vfio_pci vfio_pci_core vfio_iommu_type1 && echo "VFIO drivers added" && sudo virsh nodedev-detach pci_0000_01_00_0 && echo "GPU detached (now vfio ready)" && echo "COMPLETED!"'
alias looking-glass='looking-glass-client -s -m 97'
Open a new terminal and launch looking glass using the new alias
looking-glass
For audio to work in the VM, set the output to Speakers and make sure you have the spice display open or minimized (there will be a small audio delay)
For the primary display to be looking-glass/dummy plug, set that to main display and move the spice display off to the right
Setup Windows auto login using instructions here
Open Registry Editor
Locate this path
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
Create new string entries for the following variables with the following values
AutoAdminLogon=1
DefaultUserName=steeve
DefaultPassword=password
Exit
Reboot (windows should auto login this time)
Notes on using your laptop
Press both Ctrl keys at the same time to switch your mouse and keyboard between guest and host
Make sure you have the spice window open and minimized (so you have audio come through). Note: the VM will need to be set to default speakers
Also, i like to turn off “dim the screen”, and “turn the screen off” in the power saving settings, so that way linkux doesnt put my display to sleep while i’m gaming in linux (because my inputs are going straight to the VM, linux might not know to stay awake) — i also turn off the “auto lock” after 5 minutes which is under the screenlock settings