Проброс NVIDIA в виртуальную машину с Windows 10 в KVM с помощью PCI passhrough

Речь пойдёт о «пробросе» в гостевую машину Windows 10 видеокарты. Аппаратное обеспечение:
  • MacPro5,1, Intel(R) Xeon(R) W3565 3.20GHz, 32GB DDR3
  • NVIDIA GeForce GT 1030
Операционная система:
  • Debian GNU/Linux 12 (bookworm)

Шаг 1: Включить IOMMU

В файле /etc/default/grub в конец строки с GRUB_CMDLINE_LINUX_DEFAULT добавить «intel_iommu=on iommu=pt»
  • intel_iommu=on — включает расширения виртуализации Intel для KVM
  • iommu=pt — включает поддержку проброса
Выполнить update-grub
# update-grub
Generating grub configuration file ...
Found background image: /usr/share/images/desktop-base/desktop-grub.png
Found linux image: /boot/vmlinuz-6.1.0-7-amd64
Found initrd image: /boot/initrd.img-6.1.0-7-amd64
Warning: os-prober will not be executed to detect other bootable partitions.
Systems on them will not be added to the GRUB boot configuration.
Check GRUB_DISABLE_OS_PROBER documentation entry.
done

Шаг 2: VFIO и NVIDIA


Большинство типов устройств могут использоваться хостом, а затем передаваться виртуальной машине по требованию, после фактического запуска. С видеокартой так не получится. После того, как хост загружает драйвер для видеокарты и начинает взаимодействовать с ней, уже не получится передать её виртуальной машине. Linux загрузит драйвер для любой подключенной карты, даже если это видеокарта не по умолчанию, поэтому, чтобы обойти это, нужно сообщить ядру Linux хоста, что я намерен использовать карту NVIDIA для виртуальной машины, и это нужно сделать до того, как ядро получит соответствующий драйвер.

Есть несколько способов сделать это. Можно сказать ядру, чтобы оно полностью заблокировало модуль Nouveau. Но вместо этого я сказал ему подождать загрузки модуля Nouveau до тех пор, пока карта уже не будет инициализирована для использования VFIO passhrough. Это остановит Nouveau от попыток что-либо с этим сделать. Поскольку карта NVIDIA также использует модуль Intel HDA для вывода звука по HDMI, необходимо сделать то же самое с Intel HDA.

Чтобы сделать это, необходимо определить идентификаторы PCI для графического процессора:
# lspci -nnk | grep -i nvidia -A3
05:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP108 [GeForce GT 1030] [10de:1d01] (rev a1)
	Subsystem: Micro-Star International Co., Ltd. [MSI] GP108 [GeForce GT 1030] [1462:8c98]
	Kernel driver in use: nouveau
	Kernel modules: nouveau
05:00.1 Audio device [0403]: NVIDIA Corporation GP108 High Definition Audio Controller [10de:0fb8] (rev a1)
	Subsystem: Micro-Star International Co., Ltd. [MSI] GP108 High Definition Audio Controller [1462:8c98]
	Kernel driver in use: nouveau
	Kernel modules: snd_hda_intel
В данном случае идентификатор графического процессора — «10de:1d01«, а звуковой выход HDMI — «10de:0fb8″. Обрати внимание на часть под графическим процессором, где написано «Kernel driver in use: nouveau». Если все сделать правильно, после дальнейших изменений должно измениться.
Чтобы пометить карту для использования VFIO, сделай так:
# echo -e 'softdep nouveau pre: vfio-pci\nsoftdep snd_hda_intel pre: vfio-pci\noptions vfio-pci ids=10de:1d01,10de:0fb8' | tee -a /etc/modprobe.d/vfio.conf
softdep nouveau pre: vfio-pci
softdep snd_hda_intel pre: vfio-pci
options vfio-pci ids=10de:1d01,10de:0fb8
Затем:
# update-initramfs -u
update-initramfs: Generating /boot/initrd.img-6.1.0-7-amd64
I: The initramfs will attempt to resume from /dev/sda3
I: (UUID=70a5eab5-08c1-4ab3-aa0b-a505c17ea980)
I: Set the RESUME variable to override this.
И перезагрузи:
# reboot
Чтобы проверить, все ли работает правильно:
# lspci -nnk | grep -i nvidia -A3
05:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP108 [GeForce GT 1030] [10de:1d01] (rev a1)
	Subsystem: Micro-Star International Co., Ltd. [MSI] GP108 [GeForce GT 1030] [1462:8c98]
	Kernel driver in use: vfio-pci
	Kernel modules: nouveau
