SteamOS 3.0 VFIO guide

I feel like a lot of people after owning the Steam Deck will want to run SteamOS 3.0 based Arch on their systems, but there’s a lack of updated VFIO guides for things that aren’t Manjaro, PopOS, Ubuntu, Debian or Fedora.

Since SteamOS 3.0 is Arch, an updated Arch VFIO tutorial using SteamOS 3.0 would make a lot of sense. For instance, if you somehow managed to get the Kioxia M.2 SSD out of your Steam Deck and used it with different hardware, how would you go about doing VFIO using a real SteamOS install?

I have similar feelings, VFIO for gamers using a dedicated distro like SteamOS makes sense.
The biggest hurdle I see is the need for having two good GPUs.

Maybe with SteamOS it would be ok to do headless as the main configuration.

Anything in the middle makes no sense to me and would be better to just use VFIO for both SteamOS and Win.

Hey,
Did you check Sarge’s updated guide?

It features Fresh Arch goodness…

2 Likes

Ayyyyy, just in time it seems.

1 Like

I do personally feel like a video guide that starts with SteamOS by taking the M.2 SSD from the Steam Deck and using it in a normal ATX machine would get a lot more attention.

I don’t think migrating the SSD is a good idea. Why not just install steamos normally?

1 Like

Just in case Valve makes customizations for retail units vs their public SteamOS images. There is the possibility code is specifically left out on SteamOS public images but is present on the NVMe in the Steam Deck.

If someone compares the installations and this is completely wrong and they’re identical, then you can grab the public image.

I can say with a strong degree of confidence that any customization for the steam deck will be hardware enablement and not special sauce that’ll make any GPU magically behave like a GA100.

1 Like

Unfortunately that might not be true if there’s anti-cheat or DRM special sauce. It’s not performance based sauce.

Just be prepared for more significant code differences since Denuvo, EAC, and Battleye are not going away anytime soon.

I’m sure that they’d try to make that available on regular steamos, as long as there’s a TPM available.

Which, I’d be okay with. It’s not perfect, but it’s a suitable middle ground.

Frankly, I’m on board with the idea of just not playing those games. Most of them are crap anyways

2 Likes

It is true that it might have FW optimization and security. It is important for success with any handheld storage.

I would venture a guess that we will be able to clone it. But we can only wait.

1 Like

So who has the steam deck to image the NVMe? :slight_smile:

Wanna do a VFIO on my Fedora machine.

The image isn’t available yet.

The recovery images for the deck keep hitting github, but valve takes them down quick. We’ll be waiting a bit for this.

Well that will be happening until SteamOS proper reaches the same branch. So maybe never.

i was hoping for a forum member to just image the SSD. I kind of doubt Steam has keys and encryption burned in like smaller manufactures.

I haven’t seen anyone announce they have it yet. The number of people who have received the deck is miniscule so far.

Valve posted a recovery image for the Steam Deck yesterday but it’s not quite version 3.0 yet. Here’s the note they included along with it:

For all the tinkerers out there, please note that this system image is not quite SteamOS 3 yet. Depending on what you try to install it on (desktop, another handheld, refrigerator, toaster), it may not work properly. SteamOS 3 proper will come out sometime after launch (and even then it may not work on your toaster).

1 Like

I have VFIO for specifically trying stuff. So for me it is a curiosity thing.
Quite honestly Steam OS has a lot of potential in my eyes, especially if people stand spending time on it.

How are you doing with the progress? With the current prices on APUs we might bw able to do both steamos as host and guest.

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 :heart:)

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 :slight_smile:

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="{&quot;driver&quot;:&quot;ivshmem-plain&quot;,&quot;memdev&quot;:&quot;shmem0&quot;}"/>
    <qemu:arg value="-object"/>
    <qemu:arg value="{&quot;qom-type&quot;:&quot;memory-backend-file&quot;,&quot;id&quot;:&quot;shmem0&quot;,&quot;mem-path&quot;:&quot;/dev/kvmfr0&quot;,&quot;size&quot;:134217728,&quot;share&quot;: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 :wink:

3 Likes

This thread was intended to get VFIO working ON STEAMOS, not SteamOS within QEMU or KVM.

It’s the other way around we’re curious about.