четверг, 18 августа 2016 г.

GPU passthrough in Xenial (Заметки, нефильтрованное)

Attention

Это копипаста, записки и эксперименты, неструктурированные. Не голое howto.
В качестве железа использовалось:

Основной монитор подключён через HDMI на материнской плате и использует встроенную видеокарту (Intel® HD Graphics 4600). Телевизор подключён через HDMI к видеокарте.

Из сильных огорчений: после часового гугления оказалось что видяхи, даже дорогущие, не умеют HDMI-CEC чтобы можно было отправить сигнал для включения телевизора, хотя копеечная Raspberry PI умеет :/

TLDR;

Играбельно, за исключением со временем (часы) нарастающего количества описанных ниже звуковых артефактов.

  • The Witcher 2 играбельно на максимальных настройках 1920x1080 как в Windows 10, так и в SteamOS
  • Ori and the Blind Forest: Definitive Edition пройдена полностью в Windows 10 виртуалке, ибо linux не поддерживает
  • [Doom 4|] полностью пройден на почти максимальных настройках (после какой-то из настроек FPS резко упали до 10, но, думаю, тут уже проблема в железе).

IOMMU

http://awilliam.github.io/presentations/KVM-Forum-2016/
http://vfio.blogspot.ru/2016/09/intel-iommu-enabled-it-doesnt-mean-what.html
https://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/vt-directed-io-spec.pdf

IOMMU (англ. input/output memory management unit) — блок управления памятью (MMU) для операций ввода-вывода. Так же как традиционный, процессорный блок управления памятью, который переводит виртуальные адреса, видимые процессором в физические, этот блок занимается трансляцией виртуальных адресов, видимых аппаратным устройством, в физические адреса. Wikipedia

https://www.kernel.org/doc/Documentation/Intel-IOMMU.txt
DMAR - DMA remapping

Проверить состояние IOMMU и DMAR:

dmesg|grep -e DMAR -e IOMMU

AMD

AMD systems only require that the IOMMU is enabled in the BIOS. The system is ready for PCI passthrough once the IOMMU is enabled.

Настройка модулей ядра

Xenial Fresh

Ставим свежее ядро

sudo apt-get install linux-generic-hwe-16.04-edge

Теоретически (в процессе проверки), с ядром 4.10 (на текущий момент hwe edge) можно обойтись без vfio_iommu_type1.allow_unsafe_interrupts=1

Через параметр ядра в конфигурации grub

Добавить всё что нужно в значение переменной GRUB_CMDLINE_LINUX_DEFAULT в файле /etc/default/grub, к дефолту добавилось следующее:

intel_iommu=on vm.nr_hugepages=5120 nvidia.blacklist=1

После этого нужно выполнить команду update-grub для обновления конфигурации в /boot:

$ sudo update-grub
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.10.0-26-generic
Found initrd image: /boot/initrd.img-4.10.0-26-generic
Found linux image: /boot/vmlinuz-4.4.0-83-generic
Found initrd image: /boot/initrd.img-4.4.0-83-generic
Found linux image: /boot/vmlinuz-3.19.0-37-generic
Found initrd image: /boot/initrd.img-3.19.0-37-generic
Found memtest86+ image: /memtest86+.elf
Found memtest86+ image: /memtest86+.bin
done

TODO: телега про GRUB_HIDDEN_TIMEOUT (Warning: Setting GRUB_TIMEOUT to a non-zero value when GRUB_HIDDEN_TIMEOUT is set is no longer supported.)

Через modprobe.d

Либо воспользоваться каталогом /etc/modprobe.d/:

echo "options vfio_iommu_type1 allow_unsafe_interrupts=1" | sudo tee /etc/modprobe.d/vfio_iommu_type1.conf
$ sudo modprobe vfio_iommu_type1

Посмотреть текущие параметры модуля ядра, в данном случае - vfio_iommu_type1:

$ grep -H '' /sys/module/vfio_iommu_type1/parameters/*

Проверяем IOMMU

После перезагрузки проверяем что iommu работает (внимание на “IOMMU group <номер>” ):

$ for iommu_group in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d); do echo "IOMMU group $(basename "$iommu_group")"; for device in $(ls -1 "$iommu_group"/devices/); do echo -n $'\t'; lspci -nns "$device"; done; done
IOMMU group 0
	00:00.0 Host bridge [0600]: Intel Corporation 4th Gen Core Processor DRAM Controller [8086:0c00] (rev 06)
IOMMU group 1
	00:01.0 PCI bridge [0604]: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor PCI Express x16 Controller [8086:0c01] (rev 06)
	01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM206 [GeForce GTX 960] [10de:1401] (rev a1)
	01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:0fba] (rev a1)
IOMMU group 2
	00:02.0 VGA compatible controller [0300]: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller [8086:0412] (rev 06)
IOMMU group 3
	00:03.0 Audio device [0403]: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller [8086:0c0c] (rev 06)
IOMMU group 4
	00:14.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB xHCI [8086:8c31] (rev 05)
IOMMU group 5
	00:16.0 Communication controller [0780]: Intel Corporation 8 Series/C220 Series Chipset Family MEI Controller #1 [8086:8c3a] (rev 04)
IOMMU group 6
	00:1a.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB EHCI #2 [8086:8c2d] (rev 05)
IOMMU group 7
	00:1b.0 Audio device [0403]: Intel Corporation 8 Series/C220 Series Chipset High Definition Audio Controller [8086:8c20] (rev 05)
IOMMU group 8
	00:1c.0 PCI bridge [0604]: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express Root Port #1 [8086:8c10] (rev d5)
IOMMU group 9
	00:1c.2 PCI bridge [0604]: Intel Corporation 8 Series/C220 Series Chipset Family PCI Express Root Port #3 [8086:8c14] (rev d5)
IOMMU group 10
	00:1c.3 PCI bridge [0604]: Intel Corporation 82801 PCI Bridge [8086:244e] (rev d5)
	04:00.0 PCI bridge [0604]: ASMedia Technology Inc. ASM1083/1085 PCIe to PCI Bridge [1b21:1080] (rev 03)
IOMMU group 11
	00:1d.0 USB controller [0c03]: Intel Corporation 8 Series/C220 Series Chipset Family USB EHCI #1 [8086:8c26] (rev 05)
IOMMU group 12
	00:1f.0 ISA bridge [0601]: Intel Corporation Z87 Express LPC Controller [8086:8c44] (rev 05)
	00:1f.2 SATA controller [0106]: Intel Corporation 8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] [8086:8c02] (rev 05)
	00:1f.3 SMBus [0c05]: Intel Corporation 8 Series/C220 Series Chipset Family SMBus Controller [8086:8c22] (rev 05)
IOMMU group 13
	03:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 11)

Using vfio-pci

https://wiki.archlinux.org/index.php/PCI_passthrough_via_OVMF#Using_vfio-pci

Starting with Linux 4.1, the kernel includes vfio-pci, which is functionally similar to pci-stub with a few added bonuses, such as switching devices into their D3 state when they are not in use. If your system supports it, which you can try by running the following command, you should use it. If it returns en error, you will have to rely on pci-stub instead.

Сам PCIe-контроллер пробрасывать не нужно, только видеокарту. Звуковое устройство от видяхи тоже не нужно - у меня постоянно возникали звуковые артефакты (щелчки и искажения, звучит как переполнение буфера при попытке добиться малой задержки), а иной раз звук вообще вырубало. Не исключено что проблема в win10 Insider Preview который я использовал для тестов. Есть подозрение что это проблема всех windows 10, на уровне всей системы были уменьшены буферы для достижения низкой задержки в угоду звуковым программам - https://msdn.microsoft.com/ru-ru/library/windows/hardware/mt298187(v=vs.85).aspx). Update: кажется, дело в каких-то таймингах, в SteamOS тоже проблема со звуком. С изображением всё хорошо.

Проверил работу звука виртуализировав SteamOS.
http://kvm-exp.blogspot.ru/2015/07/SteamOSruninaKVMwithphysicalGPUpassthrough.html
Со звуком проблемы остались.

$ sudo apt-get remove nvidia* -y

$ lspci -nnk| grep NVIDIA | egrep -oe "(\w{4}:\w{4})"
10de:1401
10de:0fba
$ echo "options vfio-pci ids=10de:1401,10de:0fba" | sudo tee /etc/modprobe.d/vfio.conf
options vfio-pci ids=10de:1401,10de:0fba
$ grep vfio /etc/initramfs-tools/modules
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd

$ sudo update-initramfs -u

KSM

Внимание на параметр /sys/kernel/mm/ksm/merge_across_nodes.
TODO: Проверить :)

Huge pages

Problem:

(qemu) qemu-system-x86_64: unable to map backing store for hugepages: Cannot allocate memory
echo 5120 | sudo tee /proc/sys/vm/nr_hugepages

Создаём образ диска VM

$ qemu-img create -f raw -o preallocation=falloc win10.raw 100G

VirtIO в гостевой машине REWRITE

Чтобы Windows смогла увидеть блочное устройство нужны драйверы VirtIO - без них система не увидит дисков. Win10 умеет устанавливать драйвера перед началом установки с ISO-образа. ISO-образы (а также для НГМД) можно найти тут: https://fedoraproject.org/wiki/Windows_Virtio_Drivers#Direct_download

OVMF

http://blog.system76.com/post/139138591598/howto-qemu-w-ubuntu-xenial-host-uefi-guest
https://git.mel.vin/melvin/scripts/tree/master/qemu
https://git.mel.vin/melvin/scripts/blob/master/qemu/windows_usbpass.sh
http://www.tianocore.org/ovmf/
http://www.linux-kvm.org/page/OVMF

$ sudo apt-get install ovmf
cp /usr/share/OVMF/OVMF_VARS.fd win10_ovmf.fd

XBOX 360 usb gamepad and others usb devices

Пробросить сразу все подключённые к компьютеру контроллеры xbox 360 не получилось. Для проброса первого добавляем следующий аргумент к qemu-system-x86_64:

-usbdevice host:045e:028e

Then you can use following command in qemu monitor to add other controllers:

usb_add <host:vendor_id:product_id>

or

usb_add <host:bus.addr>

This command show you usb hierarchy: lsusb --tree or shorterlsusb -t

Refs:

When win10 guest sleep

system_wakeup в qemu-monitor

Запуск виртуалки через QEMU-KVM

qemu-system-x86_64 \
	-serial none \
	-parallel none \
	-nodefaults \
	-nodefconfig \
	-no-user-config \
	-enable-kvm \
	-name Windows \
	-cpu host,kvm=off,hv_vapic,hv_time,hv_relaxed,hv_spinlocks=0x1fff,hv_vendor_id=sugoidesu \
	-smp sockets=1,cores=4,threads=1 \
	-m 8192 \
	-mem-path /dev/hugepages \
	-mem-prealloc \
	-device ich9-usb-uhci3,id=uhci \
	-device usb-ehci,id=ehci \
	-device nec-usb-xhci,id=xhci \
	-machine pc,accel=kvm,kernel_irqchip=on,mem-merge=off \
	-drive if=pflash,format=raw,readonly,file=/usr/share/OVMF/OVMF_CODE.fd \
	-drive if=pflash,format=raw,file=./win10_ovmf.fd \
	-rtc base=localtime,clock=host,driftfix=none \
	-boot order=d \
    -net nic,macaddr=52:54:00:00:00:01,model=virtio,name=net0 \
    -net tap,ifname=tap0,script=no,downscript=no,vhost=on \
	-usbdevice tablet \
	-drive if=virtio,id=drive0,file=./win10.raw,format=raw,cache=none,aio=native \
	-drive file=/media/keeper/homer/isos/Windows10_InsiderPreview_Client_x64_ru-ru_14332.iso,if=ide,id=cd0,media=cdrom,readonly \
	-drive file=./virtio-win.iso,if=ide,id=cd1,media=cdrom,readonly \
	-device vfio-pci,host=01:00.0,addr=09.0,multifunction=on \
	-device vfio-pci,host=01:00.1,addr=09.1 \
	-device usb-host,hostbus=3,hostaddr=6 \
	-usbdevice host:045e:028e

http://www.linux-kvm.org/images/b/b3/01x09b-VFIOandYou-small.pdf
https://wiki.archlinux.org/index.php/QEMU
http://blog.system76.com/tagged/ovmf

LAST STARTS WIN10

Имя интерфейса tap0 - прямо в коде, копипаста опасна и аргументы могут быть неюзабельными, много лишнего. Звук через через PulseAudio.
win10_start.sh

#!/bin/bash

export QEMU_AUDIO_DRV="pa"
modprobe vfio_iommu_type1
qemu-system-x86_64 \
	-serial none \
	-parallel none \
	-nodefaults \
	-nodefconfig \
	-no-user-config \
	-enable-kvm \
	-name Windows \
	-cpu host,kvm=off,hv_vapic,hv_time,hv_relaxed,hv_spinlocks=0x1fff,hv_vendor_id=sugoidesu \
	-smp sockets=1,cores=4,threads=1 \
	-m 8192 \
	-mem-path /dev/hugepages \
	-mem-prealloc \
	-device ich9-usb-uhci3,id=uhci \
	-device usb-ehci,id=ehci \
	-device nec-usb-xhci,id=xhci \
	-machine pc,accel=kvm,kernel_irqchip=on,mem-merge=off \
	-drive if=pflash,format=raw,readonly,file=/usr/share/OVMF/OVMF_CODE.fd \
	-drive if=pflash,format=raw,file=./win10_ovmf.fd \
	-rtc base=localtime,driftfix=slew \
	-boot order=d \
	-net nic,macaddr=52:54:00:00:00:01,model=virtio,name=net0 \
	-net tap,ifname=tap0,script=no,downscript=no,vhost=on \
	-usbdevice tablet \
	-drive if=virtio,id=drive0,file=./win10.raw,format=raw,cache=none,aio=native \
	-drive file=/media/keeper/homer/isos/Windows10_InsiderPreview_Client_x64_ru-ru_14332.iso,if=ide,id=cd0,media=cdrom,readonly \
	-drive file=./virtio-win.iso,if=ide,id=cd1,media=cdrom,readonly \
	-device vfio-pci,host=01:00.0,addr=09.0,multifunction=on \
	-device vfio-pci,host=01:00.1,addr=09.1,multifunction=on \
	-soundhw hda \
	-usbdevice host:045e:028e \
	-device usb-host,hostbus=3,hostaddr=4 \
	-monitor stdio

win10_net.sh (запускаем после старта машины, по идее, можно сделать хук, но лучше всё обернуть в libvirt):

#!/bin/bash

brctl addif virbr0 tap0
ip l set tap0 up

LAST STARTS STEAMOS

Имя интерфейса tap0 - прямо в коде, копипаста опасна и аргументы могут быть неюзабельными, много лишнего. Звук через через hdmi видео-карты (в теории :D).
steam_os_start.sh:

#!/bin/bash


modprobe vfio_iommu_type1
qemu-system-x86_64 \
	-serial none \
	-parallel none \
	-nodefaults \
	-nodefconfig \
	-no-user-config \
	-enable-kvm \
	-name Windows \
	-cpu host,kvm=off,hv_vapic,hv_time,hv_relaxed,hv_spinlocks=0x1fff,hv_vendor_id=sugoidesu \
	-smp sockets=1,cores=4,threads=1 \
	-m 8192 \
	-mem-path /dev/hugepages \
	-mem-prealloc \
	-device ich9-usb-uhci3,id=uhci \
	-device usb-ehci,id=ehci \
	-device nec-usb-xhci,id=xhci \
	-machine pc,accel=kvm,kernel_irqchip=on,mem-merge=off \
	-drive if=pflash,format=raw,readonly,file=/usr/share/OVMF/OVMF_CODE.fd \
	-rtc base=localtime,clock=host,driftfix=none \
	-net nic,macaddr=52:54:00:00:00:01,model=virtio,name=net0 \
	-net tap,ifname=tap0,script=no,downscript=no,vhost=on \
	-usbdevice tablet \
	-boot order=c \
	-drive file=./steamos.raw,if=none,id=drive-virtio-disk0,format=raw,cache=none,aio=native \
	-device virtio-blk-pci,scsi=off,addr=0x7,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=1 \
	-device vfio-pci,host=01:00.0,addr=09.0,multifunction=on \
	-device vfio-pci,host=01:00.1,addr=09.1,multifunction=on \
	-usbdevice host:045e:028e \
	-device usb-host,hostbus=3,hostaddr=6 \
	-monitor stdio

	# -drive if=pflash,format=raw,file=./steamos_ovmf.fd \
	# -drive if=pflash,format=raw,readonly,file=/usr/share/OVMF/OVMF_CODE.fd \
#	-drive if=virtio,id=drive0,file=./steamos.raw,format=raw,cache=none,aio=native \
#	-boot order=d \
#	-drive file=/media/keeper/homer/isos/steamos.iso,if=none,id=drive-ide0-0-0,readonly=on,format=raw \
#	-device ide-cd,bus=ide.0,unit=0,drive=drive-ide0-0-0,id=ide0-0-0,bootindex=1 \

steamos_net.sh (запускаем после старта машины, по идее, можно сделать хук, но лучше всё обернуть в libvirt):

$ cat net_start.sh 
#!/bin/bash

brctl addif virbr0 tap0
ip l set tap0 up

Комментариев нет:

Отправить комментарий