Hirdetés

Egy fél GPU passthrough KVM-en

És hogy miért fél? Mert csak a feléig jutottam, de ez a fele legalább működik (vagy nem). Ezt is huszonhat leírásból és fórumból kellett összelapátolni. :O :DDD Egyszerűen nincs step-by-step leírás, és valószínűleg azért, mert nincs univerzális eljárás erre... :Y
Szükség volt egy olyan megoldásra, ahol egy virtuális Windowson futnak dVGA igényes programok, ehhez pedig GPU-t kell adni a virtuális gépnek. A fizikai gép egy workstation laptop, amin Ubuntu fut, a hipervizor KVM.

Elméletben ez nem olyan rettenetes dolog, hiszen workstation gép, IOMMU SR-IOV, VT-D, ilyesmi van. Erre lett kitalálva. Bekattintod a Virt-managerben a PCIE eszközt, hogy azt adja át és... na, így nem fog menni.
Az itthoni hostban van mondjuk egy PCIE-s párhuzamos kártya (videokátya nincs, minek), azt tényleg ennyi, simán megy. Egy GPU nem :DDD :W

Ahogyan sikerült eljutni az alapvető GPU átadásig :

- Megnézni, hogy az IOMMU csoportok rendben vannak-e, azaz hogy nem-e egy csoportban van a két GPU-nk, mert ha igen, akkor neki se kell állni. Erre jó ez a script, ami kiírja, hogy melyik PCIE eszköz melyik csoportban van. Elvileg asztali gépeken a használt PCIE slot sem mindegy.

Hirdetés

- Nvidia driver feltelepít a host gépre. Ezt az Ubuntu (KDE-vel) simán megoldotta.

- Beállítani a kernelnek pár paramétert. A /etc/default/grub -ban a GRUB_CMDLINE_LINUX_DEFAULT sor valahogy így :
GRUB_CMDLINE_LINUX_DEFAULT="iommu=pt nvidia-drm nomodeset=0 mitigations=auto intel_iommu=on rd.driver.pre=vfio-pci modprobe.blacklist=nouveau xdg.force_integrated=1 vfio_pci.ids=10de:13b0,10de:0fbc"
elmenteni, sudo update-grub , reboot.
A "vfio_pci.ids=10de:13b0,10de:0fbc" az érdekes itt. A PCIE ID-k a GPU-é, és a GPU hangkártyájáé, ezt később kiderül, hogyan lehet kinyerni A lényeg, hogy VFIO driver fogja kezelni a GPU-t, ami csak annyit csinál, hogy lehetővé teszi a direkt hozzáférést ahhoz az eszközhöz. Másnak nem szabad használnia a dVGA-t, mert vagy nem fog menni, vagy érdekes dolgok fognak történni, amikor elveszi a VFIO a kártyát a hosttól :D
A nouveau driver helyből blacklistes, a host OS-en csak az integrált videokártya dolgozik.

- A VFIO PCI ID-k a lspci -nnk parancs kimenetében lesznek, az eszközre vonatkozó első sor végén. A sor elején található PCI címre is szükség lesz. A kernelparaméterek között vesszővel kell felsorolni.
Nekem ugye ez volt:

$ lspci -nnk
.
.
.
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM107GLM [Quadro M2000M] [10de:13b0] (rev a2)
Kernel driver in use: vfio-pci
Kernel modules: nvidiafb, nouveau, nvidia_drm, nvidia
01:00.1 Audio device [0403]: NVIDIA Corporation GM107 High Definition Audio Controller [GeForce 940MX] [10de:0fbc] (rev a1)
Kernel driver in use: vfio-pci
Kernel modules: snd_hda_intel

- A virtuális gép indításakor, leállításakor le kell kezelni a kártya átadását, visszavételét (a későbbiekben kiderült, hogy ez nem is biztos, hogy kell). Ehhez az alábbi könyvtárszerkezetben lesz szükség némi scriptre :
$ tree /etc/libvirt/
/etc/libvirt/
├── hooks
│   ├── kvm.conf
│   └── qemu.d
│   └── win11
│   ├── prepare
│   │   └── begin
│   │   └── bind_vfio.sh
│   └── release
│   └── end
│   └── unbind_vfio.sh

