#
gpupassthrough #
iommu #
qemu #
kvm #
libvirt #
looking-glass #
vm #
linux Samstag habe ich den Umbau vorgenommen.
Das war der alte Zustand, noch mit dem Boxed-AMD-Lüfter, der durchaus brauchbar ist – sowohl mechanisch 1a als auch ausreichende Kühlleistung. Wurde durch den relativ kleinen Lüfter unter Vollast aber hörbar, wenn auch nicht sonderlich nervig.
Zusätzlicher 2x 2,5"-Wechselrahmen ist nun eingebaut.
Leergeräumt:
Dann wollte ich den CPU-Kühler vom Prozessor abziehen. Sinnvoll wäre es gewesen, ihn leicht zu verdrehen, weil die alte Wärmeleitpaste ein erstaunliches Klebepotenzial entwickelt hat. Das habe ich erst dann gemerkt, nachdem ich den Prozessor (bei immer noch arretiertem Sockel) aus selbigem gerissen habe. Kleiner Schockmoment, aber kein Pin verbogen oder abgerissen. Puh.
RAM und Prozessor bereits ins neue Mainboard eingesetzt und die Halterungen vom neuen Lüfter montiert:
Eine GPU und den Kühler installiert, das Netzteil für einen Funktionstest fliegend verdrahtet. Der Piepser darf natürlich auch nicht fehlen, um Fehlercodes zu hören:
Die Power-Switch-Pins kurzgeschlossen und das Board hat gestartet. Keine Beep Codes, dafür Kirmes auf den kleinen Status-LEDs, die sich über den RAM-Sockeln befinden. Nach ca. 30–45s wurde ich nervös, weil ich immer noch keinen kurzen OK-Piepser vernommen hatte und die Status-LEDs immer noch wild die Farbe gewechselt haben. Dann aber kam die Erlösung: Ein kurzer Pieps und eine grüne Status-LED: Die Grundkonfiguration funktioniert also und das Board konnte eingebaut werden. Einen so langen ersten Start aus dem Werkszustand habe ich bei einem Mainboard noch nicht erlebt. Jetzt aber startet es erstaunlich schnell und es dauert nur wenige Sekunden, bis es meinen Lieblingsbootloader „refind“ startet.
Alles fertig eingebaut. Leider wurde es mal wieder reichlich eng im Gehäuse, spätestens als ich mit der Verkabelung anfing. Aber alles hat seinen Platz gefunden. Über den drei Grafikkarten ist noch eine zusätzliche 4-fach-USB2.0-Karte im PCIe1x installiert. Hier hängen Tastatur, Maus und der Monitor-USB-Hub vom „seat1“ dran. Das Schöne: Es reicht per „loginctl attach seat1 …“ nur diese Karte zuzuweisen, alles was dort dranhängt gehört dann automatisch zum seat1. Das vereinfacht die Zuweisung und spart wertvolle USB-Ports vom Mainboard. Leider konnte ich die beiden Front-USB-Ports vom Gehäuse nicht ans Mainboard anschließen, weil der Kühlkörper der untersten Grafikkarte den Pfostenstecker verdeckt. Zum Glück passte aber der abgewinkelte Stecker vom seriellen Kabel in den COM1-Pfostenstecker, damit wird das LCD-Frontdisplay angesteuert, was ich nicht mehr missen möchte.
Jetzt ging es aber zu KVM/QEMU und der Windows10-Installation mit GPU-Passthrough. Wichtig dabei ist, dass die GPU für den Gast nicht schon vorher initialisiert bzw. mit einem Linux-Treiber versorgt werden darf. Dazu lädt man das Kernelmodul „vfio-pci“ mit der Option „ids=vendor:device“, entsprechend der Karte. In meinem Fall z.B. mit der PCI-ID „10de:0fb8“. Das Problem bei mir: Ich habe 2 Nvidia 1030 im Rechner, eine für seat1 und eine weitere für die VM. Für das Problem geben viele Howtos ein kleines Shellscript an, was anhand der PCI-Adressen die Zuweisung vornimmt. Das klappt aber nur, wenn das Script früh genug innerhalb einer initrd startet, die ich aber nicht benutze und auch nicht nutzen möchte. Fündig wurde ich mit
~ # modinfo vfio-pci
…
parm: ids:Initial PCI IDs to add to the vfio driver, format is "vendor:device[:subvendor[:subdevice[:class[:class_mask]]]]" …
…
Es gibt also noch einen „Subvendor“ und da die eine Nvidia 1030 von Asus und die andere von MSI ist, kann man sie anhand der Subvendor-ID unterscheiden. Per Kernelmodul ist aber auch da nichts zu machen, weil ohne initrd (in der man nvidia weglässt) das „passendere“ nvidia-Modul vom Kernel zugewiesen wird, bevor systemd überhaupt das benutzerdefinierte Modulladen vornimmt.
Die Lösung war aber einfach:
--- VFIO Non-Privileged userspace driver framework
│ │ [ ] VFIO No-IOMMU support ----
│ │ <*> VFIO support for PCI devices
│ │ [*] VFIO PCI support for VGA devices
│ │ [ ] VFIO PCI extensions for Intel graphics (GVT-d)
│ │ < > Mediated device driver framework
Nicht als Modul, sondern statisch in den Kernel einbinden und dann per Kerneloption mit Subvendor-ID „vfio-pci.ids=10de:0fb8:1462,10de:1d01:1462“ (GPU und HDMI-Audio) konfigurieren.
Die Installation und Konfiguration in virt-manager war dann relativ problemlos, auch wenn es einige Fallstricke gab, wie z.B. die VM-Erkennung im Windows-Nvidia-Treiber, der dann seinen Dienst verweigert. Als die direkte Ausgabe über die VM-Grafikkarte funktionierte, habe ich dann
https://looking-glass.io/ compiliert und entsprechend installiert.
Jetzt läuft es tatsächlich so, wie ich mir das gewünscht habe: Eine Windows10-VM mit nativer HW-Grafikbeschleunigung und dennoch Ausgabe auf den Linux-Desktop. Hier ein kleines Youtube-Video, was es schön zeigt:
GPU-Passthrough + Looking GlassDer rechte Monitor ist direkt mit der VM-Grafikkarte verbunden, links ist Gnome mit Looking Glass zeitgleich zu sehen. In der VM läuft 3DMark für eine 3D-Grafikdemo. Die Latenz ist mit <=16ms, also ~1 Frame bei 60Hz, für mich absolut ausreichend. Der größte Faktor ist dabei einfach, dass die Bildschirme nicht synchron bzgl. Vsync sind und allein dadurch schon ein visueller Zeitversatz erscheint.
Was noch zu tun ist:
Auf die bestellte SSD für das Gastsystem warten und Netzwerk und Harddisk mittels „virtio“ zu paravirtualisieren, was auch noch mal einen schönen Geschwindigkeitsboost gibt. Und natürlich noch den einen USB3.0-Controller des MBs, der in einer einzelnen IOMMU-Gruppe ist, ebenfalls mittels PCI-Passthrough zur VM durchreichen.
IOMMU Group 18:
08:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Family 17h (Models 00h-0fh) USB 3.0 Host Controller [1022:145c]
Laut einem Forumsbeitrag ist dieser USB-Controller für genau 2 USB-Ports (1x normal, 1x USB-C) an der Rückseite zuständig, was ausreicht, um mal eine Webcam und ein Audiointerface mit niedriger Latenz unter der Windows-VM zu betreiben.