QEMU z przepustowością GPU nie uruchamia się

4

Używam Ubuntu i próbuję skonfigurować QEMU z przejściem przez GPU. Śledziłem te przewodniki:

https://www.youtube.com/watch?v=w-hOr44oBAI

https://www.pugetsystems.com/labs/articles/Multiheaded-NVIDIA-Gaming-using-Ubuntu-14-04-KVM-585/#Step5Createascripttoruneachvirtualmachine

http://www.howtogeek.com/117635/how-to-install-kvm-and-create-virtual-machines-on-ubuntu/

Mój /etc/modules:

lp
rtc
pci_stub
vfio
vfio_iommu_type1
vfio_pci
kvm
kvm_intel 

Mój /etc/default/grub:

GRUB_DEFAULT=0
GRUB_HIDDEN_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=true
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on vfio_iommu_type1.allow_unsafe_interrupts=1"
GRUB_CMDLINE_LINUX=""

Mój GPU:

$ lspci -nn | grep NVIDIA
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GK106 [GeForce GTX 650 Ti] [10de:11c6] (rev a1)
01:00.1 Audio device [0403]: NVIDIA Corporation GK106 HDMI Audio Controller [10de:0e0b] (rev a1)
$ lspci -nn | grep -i graphic
00:02.0 VGA compatible controller [0300]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller [8086:0152] (rev 09)

Mój /etc/initramfs-tools/modules:

pci_stub ids=10de:11c6,10de:0e0b

pci_stub wydaje się działać:

$ dmesg | grep pci-stub
[    0.541737] pci-stub: add 10DE:11C6 sub=FFFFFFFF:FFFFFFFF cls=00000000/00000000
[    0.541750] pci-stub 0000:01:00.0: claimed by stub
[    0.541755] pci-stub: add 10DE:0E0B sub=FFFFFFFF:FFFFFFFF cls=00000000/00000000
[    0.541760] pci-stub 0000:01:00.1: claimed by stub

Mój /etc/vfio-pci1.cfg:

0000:01:00.0
0000:01:00.1

Mój ~/windows_start.bash: http://pastebin.com/F7fq2Szt

Po uruchomieniu skryptu bash vfio-pcijest używany jako sterownik:

$ lspci -k | grep -C 3 -i nvidia
    Kernel driver in use: ahci
00:1f.3 SMBus: Intel Corporation 7 Series/C210 Series Chipset Family SMBus Controller (rev 04)
    Subsystem: ASRock Incorporation Motherboard
01:00.0 VGA compatible controller: NVIDIA Corporation GK106 [GeForce GTX 650 Ti] (rev a1)
    Subsystem: Gigabyte Technology Co., Ltd Device 3557
    Kernel driver in use: vfio-pci
01:00.1 Audio device: NVIDIA Corporation GK106 HDMI Audio Controller (rev a1)
    Subsystem: Gigabyte Technology Co., Ltd Device 3557
    Kernel driver in use: vfio-pci
03:00.0 PCI bridge: ASMedia Technology Inc. ASM1083/1085 PCIe to PCI Bridge (rev 03)

Wersje oprogramowania:

$ kvm --version
QEMU emulator version 2.5.0, Copyright (c) 2003-2008 Fabrice Bellard

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.3 LTS
Release:    14.04
Codename:   trusty

Problem polega na tym, że kiedy uruchamiam windows_start.bash, uruchamia się terminal QEMU, ale nic się nie dzieje. Monitor podłączony do procesora graficznego NVIDIA jest czarny, powinien być włączony przez QEMU, ale tak nie jest. Co ja robię źle? Jak mogę to debugować? Co jeszcze mogę spróbować osiągnąć przez GPU?

Sprawdziłem za pomocą tego przewodnika i wygląda na to, że mój procesor graficzny nie obsługuje interfejsu UEFI, więc może to jest przyczyną niepowodzenia? To wciąż dziwne, wiele osób odniosło sukces przy użyciu nawet starszych GPU, więc musi być jakiś sposób.

EDYCJA: Właśnie próbowałem uruchomić vm przy libvirtużyciu virt-manager, jak sugeruje @Deltik. Oto jak wygląda moja konfiguracja: http://pastebin.com/W46kNcrh

Wynik był prawie taki sam jak wcześniej - zaczął się, pokazał czarny ekran w virt-manageroknie i nic więcej się nie wydarzyło. W konsoli debugowania nie było błędów (które zacząłem od uruchomienia virt-manager --debug). Próbowałem również tego samego podejścia w Arch Linux i nowszej wersji Ubuntu, nie miało to żadnego znaczenia.