kvm.conf :
VIRSH_GPU_VIDEO=pci_0000_01_00_0
VIRSH_GPU_VIDEO=pci_0000_01_00_1

(A PCI id-k a lspci -nnk kimenetében a sorok elején levő címből állnak elő.)

bind_vfio.sh :
#!/bin/bash

systemctl stop nvidia-presistenced.service

## Load the config file
source "/etc/libvirt/hooks/kvm.conf"

## Load vfio
modprobe vfio
modprobe vfio_iommu_type1
modprobe vfio_pci

## Unbind gpu from nvidia and bind to vfio
virsh nodedev-detach $VIRSH_GPU_VIDEO
virsh nodedev-detach $VIRSH_GPU_AUDIO

unbind_vfio.sh :
#!/bin/bash

## Load the config file
source "/etc/libvirt/hooks/kvm.conf"

## Unbind gpu from vfio and bind to nvidia
virsh nodedev-reattach $VIRSH_GPU_VIDEO
virsh nodedev-reattach $VIRSH_GPU_AUDIO

## Unload vfio
modprobe -r vfio_pci
modprobe -r vfio_iommu_type1
modprobe -r vfio

- És már tényleg csak a Virt-managerben kell összekattintani egy gépet, aminek win11 lesz a neve (mert ez alapján találja meg a scripteket hozzá a KVM), és elindítani. Ha minden jó, akkor elindul, van kép, és nem áll meg a host UI-ja :D

Itt olyan gondba futottam, hogy ugyan az átadott hardver látszik, de a Windows Microsoft Basic video adapterként ismeri fel (az Everest, GPU-Z által kiolvasott azonosító rendben van, 10de:13b0 ahogy kell), és nem jövök rá, miért. A Nvidia driver nem települ fel, mert szerinte nincs nVidia kártya. Vagy a video BIOS kell neki (ezt be kell szerezni, vagy kidumpolni egy updaterből - szerencsém volt, simán fent volt a TechPowerUp-on), vagy a ROM BAR-nak kellene működnie, és azzal meg is lenne?????? :F ), vagy mivel ez mobil GPU, be kéne neki kamuzni, hogy laptopon fut. Nézzük, ez okozza-e...

És lőn. A laptop kamuzásához akku kell; a virtuálgép XML-jében lett egy Qemu-s bejegyzés :
<qemu:commandline>
<qemu:arg value='-acpitable'/>
<qemu:arg value='file=/opt/qemu/SDDT1.dat' />
</qemu:commandline>

Ezt közvetlenül a </domain> elé kell betenni.

A file= az, ahol a SDDT1.dat van (a linken le is lehet tölteni). Az se mindegy, hogy hol van, mert az Apparmor megfogja, ha nem jó helyre kerül. Tehát a /usr/share/libvirt/seabios/ -ba kell tenni, különben file not found-dal el sem indul a guest.

Valamint az XML elején az XML definíció nézzen ki így :
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
Mert különben nem fogja a libvirt érteni, hogy a Qemu parancssorba tegye be a megadott paramétereket.

Így már lesz egy akku is a virtuális gépben, de nekem a nVidia driver így se m ment fel. :O
Persze ha nem laptopon kerül előadásra a dolog, akkor nem kell akkut csinálni.

A video BIOS hasonlóképpen a /usr/share/vgabios/ könyvtárba kerüljön (Apparmor-os disztrókon, mint a Debian, és származékai.). Az XML-ben a <hostdev>...</hostdev> sorok közöt lesz a rom bar='on' bejegyzés, ezt kell módosítani ilyenre :

<rom bar='on' file='/path/to/your/gpu/bios.bin' />
Ekkor már meg kell lennie a VGA BIOS-nak is. Már ha olyan a cucc, hogy a letöltött BIOS megfelel neki.

Nekem nem felelt, ezért a VGA BIOS-t a kártyáról kellett lementeni. Elvileg ezen a mobil Quadro-n is patchelni (valójában strippelni) kellett volna a BIOS-t, ez jelen esetben azt jelenti, hogy az elejét levágni; na most ez ezen Arch-os single GPU-s leírás alapján már jól lett kinyerve a kártyáról.