05:00.1 Audio device [0403]: NVIDIA Corporation GP108 High Definition Audio Controller [10de:0fb8] (rev a1)
	Subsystem: Micro-Star International Co., Ltd. [MSI] GP108 High Definition Audio Controller [1462:8c98]
	Kernel driver in use: vfio-pci
	Kernel modules: snd_hda_intel
Под устройствами NVIDIA, должно быть «Kernel driver in use: vfio-pci»

Шаг 3: Создать виртуальную машину Windows ! без проброса графического процессора !

Можно использовать «virt-manager» и настроить обычную виртуальную машину Windows 10 с использованием видеокарты QXL по умолчанию, установить для параметра встроенного ПО значение «UEFI». Установить Windows, пока что без проброса графической карты, затем выключить виртуальную машину.

Шаг 4: Проброс NVIDIA

В «virt-manager» открыть настройки ВМ, нажать «Добавить оборудование», затем «PCI устройство узла». Повторить процесс для аудиоконтроллера NVIDIA.
На данном этапе если попытаться запустить виртуальную машину, и она запустится, скорее всего произойдёт следующее: Windows установит драйвер NVIDIA, но карта по-прежнему не будет работать. В диспетчере устройств, карта NVIDIA будет помечена маленьким желтым значком предупреждения, а при открытии свойств устройства отобразится загадочная ошибка «Код 43». Если совсем не запустится, то смотри «Шаг 4.2»

Шаг 4.1: Ошибка Windows Code 43

Эта ошибка, по-видимому, возникает из-за того, что драйвер NVIDIA понимает, что он запущен внутри виртуальной машины, и отключается сам. Нужно «скрыть» факт наличия виртуальной машины от драйвера. В KVM есть механизм для этого, но он не представлен в `virtual-manager`, поэтому необходимо будет отредактировать XML-конфигурацию для виртуальной машины вручную:
# virsh edit win10
— win10 — это имя ВМ
необходимо добавить:
  • внутри тега <hyperv>: <vendor_id state=’on’ value=’10de1d011462‘/>
    10de1d011462— vendor_id, произвольное 12-значное шестнадцатеричное число
  • внутри тега <kvm>: <hidden state=’on’/>
  • внутри тега <features>: <ioapic driver=’kvm’/>

Результат должен выглядеть примерно так:
# virsh dumpxml win10 | sed -n '/<features/,/<\/features/p'
<features>
  <acpi/>
  <apic/>
  <hyperv mode='custom'>
    <relaxed state='on'/>
    <vapic state='on'/>
    <spinlocks state='on' retries='8191'/>
    <vendor_id state='on' value='10de1d011462'/>
  </hyperv>
  <kvm>
    <hidden state='on'/>
  </kvm>
  <vmport state='off'/>
  <ioapic driver='kvm'/>
</features>
Теперь, драйвер NVIDIA должен работать! Вероятно, Windows по умолчанию будет использовать графический процессор в качестве основной карты, что означает, что приглашение для входа в Windows, скорее всего, появится на дисплее, подключенном к видеокарте, а не на дисплее QXL, который можно увидеть в `virt-manager`. В дальнейшем QXL можно либо удалить из ВМ, либо отключить в диспетчере устройств

Шаг 4.2: ВМ не запускается: Failed to set iommu for container: Operation not permitted

Если во время запуска появляется ошибка:
# virsh start win10
ошибка: Failed to start domain 'win10'
ошибка: внутренняя ошибка: QEMU неожиданно завершил работу монитора: 2023-04-28T09:54:20.363311Z kvm: -device {"driver":"vfio-pci","host":"0000:05:00.0","id":"hostdev0","bus":"pci.4","addr":"0x0"}: vfio 0000:05:00.0: failed to setup container for group 43: Failed to set iommu for container: Operation not permitted
Выполняю:
# dmesg | egrep -i allow_unsafe_interrupts
[  163.327204] vfio_iommu_type1_attach_group: No interrupt remapping support.  Use the module param "allow_unsafe_interrupts" to enable VFIO IOMMU support on this platform
Лечение:
добавить к GRUB_CMDLINE_LINUX_DEFAULT pci=noaer vfio_iommu_type1.allow_unsafe_interrupts=1
Должно получится что-то типа:
egrep GRUB_CMDLINE_LINUX_DEFAULT /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt pci=noaer vfio_iommu_type1.allow_unsafe_interrupts=1"
После чего:
# update-grub
# reboot
После перезагрузки, должно работать.

[Setting up KVM with GPU passthrough in Debian Buster](https://gist.github.com/davesilva/445276f9157e7cb3a4f6ed2fe852b340 )

[Debian User Forums [Solved] VGA Passthrough problem](https://wiki.debian.org/VGAPassthrough#Host_OS_Installation )
Рубрики: *nix, Debian, KVM, виртуализация | 0 | 1 931 | Распечатать эту статью