Проброс видеокарты в гостевую ОС из гипервизора KVM с помощью технологии VFIO

Вступление


В статье описывается способ проброса физических устройств из гипервизора KVM в гостевую ОС с помощью технологии VFIO, реализованной в linux kernel 3.9.*.
Материал не является руководством к действию (прим. туториалом). Все описанные инструкции вы производите на свой страх и риск.

Эксперимент выполняется под ОС Ubuntu 13.10:

  • kernel: 3.11.0-15-generic
  • qemu: 1.5.0
  • seabios: 1.7.3


Аппаратная часть стенда:

  • мат. плата: AMD990FX
  • процессор: AMD FX-8120
  • опер. память: DDR3 PC3-14900
  • видеокарта: ATI RADEON HD 7750
  • видеокарта (гость): NVIDIA GTX560-TI


Видеокарта для гостевой системы и хоста, может быть, предположительно, любая (NVIDIA, ATI RADEON).
Материнская плата должна иметь блок управления памятью ввода/вывода (IOMMU) — технология AMD-Vi или VT-d.
Если используется процессор Intel, то он также должен поддерживать VT-d.
Независимо от выбранной платформы в биосе материнской платы должны быть реализованы IVRS/DMAR таблицы.

Подготовка


Настоятельно рекомендуется обновить биос мат. платы с сайта производителя перед началом эксперимента.

Проверяем поддержку технологии проброса.
$ dmesg | grep AMD-Vi
[    1.279788] AMD-Vi: Found IOMMU at 0000:00:00.2 cap 0x40
[    1.279790] AMD-Vi: Interrupt remapping enabled
[    1.292879] AMD-Vi: Lazy IO/TLB flushing enabled


Включаем модули в ядре.
$ cat /etc/modules
# /etc/modules: kernel modules to load at boot time.
lp
rtc
pci_stub
vfio
vfio_iommu_type1
vfio_pci
#vfio_pci_vga  (For now, this component is in the stock Ubuntu kernel.)
kvm
kvm_amd

$ sudo update-initramfs -u


Отключаем пробрасываемые устройства (для удобства также проброшены порты usb контроллера).
$ lspci -nn | grep NVIDIA
03:00.0 VGA compatible controller [0300]: NVIDIA Corporation GF114 [GeForce GTX 560 Ti] [10de:1200] (rev a1)
03:00.1 Audio device [0403]: NVIDIA Corporation GF114 HDMI Audio Controller [10de:0e0c] (rev a1)

$ cat /etc/default/grub | grep GRUB_CMDLINE_LINUX_DEFAULT
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash pci-stub.ids=10de:1200,10de:0e0c,1002:4397,1002:4396"

$ sudo update-grub


После перезагрузки должно получиться:
$ dmesg | grep pci-stub
[    3.163062] pci-stub: add 10DE:1200 sub=FFFFFFFF:FFFFFFFF cls=00000000/00000000
[    3.163088] pci-stub 0000:03:00.0: claimed by stub
[    3.163100] pci-stub: add 10DE:0E0C sub=FFFFFFFF:FFFFFFFF cls=00000000/00000000
[    3.163116] pci-stub 0000:03:00.1: claimed by stub
[    3.163124] pci-stub: add 1002:4397 sub=FFFFFFFF:FFFFFFFF cls=00000000/00000000
[    3.163136] pci-stub: add 1002:4396 sub=FFFFFFFF:FFFFFFFF cls=00000000/00000000


Создаем скрипт для подключения устройства к VFIO-PCI.
$ cat /usr/bin/vfio-bind
#!/bin/bash

modprobe vfio-pci

for dev in "$@"; do
        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
done

$ sudo chmod 755 /usr/bin/vfio-bind


И добавляем его в автозапуск (ключи берем из вызова lspci — рассматривалось выше).
$ cat /etc/rc.local
#!/bin/sh -e

/usr/bin/vfio-bind 0000:03:00.0 0000:03:00.1 0000:00:12.0 0000:00:12.2
exit 0


Небольшая автоматизация процесса
Внимание: задать ваши параметры!

$ cat pass.sh
#!/bin/sh

