Dieses mal habe ich mich mit dem Durchreichen einer Grafikkarte an eine virtuelle Windowsinstallation unter KVM beschäftigt. Als Dom0 nutze ich hier ArchLinux, u.a. auch weil das Thema noch sehr in Bewegung ist und man wegen dem rolling Release immer einen neuen Kernel erhält. Der Vorteil von VGA-Passthrough ist, dass das Gast-System im Idealfall nahezu die volle Geschwindigkeit der Grafikkarte umsetzen kann. So könnte man z.B. an einem Fernseh-Server eine DomU für einen VDR haben kann, eine weitere DomU mit einem Windows für die WG-Mitbewohner die Windowsspiele auf dem Fernseher zocken möchten oder über XBMC dann das Fernsehprogramm sehen. Eine weitere DomU könnte als Proxy/Firewall/Mailserver und und und…
Mein Hintergedanke ist noch immer, dass dieses Projekt meinen aktuellen WG-Server, der mit YaVDR arbeitet ablösen kann. Der Linux Kernel 3.10 soll ja VDPAU für die Radeon Karten ermöglichen – das würde bedeuten, dass ich einen großen Server mit einer DomU als Fernsehreceiver mit BluRayplayer und eine DomU als Konsolenersatz nutzen könnte.
Info: Der Artikel ist derzeit noch „work-in-progress“, da meine Dokumentation noch nicht gut genug ist und ich nur als root unterwegs bin. Zum anderen bin ich mit der Geschwindigkeit auch noch nicht zufrieden. Ich bin jedoch froh, dass das Konzept quasi schon arbeitet. Dennoch werde ich weiter herumprobieren und an Parametern schrauben, bis ich ein zufriedenstellendes Ergebnis habe – der Artikel wird daher sicherlich noch mehrmals geupdated werden. Wichtig ist mir erstmal, dass man hier erstmal einen Ausgangspunkt für seine eigenen Recherchen hat und in späteren Versionen des Artikels dann quasi mit Copy & Paste ans Ziel kommt.
Die Hardware (IOMMU / VT-D tauglich):
Wichtig ist, dass man ein System mit IOMMU (bei AMD) bzw. VT-D (bei Intel) hat. Bei AMD ist das bei den neueren 900er Sets der Fall – vorher sollte man sich aber versichern, dass dieses Feature auch vom Mainboardhersteller ins BIOS gebracht wurde. Ich habe mir dazu extra ein AMD-Board mit 990er Chipsatz gegönnt. Recht praktisch sind auch Kombidesktops wie der von Logitech. Man hat nur einen USB-Receiver, der dann exklusiv an eine DomU durchgereicht wird.
Mainboard: Asus M99X-Evo
Cpu: Athlon II 640
RAM: 4 GB RAM (ECC)
Festplatte: eine kleine 160er Sata 2,5
Tastatur: Logitech MK520 Wireless Desktop
Grafikkarte Dom0: Matrox Millenium
Grafikkarte DomU: ATI Radeon 4850, jetzt 6850
Pakete installieren:
Die folgenden Pakete müssen installiert werden:
libvirt qemu dnsmasq
Grub Parameter setzen:
Ein Auszug aus meiner menu.cfg. Die Parameter iommu=pt iommu=1 sind wichtig.
linux /vmlinuz-linux root=UUID=328873c3-cc85-4c75-8b77-ac9a7763d532 ro iommu=pt iommu=1 quiet echo 'Initiale Ramdisk wird geladen …' initrd /initramfs-linux.img
Modprobe Parameter setzen:
Damit die Dom0 nicht die Karte nutzt, habe ich die Kernelmodule geblacklistet, sodass die Karte nicht angesprochen wird.
[root@Virtking modprobe.d]# cat blacklist.conf
install nouveau /bin/false install radeon /bin/false
[root@Virtking modprobe.d]# cat kvm_iommu_map_guest.conf
options kvm allow_unsafe_assigned_interrupts=1
Und NPT (Nested Page Tables) deaktivieren. Das brachte mir ca. 300% mehr Speed in Grafikbenchmarks.
[root@Virtking modprobe.d]# cat kvm-amd.conf
options kvm-amd npt=0
Danach noch das neue initrd bauen:
mkinitcpio -p linux
und neustarten
Qemu Parameter setzen:
-> qemu.conf parameter
vi /etc/libvirt/qemu.conf
# ohne iommu: user="dennis" group="kvm" # später # Some examples of valid values are: # # user = "qemu" # A user named "qemu" # user = "+0" # Super user (uid=0) # user = "100" # A user named "100" or a user with uid=100 # user = "root" allow_unsafe_assigned_interrupts=1 # The group for QEMU processes run by the system instance. It can be # specified in a similar way to user. group = "root"
Virtuelle Maschine anlegen:
Hier kann man sich es erstmal bequem machen. Entweder man legt das ganze von Hand an, oder baut erstmal ein Gerüst, indem man sich mit VirtManager von einem anderen Computer auf die Dom0 verbindet und eine Maschine anlegt. Positiver Nebeneffekt ist, dass man relativ schnell die CPU und den USB-Receiver der Tastatur umgestellt hat.
Achtung: Wenn die Tastatur beim Start der DomU an diesee gebunden wird, kann man auf der Dom0 nichts mehr eintippen. Ein funktionierende SSH-Verbindung ist daher wichtig, es sei denn man hat 2 Tastaturen am Server.
Für die Virtio-Treiber sind die ISOs des Fedora Projektes sehr nützlich: http://alt.fedoraproject.org/pub/alt/virtio-win/latest/images/bin/
Hier als Beispiel meine vorläufige Konfiguration der Maschine:
[root@Virtking qemu]# cat /etc/libvirt/qemu/testmaschine001.xml
<!-- WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE OVERWRITTEN AND LOST. Changes to this xml configuration should be made using: virsh edit testmaschine001 or other application using the libvirt API. -->
<domain type='kvm'> <name>testmaschine001</name> <uuid>cef56731-d06e-d1f1-d063-f8105645826b</uuid> <memory unit='KiB'>2097152</memory> <currentMemory unit='KiB'>2097152</currentMemory> <vcpu placement='static' cpuset='2-3'>2</vcpu> <os> <type arch='x86_64' machine='pc-i440fx-1.4'>hvm</type> <boot dev='hd'/> </os> <features> <acpi/> <apic/> <pae/> </features> <cpu mode='custom' match='exact'> <model fallback='allow'>Opteron_G3</model> <vendor>AMD</vendor> <feature policy='require' name='skinit'/> <feature policy='require' name='vme'/> <feature policy='require' name='mmxext'/> <feature policy='require' name='fxsr_opt'/> <feature policy='require' name='cr8legacy'/> <feature policy='require' name='ht'/> <feature policy='require' name='3dnowprefetch'/> <feature policy='require' name='3dnowext'/> <feature policy='require' name='wdt'/> <feature policy='require' name='extapic'/> <feature policy='require' name='pdpe1gb'/> <feature policy='require' name='osvw'/> <feature policy='require' name='nodeid_msr'/> <feature policy='require' name='ibs'/> <feature policy='require' name='cmp_legacy'/> <feature policy='require' name='3dnow'/> </cpu> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> <emulator>/usr/bin/qemu-system-x86_64</emulator> <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/var/lib/libvirt/images/testmaschine001.img'/> <target dev='vdb' bus='virtio'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x09' function='0x0'/> </disk> <disk type='block' device='cdrom'> <driver name='qemu' type='raw'/> <target dev='hdc' bus='ide'/> <readonly/> <address type='drive' controller='0' bus='1' target='0' unit='0'/> </disk> <controller type='usb' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> </controller> <controller type='ide' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> </controller> <controller type='sata' index='0'> <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </controller> <controller type='pci' index='0' model='pci-root'/> <interface type='network'> <mac address='52:54:00:0a:66:b0'/> <source network='default'/> <model type='virtio'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> <serial type='pty'> <target port='0'/> </serial> <console type='pty'> <target type='serial' port='0'/> </console> <input type='tablet' bus='usb'/> <input type='mouse' bus='ps2'/> <graphics type='vnc' port='-1' autoport='yes' keymap='de'/> <video> <model type='vga' vram='9216' heads='1'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </video> <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='usb' managed='yes'> <source> <vendor id='0x046d'/> <product id='0xc52b'/> </source> </hostdev> <memballoon model='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </memballoon> </devices> </domain>
Vor dem Start der Maschine noch den Governor auf Performance stellen. Das brachte mir nochmal ca. 50% Speed und einen insgesamt flüssiger wirkenden Ablauf im Unigine Heaven 4.0 Benchmark.
cpupower frequency-set -g performance
Vielen Dank geht an:
- Das Fedora Wiki: http://fedoraproject.org/wiki/How_to_debug_Virtualization_problems#PCI_device_assignment
- natürlich auch das KVM-Projekt an sich: http://www.linux-kvm.org/page/HOWTO
- und tavi-tech, wo ich angefangen habe mich durch die Sache durchzuarbeiten: http://tavi-tech.blogspot.de/p/vga-passthrough-kvm.html
- ’nbhs‘ aus dem Arch Linux Forum: https://bbs.archlinux.org/viewtopic.php?id=162768
Todo:
dmesg:
port. Nested cgroups may change behavior in the future.
[ 15.497875] cgroup: „memory“ requires setting use_hierarchy to 1 on the root.
[ 15.497996] cgroup: libvirtd (326) created nested cgroup for controller „devices“ which has incomplete hierarchy support. Nested cgroups may change behavior in the future.
[ 15.498105] cgroup: libvirtd (326) created nested cgroup for controller „blkio“ which has incomplete hierarchy support. Nested cgroups may change behavior in the future.
[ 34.849069] pci 0000:01:00.0: enabling device (0000 -> 0003)
[ 36.030584] assign device 0:1:0.0
[ 68.684243] pci-stub 0000:01:00.0: claimed by stub
-> stub
echo „modprobe pci_stub“
echo „unbind pci-pci bridge“
#01:00.0 0300: 10de:1040 (rev a1)
echo „10de 1040“ > /sys/bus/pci/drivers/pci-stub/new_id
echo „unbind pci device“
echo „0000:01:00.0“ > /sys/bus/pci/devices/0000:01:00.0/driver/unbind
echo „0000:01:00.0“ > /sys/bus/pci/drivers/pci-stub/bind
#echo „0000:03:07.0“ > /sys/bus/pci/drivers/ivtv/unbind
#echo „4444 0803“ > /sys/bus/pci/drivers/pci-stub/new_id
#echo 0000:03:07.0 > /sys/bus/pci/devices/0000\:03\:07.0/driver/unbind
#echo 0000:03:07.0 > /sys/bus/pci/drivers/pci-stub/bind
-> iommu BIOS/UEFI Setting 64MB:
OFF:
[ 0.000000] Checking aperture…
[ 0.000000] No AGP bridge found
[ 0.000000] Node 0: aperture @ b4000000 size 32 MB
[ 0.000000] Aperture pointing to e820 RAM. Ignoring.
[ 0.000000] Your BIOS doesn’t leave a aperture memory hole
[ 0.000000] Please enable the IOMMU option in the BIOS setup
[ 0.000000] This costs you 64 MB of RAM
[ 0.000000] Mapping aperture over 65536 KB of RAM @ b4000000
[ 0.000000] PM: Registered nosave memory: 00000000b4000000 – 00000000b8000000
ON:
[ 0.000000] Checking aperture…
[ 0.000000] No AGP bridge found
[ 0.000000] Node 0: aperture @ f8000000 size 64 MB
[ 0.000000] Memory: 4009724k/5242880k available (4983k kernel code, 1085948k absent, 147208k reserved, 3967k data, 1092k init)
[ 0.000000] SLUB: Genslabs=15, HWalign=64, Order=0-3, MinObjects=0, CPUs=8, Nodes=1
[ 0.000000] Preemptible hierarchical RCU implementation.