Hi guys,
I have been tinkering with setting up a virtual machine to run SteamOs.
At some point I might do a full write up about it. I am still fighting some issues. But I am getting close to being finished!
So this is me just writing done what I have done in the hope it might helps someone. (And to here some suggestions on how to improve the setup).
My Hardware:
Motherboard: Aorus Master x670e
CPU: AMD Ryzen 9 7950X
Memory: 64G running in XMP and 5200MHz
GPU: Radeon RX 6700 XT
Storage: 1TB NVME Drive + 2x 10TB Hard Drives in RAID-Z1 additionally I have a SATA SSD as a read cache (zfs )
Additionally I have added a Mellanox Fibre Card and 4 Port USB Card into the system. More PCI device sadly are not possible since I only have 3 slots available. I probably could use a break out board to convert an NVME slot into a PCI slot, but it has not been required so far.
The Idea for me is that since my living room also is my homeoffice I could game from my PC on the TV. I did not just want to attach the TV as another monitor, because moving windows between them would be a hassle and I do not want it to interfere with my work environment. A virtual machine seemed like the best approach to this and given that my CPU has integrated graphics it is not an issue to passthrough my main GPU. The integrated graphics are more than enough for my work requirements. So with this configuration I do not need to have another graphics card
As a Host OS I am running Archlinux using the linux-zen
kernel. This is not just because of performance reasons but because I also required the acs overwride patch because the default IOMMU groups are unlucky for my setup. At the time of writing I am on kernel version 6.4
. There are some issues with the intgrated graphis amdgpu driver. In order for it to work without a flickeriung display I had to add the amdgpu.sg_display=0
kernel parameter. This is a temporary fix, I will see how long I will need to have it applied.
So my virtual machine actually is getting 4 devices via passthrough.
- Main GPU
- Main GPU HDMI Audio Device
- 4 Port USB Card
- Wired Ethernet adapter (the mellanox card is from my normal work environment)
For storage I am using virtiofs and giving the virtual machine access to the partitions I have for games.
- One for older games that do not need fast storage running on my spinning rust raid
- One for games that need fast storage on my nvme ssd.
Initially I tried running HoloIso
which is a steamdeck sort of installer. But I realized that this is suboptimal since the steamdeck has build in assumptions about the screen resolution and gpu capabilities that just limit the performance of this setup. So for the gaming OS I am now running manjaro kde and have steam set to autostart with the options -steamos -gamepadui
. This creates the same experience as you would get on the deck.
It would still be great to be able to game on my computer if I want to. Sadly I am running into issues getting LookingGlass
working. The problem for me here is that once I add the ivshmem-plain
for usage with the kvmfr
kernel module the virtual machine does boot. But my storage just hangs. So my games are inaccessible and steam is not starting. I am kind of stuck trying to figure out what is going on. At least in lspci
everythings seems fine and I can see the the shared memory there. But I have found zero information on how to mount that storage or how to use it with the looking-glass-host
. Now I know that running the looking-glass-host
on linux is not a priority for the developers. But since I am on myself I am happy to test and even patch things if required. Any tips or guidance on how to get this “working” would be greatly appreachated!
For completeness I am adding my libvird configuration here:
domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0" type="kvm">
<name>gaming</name>
<uuid>49cdb117-0c87-4198-80c8-a87f2c3cd58d</uuid>
<metadata>
<libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
<libosinfo:os id="http://archlinux.org/archlinux/rolling"/>
</libosinfo:libosinfo>
</metadata>
<memory unit="KiB">16777216</memory>
<currentMemory unit="KiB">16777216</currentMemory>
<memoryBacking>
<hugepages/>
<source type="memfd"/>
<access mode="shared"/>
</memoryBacking>
<vcpu placement="static">8</vcpu>
<cputune>
<vcpupin vcpu="0" cpuset="12"/>
<vcpupin vcpu="1" cpuset="28"/>
<vcpupin vcpu="2" cpuset="13"/>
<vcpupin vcpu="3" cpuset="29"/>
<vcpupin vcpu="4" cpuset="14"/>
<vcpupin vcpu="5" cpuset="30"/>
<vcpupin vcpu="6" cpuset="15"/>
<vcpupin vcpu="7" cpuset="31"/>
</cputune>
<numatune>
<memory mode="preferred" nodeset="0"/>
</numatune>
<os firmware="efi">
<type arch="x86_64" machine="pc-q35-7.2">hvm</type>
<firmware>
<feature enabled="no" name="enrolled-keys"/>
<feature enabled="yes" name="secure-boot"/>
</firmware>
<loader readonly="yes" secure="yes" type="pflash">/usr/share/edk2/x64/OVMF_CODE.secboot.4m.fd</loader>
<nvram template="/usr/share/edk2/x64/OVMF_VARS.4m.fd">/var/lib/libvirt/qemu/nvram/gaming_VARS.fd</nvram>
<bootmenu enable="yes"/>
</os>
<features>
<acpi/>
<apic/>
<vmport state="off"/>
<smm state="on"/>
</features>
<cpu mode="host-passthrough" check="full" migratable="off">
<topology sockets="1" dies="1" cores="4" threads="2"/>
<feature policy="require" name="topoext"/>
</cpu>
<clock offset="localtime">
<timer name="rtc" tickpolicy="catchup"/>
<timer name="pit" tickpolicy="delay"/>
<timer name="hpet" 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="no"/>
</pm>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type="file" device="disk">
<driver name="qemu" type="raw"/>
<source file="/var/virtual_machines/gaming-default.img"/>
<target dev="vdb" bus="virtio"/>
<boot order="1"/>
<address type="pci" domain="0x0000" bus="0x01" slot="0x00" function="0x0"/>
</disk>
<controller type="usb" index="0" model="qemu-xhci">
<address type="pci" domain="0x0000" bus="0x02" 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="pcie-root-port"/>
<target chassis="1" port="0x8"/>
<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" multifunction="on"/>
</controller>
<controller type="pci" index="10" model="pcie-to-pci-bridge">
<model name="pcie-pci-bridge"/>
<address type="pci" domain="0x0000" bus="0x09" slot="0x00" function="0x0"/>
</controller>
<controller type="pci" index="11" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="11" port="0x11"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x1"/>
</controller>
<controller type="pci" index="12" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="12" port="0x12"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x2"/>
</controller>
<controller type="pci" index="13" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="13" port="0x13"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x3"/>
</controller>
<controller type="pci" index="14" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="14" port="0x14"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x4"/>
</controller>
<controller type="pci" index="15" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="15" port="0x15"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x5"/>
</controller>
<controller type="pci" index="16" model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="16" port="0x16"/>
<address type="pci" domain="0x0000" bus="0x00" slot="0x02" function="0x6"/>
</controller>
<controller type="scsi" index="0" model="virtio-scsi">
<address type="pci" domain="0x0000" bus="0x04" slot="0x00" function="0x0"/>
</controller>
<filesystem type="mount" accessmode="passthrough">
<driver type="virtiofs"/>
<source dir="/var/games-fast"/>
<target dir="/var/games-fast"/>
<address type="pci" domain="0x0000" bus="0x0e" slot="0x00" function="0x0"/>
</filesystem>
<filesystem type="mount" accessmode="passthrough">
<driver type="virtiofs"/>
<source dir="/var/games"/>
<target dir="/var/games"/>
<address type="pci" domain="0x0000" bus="0x0f" slot="0x00" function="0x0"/>
</filesystem>
<input type="mouse" bus="ps2"/>
<input type="keyboard" bus="ps2"/>
<audio id="1" type="none"/>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x03" slot="0x00" function="0x0"/>
</source>
<address type="pci" domain="0x0000" bus="0x03" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x03" slot="0x00" function="0x1"/>
</source>
<address type="pci" domain="0x0000" bus="0x08" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x0e" slot="0x00" function="0x0"/>
</source>
<address type="pci" domain="0x0000" bus="0x10" slot="0x00" function="0x0"/>
</hostdev>
<hostdev mode="subsystem" type="pci" managed="yes">
<source>
<address domain="0x0000" bus="0x0d" slot="0x00" function="0x0"/>
</source>
<address type="pci" domain="0x0000" bus="0x0b" slot="0x00" function="0x0"/>
</hostdev>
<watchdog model="itco" action="reset"/>
<memballoon model="none"/>
<rng model="virtio">
<backend model="random">/dev/urandom</backend>
<address type="pci" domain="0x0000" bus="0x07" slot="0x00" function="0x0"/>
</rng>
</devices>
<qemu:commandline>
<qemu:arg value="-device"/>
<qemu:arg value="{"driver":"ivshmem-plain","memdev":"shmem0"}"/>
<qemu:arg value="-object"/>
<qemu:arg value="{"qom-type":"memory-backend-file","id":"shmem0","mem-path":"/dev/kvmfr0","size":134217728,"share":true}"/>
</qemu:commandline>
</domain>
If I remove the qemu:commandline block then everything works fine. But then running LookingGlass
will not be possible. Which is fine for now I guess. If I really need to game on my PC I can also use the steamlink
client. Which works