#configs
modules="pci_stub;vfio;vfio_iommu_type1;vfio_pci;kvm;kvm_amd"
grub="quiet splash pci_stub.ids=10de:1200,10de:0e0c,1002:4397,1002:4396"
autorun="/usr/bin/vfio-bind 0000:03:00.0 0000:03:00.1 0000:00:12.0 0000:00:12.2"

#functions
split() {
	#$1 - file, $2 - param
	arr=$(echo $2 | tr ";" "\n")

	for x in $arr
	do
	    echo $x >> $1
	done
}

replaceParam() {
	#$1 - file, $2 - param, $3 - value
	cur_val=`cat $1 | grep $2`
	sed "s/$cur_val/$2=\"$3\"/g" -i $1
}

autorunAdd() {
	#$1 - param
	str='$i \'"$1"'\n'
	sed -i -e "$str" /etc/rc.local
}

pause() {
	read -p "$1" -n1 -s
	echo
}

#info virtualization
dmesg | grep AMD-Vi
pause 'Press any key to continue or CTRL-C to exit...'

#modules load
split '/etc/modules' "$modules"
update-initramfs -u

#grub config
replaceParam '/etc/default/grub' 'GRUB_CMDLINE_LINUX_DEFAULT' "$grub"
update-grub

autorunAdd "$autorun"

$ cat vfio-bind
#!/bin/bash

modprobe vfio-pci

for dev in "$@"; do
        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
done

$ sudo cp vfio-bind /usr/bin/
$ sudo chmod 755 /usr/bin/vfio-bind
$ sudo chmod 755 pass.sh
$ sudo bash pass.sh



Запуск


В качестве гостевой ОС используется WINDOWS 7 с паравиртуальными драйверами VIRTIO. В соответствии с этим выбрано оборудование виртуальной машины.

$ cat win7_vfio_test.sh
#! /bin/sh
IS_TAP0_EXISTS=`ifconfig | grep -c tap0`
if [ $IS_TAP0_EXISTS = 0 ] ; then
    sudo tunctl -t tap0 && sudo ifconfig tap0 0.0.0.0 promisc up && sudo brctl addif br0 tap0 && echo 'Success: tap0 interface created.' || echo 'Error: tap0 interface is not created.'
else
    echo 'Success: tap0 interface already exists.'
fi

#init kvm-qemu
sudo qemu-system-x86_64 \
-boot menu=on \
-enable-kvm \
-M q35 \
-m 1024 \
-cpu host \
-rtc base=localtime \
-smp 1,sockets=1,cores=1,threads=1 \
-bios /usr/share/qemu/bios.bin \
-acpitable file=/usr/share/seabios/q35-acpi-dsdt.aml \
-device ioh3420,bus=pcie.0,addr=1c.0,multifunction=on,port=1,chassis=1,id=root \
-device ahci,bus=pcie.0,id=ahci \
-device virtio-balloon-pci,id=balloon0,bus=pcie.0,addr=0x6 \
-drive file='/dev/sdc6',if=none,id=drive-virtio-disk0,format=raw -device virtio-blk-pci,scsi=off,bus=pcie.0,addr=0x5,drive=drive-virtio-disk0,id=virtio-disk0,bootindex=2 \
-drive file='windows7.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,bootindex=1 \
-drive file='virtio-win-0.1-74.iso',if=none,id=drive-ide0-2-0,readonly=on,format=raw -device ide-cd,bus=ide.2,unit=0,drive=drive-ide0-2-0,id=ide0-2-0 \
-netdev tap,ifname=tap0,id=hostnet0,script=no,downscript=no -device virtio-net-pci,netdev=hostnet0,mac=52:54:00:26:7F:96,id=net0 \
-device vfio-pci,host=00:12.0,bus=pcie.0 \
-device vfio-pci,host=00:12.2,bus=pcie.0 \
-device vfio-pci,host=03:00.0,bus=root,addr=00.0,multifunction=on,x-vga=on \
-device vfio-pci,host=03:00.1,bus=root,addr=00.1 \
-vga none \
-nographic

#-vnc 127.0.0.1:0


