Back to main page

Hardware passthrough using VFIO

Virtual Function I/O is a feature of Linux that allows assigning real hardware devices to a virtual machine so the guest OS has full control of it and can use it as on a real machine. This is useful to avoid overhead of emulating devices (e.g. assigning a network card) or to allow using devices such as GPUs that are not emulated by QEMU.

The guest OS will see passed through cards as if these were plugged into it as on a real machine, thus it needs appropriate guest drivers for these cards. This also means that passthrough cards have to be removed from the host driver and assigned to the vfio-pci driver instead, which means the host cannot use them any more and the guest will take full control of those cards. That also means you cannot pass through the video card or network card that the host uses for its output or network but may need a second card you don't use on the host to pass through or live with loosing graphics output from the host while the guest is running if you only have one GPU for example (that makes it more difficult to set up, so probably start with a second card first before trying more advanced setups).

There are several guides online for setting up GPU passthrough, mostly for Windows guest for gaming and using KVM. They also often suggest using high level tools such as libvirt and virt-manager which is supposed to make it simple but in reality just makes it more complicated than it needs to be. Reading the original presentation on VFIO one can see that this is actually quite simple. What makes it complex is all the differences between motherboards, CPUs, Linux distros and cards to be passed through. Additionally, GPU passthrough is more difficult because these have peculiarities that need to be considered and also the situation with GPU support on AmigaNG machines and different drivers on Amiga like OSes adds another level of complexity on top of that.

This page attempts to give a simple overview and demystify setup of passthrough of GPUs and other cards to Amiga like OSes running on QEMU, but it is not a "for dummies" or "quickly and easily" guide. You will still need to know what you are doing to achieve this, but hopefully will have more understanding after reading this (and linked) pages.

Prerequisites

Setup

Usage

To pass through the devices to the guest, add appropriate options to QEMU command. For example a graphics card may need something like this:
-vga none
-device vfio-pci,host=01:00.0,multifunction=on,x-vga=on
-device vfio-pci,host=01:00.1
where the host values are the bus:device.function address of the device. The graphics card has two functions so you need multifunction=on for the first function to let it know that there are other functions and it is a VGA card with legacy VGA resources that are to be passed through with x-vga=on to replace the emulated VGA which is disabled with -vga none otherwise it had conflicting VGA resources. You also need to run QEMU as root to be able to access VFIO devices. After this the card should appear in the guest virtual machine as a PCI device and the guest OS can use it as other PCI devices.

In principle that is all there is to it and this also works most of the time for simpler devices such as network or SATA cards. It may be a good idea to get such a simpler card working first just to see how it works generally before trying to get GPU passthrough work.

Complications

If your goal is to get better graphics by passing through a GPU to Amiga like OSes this is where it gets more complicated. I will assume you are familiar with what cards are supported on real machines. If not, check here for AmigaOS or here for MorphOS. Also consider that QEMU before version 10 only supported VFIO passthrough for RadeonHD and newer cards. Older cards may work now with QEMU v10.0.0 but are still untested for now. So first you need to find a card within those constraints that you can also plug in the host.

Some knowledge of the theory of operation of graphics cards on real machines is also useful. I try to give a quick summary here. Most graphics cards are made for x86 compatible PCs. These have an option ROM that is run by BIOS on a PC to initialise the card when the machine is switched on. To use such PC card on an AmigaNG machine, the machine's firmware has an x86 and BIOS emulator that runs this ROM. This emulator is not perfect and often crashes on newer cards (or the QEMU default video bios of the emulated cards) but despite of that it may run enough to get the card working, but then you will get no output until the OS driver loads. The OS driver may need the firmware to run the card's ROM first so if you boot with -kernel bboot and not with -bios machine.rom it may not work. But some newer Radeon cards have AtomBIOS which some drivers may know how to run so with some luck those cards may work even without the BIOS emulator in firmware run first. In short, you may need to use the firmware ROM for the machine if passing through GPUs to correctly initialise the card, so this may be more difficult than just getting AmigaOS boot on QEMU with BBoot. The sam460ex has the firmware included in QEMU. For amigaone and pegasos2 there is info here on how to get firmware ROM.

Other considerations specific for machines emulated by QEMU:

Other problems you may encounter:
  1. VGA arbitration and Intel integrated graphics

    According to this article Intel iGPU may not work with x-vga=on but the card ROM may not work without VGA resources. (Windows guests usually avoid this using OVMF as guest firmware with newer cards that have UEFI ROMs and don't need the VGA resources but that's not an option for AmigaNG.) The work around patch might fix it but may disable 3D acceleration on the host. Cards with AtomBIOS may still work without VGA regions but the card may not be fully initialised which may lead to problems later. With x-vga=on this may corrupt host display or cause the host to freeze as those regions still go to the Intel iGPU even when it told to release them. There seems to be no good solution other than using another graphics card and disable the iGPU.

  2. Overlapping reserved regions

    As described here and here you may get an error if the guest's memory map overlaps reserved regions. You can check reserved regions on the host with cat /sys/kernel/iommu_groups/0/reserved_regions replacing 0 with the appropriate IOMMU group number and the host memory map with info mtree in QEMU Monitor. This may be the reason why some cards need bus=pci.0 on pegasos2 and may be less likely to happen on amigaone due to the different memory map. Disabling resizable BARs may also be related but I'm not sure. Using another host machine may also help as it may have different reserved regions.

  3. Cannot start guest more than once without host reset

    Some Radeon cards do not support Function Level Reset so only work for the first start of the machine but cannot get back to a sane state when the guest stops, so next boot of guest fails until the host is reset which also resets the card. There is an out of tree Linux kernel module to fix this for some cards which may be needed to avoid this problem with those cards.

  4. AmigaOS freezes on boot with passed through GPU

    As a work around you may need to disable interrupts which can be done adding INTERRUPT=no tool type to the monitor file for the graphics card which is created on first boot. After the freeze remove the -device vfio-pci lines and add -device sm501 and boot with that to set the tool type which may fix this with somewhat lowered performance but the cause and proper fix is not understood yet.

Other tips and tricks: See main page for more general info.