Fontos, hogy egyes nVidia (amit biztosan tudok) kártyák és driver verziók (pl. a GeForce-ok) nem támogatják csak úgy a GPU passthrough-t, illetve a 465-ös drivertől van támogatás elvileg GeForce-okra - előtte trükközni kellett (na most ezt nem tudom, hogy host vagy guest oldalon kell ez a driver, de majd kiderítem). Megint más driverek a virtuális géptől hisztiznek be (de pl. ebben a gépben mobil Quadro volt, ennek mennie kellett volna)...
Olyan hibák jönnek, hogy 13, 31, 43 a 'dózer eszközkezelőjében. Ezek ilyen "nem tudom elindítani a drivert" "más az eszközazonosító mint a POST alatt volt" meg ilyesmik.

(Utóbbira talán a
<kvm>
<hidden state='on'/>
</kvm>

megoldás lehet a XML <features> részében. Egyszer sikerült úgy beletenni, hogy nem tűnt el az egész gép a Virt-manager-ből, de nem működött az sem :D )

- Érdekes lehet, hogy a nVidia driver nagyon kukacos; pl. a KVM beállítja az átadott PCIE eszközt 0x05-nek, ezt észreveszi, és beduzzog. Tehát a bus=0x01... ( pl. ez volt a VGA eszköznél az XML-ben : <address domain='0x0000' bus='0x05' slot='0x00' function='0x0'/> )

- A fel nem települő driverre lett egy olyan megoldás, hogy esetleg a PCI Vendor ID? Subsystem ID? nem jó. Na jó, az eszközazonosító rendben volt, de a subsystem ID-t meg lehet adni qemu:commandline paraméterek között :
<qemu:arg value='device.hostdev0.romfile=/usr/share/vgabios/vbios.rom'/>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-pci-vendor-id=0x10de'/>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-pci-device-id=0x13b0'/>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-pci-sub-vendor-id=0x17aa'/>
<qemu:arg value='-set'/>
<qemu:arg value='device.hostdev0.x-pci-sub-device-id=0x222e'/>

...és ezzel a VGA BIOS átadása is megvan. (A linkelt Reddit subon van egy utalás a Gvt-g-re is, ami elég meredeken hangzik, de működhet.) A hexa értékeket úgy lehet kinyerni, ha telepítesz egy Windowst, és megnézed, mit ad az Eszközkezelő, tulajdonságok között. (Esetleg a driverben az .inf file-ból.) Ha ez nincs meg, akkor nem ismerhető fel a kártya nVidia-nak, amint megkapja a guest, azonnal megvan a Quadro kártya, ...és a Code 43 :O

Így már feltelepült a driver (azaz : talált neki megfelelő eszközt), de természetesen "device has problems" (és én is :D ), sárga felkiáltójel.

- Voltak olyan megoldások is, hogy a Proxmox (ami alatt szintén KVM dolgozik, és amin működik a GPU passthrough) OVMF BIOS-aival sikerült működésre bírni az egyéb KVM-es passthrough-t; megoldottam, a Proxmox OVMF-ével sem ment :D (Saját OVMF-et buildelni nem tudtam, nem működött egyik megoldás sem.)


Code 31, de amúgy 43-at is tud dobni :C


Legalább felteepül, de a VGA BIOS még mindig sehol

Jött az ötlet, hogy mit kezdene próbaképpen egy Linux guest-tel ugyanez a cucc? nVidia driver arra is van... ;]


Ez meg megy

És működött. Legalábbis olyan szintig, hogy egy friss Ubuntu telepítés virtuálgépre azonnal húzta be a Nouveau drivert. Viszont a zárt driver inicializációs hibákat dobál. :D

A gond csak az, hogy ezen a gépen semmilyen hókuszpókusz nem volt, a két PCIE eszköz bekattint, hogy az megy a guestnek (nyilván itt ugye lényeges, hogy a host Ubuntun a VFIO driver sem változott), se a start/stop scriptek, se semmi nem volt... :D Mondjuk nem tudom, ez a helyes működés volt-e, de a dmesg alapján nem volt baja, és gondolom a nouveau modul sem működne, ha nincs video BIOS. Képet nem tudtam kinyerni belőle a gép HDMI-jén, de nem is biztos, hogy annak ott kellett volna jönnie (a host OS sem látta azt a kimenetet, mivel a VFIO driver nem működik videoeszközként).

Tovább a fórumba.