В ВМ проброшен раздел жесткого диска -drive file=/dev/sdc6.
Начальная установка выполнялась без проброса физических устройств (можно использовать -vnc 127.0.0.1:0 или стандартную консоль).
Аргументы -vga none -nographic следует добавить при пробросе компонентов видеокарты (-device vfio-pci).

Share post

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 28

  • UFO just landed and posted this here
      0
      Производительность карты должна быть около 99% от нормальной.
        0
        Поставил Win8 в гостя с пробросом Radeon 7970, работаю с пакетом Adobe (PS, AE, PR). Производительность изумительная. Изначально на машине стояла полноценная винда. Бенчмарки не гонял, но по ощущениям — никакой разницы. Слабое место — диски, которые и в гипервизоре не особо хорошо себя чувствуют. А вот если пробросить раздел с SSD — будет шикарно.
        +1
        Добавлю, что пробросится не каждая карта, зависит от ее биоса. У меня например Gigabyte 7870 пробросилась, но драйвера корректно не работают. Похожая статья для Archlinux
        Могу выложить XML файл конфигурации для libvirt с проброшенной видеокартой.
          0
          > Добавлю, что пробросится не каждая карта, зависит от ее биоса.
          А можно поподробнее? Пробрасывали 5 радеонов и чуть меньше нвидий, никаких проблем не возникло. Вы сами столкнулись с этой проблемой?
            0
            Да, с проблемой столкнулся сам, ОС Archlinux, карта Gigabyte 7870. Если пробрасывать ее без биоса, то не работает вообще. Если подпихнуть ей при пробросе rom файл с биосом другой версии, то работает, но драйвера от AMD не работают. Пока не пробовал перепрошивать карту (лень).
            0
            Драйвера не будут корректно работать, если:
            1) В системе два радеона и на гипервизоре стоит каталист
            2) В системе два радеона и они установлены в запараллеленные порты pci-e
            +2
            Если кого интересует, некоторые карты nVidia, которые просто так не пробрасываются, можно немного модифицировать, превратив GTX в Tesla/Quadro и модифицированная карта уже пробросится без проблем.
              0
              Автор, а почему Вы сделали:
              -cpu Opteron_G4,+perfctr_nb,+perfctr_core,+topoext,+nodeid_msr,+lwp,+wdt,+skinit,+ibs,+osvw,+cr8legacy,+extapic,+cmp_legacy,+fxsr_opt,+mmxext,+osxsave,+monitor,+ht,+vme

              вместо
              -cpu host
              Из каких соображений?
                0
                Все верно, для проброса всех возможностей процессора в гость достаточно указать
                -cpu host
                

                Обозначенный вариант выбран из соображений совместимости при тестировании. Исправил на более предпочтительный.
                0
                А нет ещё технологий виртуализации, которые позволяли бы пробрасывать карту туда-сюда между несколькими запущенными гестами, или хотя бы между хостом и гестом?

                Хотелось бы иметь одновременно запущенные Windows и Linux дома с возможностью при переключении между ними такого вот переброса…
                  0
                  Так это уже возможно. В гостевой винде необходимо «извлечь» видеоустройство и его можно будет использовать дальше.
                    0
                    Хм, а не расскажете поподробней?
                    0
                    Если речь идет об одной видеокарте, которую предполагается использовать между хостом и гостем или гостями, то теоретически такое переключение возможно.
                    Для реализации подобного следует обратить внимание на технологию SPICE. Она позволит на хост-машине под управлением Linux эмулировать видеокарту, отключив физическую. После вы сможете пробросить ее в гостя.

                    Одновременное использование видеокарты невозможно, поэтому потребуется извлечь ее из гостя тем или иным способ.

                    Далее, если вы захотите вернуть видеокарту в хост-систему или перебросить в другой хост, то действовать вы будете вслепую, поэтому у вас есть следующие пути решения:
                    — создать демона для прослушки процесса и выполнения операций включения устройства обратно в хост или запуска другого хоста с видеокартой в автоматическом неконтролируемом режиме.
                    — удаленное администрирование по любому доступному протоколу (например, ssh, http, vnc) хост-машины с другой машины с целью выполнения указанных ранее действий.
                      0
                      Ну так это можно совместить — сделать пару скриптов на хосте и гесте. В первом гест связывается например по ssh с хостом, отключает свою видеокарту и включает на хосте. Во втором — наоборот. Скорее вопрос как практически делать это переключение «на лету» без перезапусков хоста и/или геста. Просто нигде ничего про это не сказано.
                        0
                        VFIO — Virtual Function I/O — как раз для этого и предназначен. Именно поэтому мы и пробрасываем устройство через этот модуль. Поэтому чисто практически каждый решает для себя сам, но необходимо, чтобы гость рапортовал о завершении использования устройства (видеокарты в том числе), а для этого в госте нужно устройство «извлечь». То есть извлекаем либо гипервизором принудительно и передаем управление другому гостю, либо в самом госте завершаем использование, а в другом начинаем.
                          0
                          Вопрос а как из геста «извлечь». Принудительно это слишком уж жёстко. Скажем гест — Win7, хост Linux — и как сделать извлечение из Win7?
                            0
                            С помощью виндового трея, ровно так же, как извлекаете usb устройство. Необходимо заметить, что технология вцелом еще крайне сырая. То ли vfio, то ли поддержка со стороны kvm. У меня запущено чуть более 20 гостей, которые постоянно трудятся с графикой и не только. Извлечение частенько вешает виртуалку наглухо. Бывает не вешает, но я отказался от использования этой фичи. Де факто, для меня это пока абстрактная альфа-версия функционала.
                              0
                              А вот чем с ОС технически отличается «извлекаемое» устройство от «не извлекаемого»? А то я много раз видел, что в виртуалке сетевуху или там жёсткий диск можно «извлечь», а на обычной машине — нельзя, но как-то ни разу не разбирался, почему так.
                                0
                                Ответ на ваш вопрос — virtio драйвер. Я довольно недавно в этой теме, не могу утверждать, но насколько я успел понять в 90 процентах случаев для проброса или эмуляции устройств используется virtio. В тонкости реализации я не вдавался, поэтому пояснить более развернуто не могу. Если коротко — драйвер устройства дает понять ОС, что устройство что-то типа Plug&Play.
                                0
                                А с помощью командной строки извлечь нельзя?
                                  0
                                  Гуглите. Я так часто делаю ;)
                      0
                      Эээ, есть глупый вопрос.
                      А монитора в таком случае тоже нужно два? А если он один, то его нужно переключать на вторую видеокарту при включении гостя?
                        0
                        Возможно кто-то задавался вопросом. Пробросить встроенную видео на второй вход монитора.
                        Видео Intel HD Graphics Haswell способная работать одновременно с дискретной NVidia 550 Ti.
                        Пока ничего не выходит, возможно у кого есть подобный опыт использования.
                          0
                          Для начала убедитесь, что все необходимые технологии у вас присутствуют в системе. Во вторых, есть большая вероятность, что проброс видеокарт реализован более-менее для nvidia, ati, maxtor, поэтому для начала попробуйте пробросить вторую видеокарту, а не intel. И в третьих, проверьте, на какой видеокарте работает ваша система, т.к. карта для проброса должна быть «отключена».
                            0
                            К сожалению вопрос снят, физически мой процессор (самый недорогой из Хасвелов BX80646G3420) не поддерживает технологию VT-d. Ближайший кто держит стоит почти в три раза дороже, хотя даже меньше по гигагерцам :(. Сейчас начал копать в любом другом направлении, которое даст возможность отказаться от отдельного раздела с виндой навсегда. Проблема в возможности запускать ArcheAge под линуксом. Пока не решена. Если есть идеи, буду очень благодарен.
                              0
                              Попробуйте это wine или откажитесь от использования ПО, которое предназначено для запуска под ОС отличной от Linux, коли используете последнюю.
                                –1
                                Wine к сожалению не подходит. Как не крути, а это всего-лиш набор библиотек для работы, а не полноценное окружение. Отказ тоже не приемлем по причинам указанным выше. Поиск продолжается.

                        Only users with full accounts can post comments. Log in, please.