Dałem nagrodę @Deltik, ponieważ dał mi kilka dobrych rad, ale nadal nie byłem w stanie sprawić, by działało. Wydaje się, że tego zadania nie można wykonać, przynajmniej na moim obecnym sprzęcie.

Victor Marchuk
źródło
2
jedno (chociaż może nie rozwiązać problemu): nie pociągają za sobą pci-stubi vfio-pciw tym samym czasie. są to dwa moduły jądra, które w zasadzie służą do tego samego - przekazywania pci (-e). KAŻDY z nich odpowiada RÓŻNEMU „urządzeniu” qemu: powinieneś brać udział vfio-pcitylko wtedy, gdy używasz nowszego -device vfio-pci, LUB pci-stubtylko jeśli używasz starszego-device pci-assign
Tom Yan
1
więc w zasadzie możesz usunąć całą tę część ze skryptu startowego: gist.github.com/anonymous/039bd3a033210f401d0b, o ile zmienisz pci-stubna vfio-pci(tak, przyjmują ten sam ids=parametr w ten sam sposób) w/etc/initramfs-tools/modules
Tom Yan
1
prawdopodobnie należy je również usunąć z /etc/modules: gist.github.com/anonymous/5d19ae3c22653a282e90 , szczególniepci-stub
Tom Yan
1
btw i słabo pamiętam, że potrzebujesz ovmf (UEFI) zamiast seabios, aby gpu / vga przeszło przez pracę
Tom Yan
1
Po uruchomieniu skryptu ~/windows_start.bash, w lspci -k, widzisz Kernel driver in use: vfio-pcidla urządzeń 01:00.0i 01:00.1? Jeśli nie, vfio-pcisterownik nie jest używany na tych urządzeniach.
Deltik

Odpowiedzi:

3

Jesteś blisko

Używanie obu pci-stubivfio-pci

Można pci-stubzarezerwować urządzenie PCI (takie jak GPU), aby zapobiec przechwyceniu go przez sterownik karty graficznej, ponieważ sterownik karty graficznej (jak nouveaulub fglrx) nie puści urządzenia.

W rzeczywistości w moim teście musiałem pci-stubnajpierw vfio-pcizająć kartę graficzną PCI, ponieważ nie zrobiłbym tego przy rozruchu, co jest jednym z problemów, których doświadczyłeś. Podczas rozładunku jeden sterownik ( pci-stub) i ładowanie drugiego ( vfio-pci) w jego miejsce może wydawać się dla niektórych brzydki , pci-stubi vfio-pcisą niezawodne tag team, który skutkuje udanym maszynie wirtualnej z trybu Przez GPU. Moje testy nie przyniosły sukcesu przy użyciu tylko jednego lub drugiego.

Teraz musisz zwolnić urządzenie PCI pci-stubi przekazać je vfio-pci. Ta część skryptu powinna już to robić:

configfile=/etc/vfio-pci1.cfg

vfiobind() {
    dev="$1"
        vendor=$(cat /sys/bus/pci/devices/$dev/vendor)
        device=$(cat /sys/bus/pci/devices/$dev/device)
        if [ -e /sys/bus/pci/devices/$dev/driver ]; then
                echo $dev > /sys/bus/pci/devices/$dev/driver/unbind
        fi
        echo $vendor $device > /sys/bus/pci/drivers/vfio-pci/new_id

}

modprobe vfio-pci

cat $configfile | while read line;do
    echo $line | grep ^# >/dev/null 2>&1 && continue
        vfiobind $line
done

Uwaga: „ vfiobind” jest potrzebne tylko raz

Jak zauważono w tym komentarzu , prawdą jest, że przełączenie z pci-stubna vfio-pcimusi być wykonane tylko raz po uruchomieniu. To prawda, ale w rzeczywistości vfiobindwielokrotne uruchamianie funkcji „ ” jest nieszkodliwe, chyba że maszyna wirtualna używa obecnie uszkodzonego urządzenia PCI.

Jeśli maszyna wirtualna korzysta z urządzenia, operacja odblokowania zostanie zablokowana ( proces „stan D” ). Można to naprawić, wyłączając lub zabijając maszynę wirtualną, po czym rozpięcie prawdopodobnie się powiedzie.

Możesz uniknąć tego niepotrzebnego dodatkowego rozpinania i ponownego wiązania, zmieniając swoją vfiobind()funkcję na następującą:

vfiobind() {
        dev="$1"
        vendor=$(cat /sys/bus/pci/devices/$dev/vendor)
        device=$(cat /sys/bus/pci/devices/$dev/device)
        if [ -e /sys/bus/pci/devices/$dev/driver/module/drivers/pci\:vfio-pci ]; then
                echo "Skipping $dev because it is already using the vfio-pci driver"
                continue;
        fi
        if [ -e /sys/bus/pci/devices/$dev/driver ]; then
                echo "Unbinding $dev"
                echo $dev > /sys/bus/pci/devices/$dev/driver/unbind
                echo "Unbound $dev"
        fi
        echo "Plugging $dev into vfio-pci"
        echo $vendor $device > /sys/bus/pci/drivers/vfio-pci/new_id
        echo "Plugged $dev into vfio-pci"
}

Sprawdź lspci -kpomyślne vfio-pcidołączenie sterownika

Sprawdź, vfio-pciczy przejął za pomocą lspci -k. Ten przykład pochodzi z mojej równoważnej konfiguracji:

01:00.0 VGA compatible controller: NVIDIA Corporation GK104 [GeForce GTX 760] (rev a1)
    Subsystem: eVga.com. Corp. Device 3768
    Kernel driver in use: vfio-pci
01:00.1 Audio device: NVIDIA Corporation GK104 HDMI Audio Controller (rev a1)
    Subsystem: eVga.com. Corp. Device 3768
    Kernel driver in use: vfio-pci

Jeśli nie widzisz Kernel driver in use: vfio-pci, coś poszło nie tak z częścią skryptu, którą wkleiłem powyżej.

Konfiguracja przejścia QEMU

Zmagałem się trochę z czarnym wyświetlaczem.

We wcześniejszej wersji skryptu określono:

-device vfio-pci,host=01:00.0,bus=root.1,addr=00.0,multifunction=on,x-vga=on \
-device vfio-pci,host=01:00.1,bus=root.1,addr=00.1 \

Spróbuj pozwolić QEMU zdecydować, jakiej wirtualnej magistrali i adresu użyć:

-device vfio-pci,host=01:00.0,multifunction=on,x-vga=on \
-device vfio-pci,host=01:00.1 \

Powinieneś także przekazać flagi -nographici -vga nonedo qemu-system-x86_64. Domyślnie QEMU ujawnia emulowaną kartę graficzną maszynie wirtualnej, a maszyna wirtualna może używać tego innego urządzenia wideo do wyświetlania zamiast planowanej fizycznej karty NVIDIA.

Jeśli nadal pojawia się pusty ekran, spróbuj również dodać -nodefaultsflagę, co wyklucza domyślny port szeregowy, port równoległy, konsolę wirtualną, urządzenie monitorujące, adapter VGA, urządzenie dyskietek i urządzenie CD-ROM.

Teraz twoje qemu-system-x86_64polecenie powinno być w stanie uruchomić maszynę wirtualną z urządzeniami PCI 01:00.0i 01:00.1przejść, a podłączony ekran 01:00.0powinien coś pokazywać.

Odniesienie / konfiguracja próbki

Mój test nie jest identyczny z twoim, ale udało mi się uzyskać działające przejście grafiki i przejście USB za pomocą tego qemu-system-x86_64polecenia, po zajęciu wszystkich odpowiednich urządzeń PCI pci-stubz vfio-pci:

qemu-system-x86_64 \
-enable-kvm \
-name node51-Win10 \
-S \
-machine pc-i440fx-2.1,accel=kvm,usb=off \
-cpu host,kvm=off \
-m 16384 \
-realtime mlock=off \
-smp 8,sockets=8,cores=1,threads=1 \
-uuid 5c4a3e8a-6e8e-449f-9361-29fcdc35358d \
-nographic \
-no-user-config \
-nodefaults \
-chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/node51-Win10.monitor,server,nowait \
-mon chardev=charmonitor,id=monitor,mode=control \
-rtc base=localtime,driftfix=slew \
-global kvm-pit.lost_tick_policy=discard \
-no-hpet \
-no-shutdown \
-global PIIX4_PM.disable_s3=0 \
-global PIIX4_PM.disable_s4=0 \
-boot strict=on \
-device ich9-usb-ehci1,id=usb,bus=pci.0,addr=0x5.0x7 \
-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,bus=pci.0,multifunction=on,addr=0x5 \
-device ich9-usb-uhci2,masterbus=usb.0,firstport=2,bus=pci.0,addr=0x5.0x1 \
-device ich9-usb-uhci3,masterbus=usb.0,firstport=4,bus=pci.0,addr=0x5.0x2 \
-device virtio-serial-pci,id=virtio-serial0,bus=pci.0,addr=0x6 \
-drive file=/dev/zd16,if=none,id=drive-virtio-disk0,format=raw,cache=none,aio=native \
-device virtio-blk-pci,scsi=off,bus=pci.0,addr=0x2,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 \
-drive file=/media/isos/Win10_English_x64.iso,if=none,id=drive-ide0-1-0,readonly=on,format=raw \
-device ide-cd,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0 \
-device ide-cd,bus=ide.1,unit=1,drive=drive-ide0-1-1,id=ide0-1-1 \
-netdev tap,fd=24,id=hostnet0,vhost=on,vhostfd=25 \
-device virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:11:bf:dd,bus=pci.0,addr=0x3 \
-chardev pty,id=charserial0 \
-device isa-serial,chardev=charserial0,id=serial0 \
-device usb-tablet,id=input0 \
-device intel-hda,id=sound0,bus=pci.0,addr=0x4 \
-device hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0 \
-device vfio-pci,host=01:00.1,id=hostdev0,bus=pci.0,addr=0x9 \
-device vfio-pci,host=00:12.0,id=hostdev1,bus=pci.0,addr=0x8 \
-device vfio-pci,host=00:12.2,id=hostdev2,bus=pci.0,addr=0xa \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x7 \
-device vfio-pci,host=01:00.0,x-vga=on \
-vga none \
-msg timestamp=on

Odpowiednie przedmioty z lspci -k:

00:12.0 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB OHCI0 Controller
    Subsystem: Gigabyte Technology Co., Ltd Device 5004
    Kernel driver in use: vfio-pci
00:12.2 USB controller: Advanced Micro Devices, Inc. [AMD/ATI] SB7x0/SB8x0/SB9x0 USB EHCI Controller
    Subsystem: Gigabyte Technology Co., Ltd Device 5004
    Kernel driver in use: vfio-pci
01:00.0 VGA compatible controller: NVIDIA Corporation GK104 [GeForce GTX 760] (rev a1)
    Subsystem: eVga.com. Corp. Device 3768
    Kernel driver in use: vfio-pci
01:00.1 Audio device: NVIDIA Corporation GK104 HDMI Audio Controller (rev a1)
    Subsystem: eVga.com. Corp. Device 3768
    Kernel driver in use: vfio-pci

Obserwowany wynik:

Zdjęcie zaobserwowanego wyniku

Deltik
źródło
Tylko głupie i mylące jest wiązanie pci-stubsię z kartą za pomocą initramfs, a następnie ponowne wiązanie vfio-pci, NAWET JEŚLI nadal będzie działać. Nie wspominając już o tym, że powoduje to, że skrypt zawiera kroki, które muszą zostać uruchomione tylko raz, więc będą bezbłędnie uruchamiane wielokrotnie, jeśli wykonasz „cykle zasilania” na maszynie wirtualnej.
Tom Yan
2
@TomYan: Zarówno OP, jak i ja nie byliśmy w stanie połączyć się vfio-pciprzy rozruchu. W moim teście rezerwowanie z, pci-stuba następnie przełączanie na vfio-pcinie powiodło się.
Deltik
@Deltik: Dziękujemy za szczegółową odpowiedź. Wprowadziłem zmiany, które zasugerowałeś i odpowiednio zaktualizowałem moje pytanie. Wygląda na to, że mój GPU używa teraz vfio-pcipo uruchomieniu skryptu, co jest dobre, ale nic innego się nie zmieniło. Ekran podłączony do NVIDIA jest nadal czarny i nie ma błędów w terminalu. Czy mógłbym jeszcze spróbować rozwiązać problem? Moim największym problemem jest to, że nawet teraz nie rozumiem, co jest nie tak. Spróbuję innych ustawień z twojej przykładowej konfiguracji, może coś będzie działać.
Victor Marchuk
1
@VictorMarchuk: Czy możesz spróbować dodać -nographicflagę i / lub -nodefaultsflagę do qemu-system-x86_64? Te flagi wyłączają emulowane urządzenie graficzne, które QEMU domyślnie udostępnia, co, mam nadzieję, zmusiłoby twój GeForce GTX 650 Ti do bycia jedyną opcją graficzną.
Deltik
1
@VictorMarchuk: Twoje polecenie wymaga końcowego „\” w każdym wierszu oprócz ostatniego. Mówi powłoce, że w poleceniu jest jeszcze więcej parametrów.
Deltik