Вопрос или проблема
У меня есть ноутбук Dell Latitude E6530 с графикой Optimus (Intel/Nvidia), и я пытаюсь выполнить passthrough dGPU, о котором я читал множество статей и форумов, чтобы преодолеть это препятствие. После долгих усилий с конфигурациями и несовпадающими пакетами, я, наконец, заставил загружаться модуль vfio_pci при загрузке и привязал драйвер vfio-pci к моей dGPU и ее аудиоустройству. Однако я не могу избавиться от печально известной Ошибки 43, которая мешает моей dGPU действительно загружаться в виртуальной машине. Я пробовал обходные пути для vendor_id в XML, обходной путь virsh-patcher для ошибки 43, отключение функций hyperv в XML и различные другие изменения в XML, о которых сообщалось, что они помогли другим решить эту проблему. В итоге я не добился успеха. Я также извлек vBIOS своей dGPU с помощью инструмента VBiosFinder на Github и добавил его в свой XML, однако после этого он больше не загружался, даже с QXL в качестве основного видео драйвера. Я приведу здесь выводы для информации, и при необходимости могу предоставить больше.
lspci -nnk -s 1:
01:00.0 VGA совместимый контроллер [0300]: NVIDIA Corporation GF108GLM [NVS 5200M] [10de:0dfc] (rev a1)
Подсистема: Dell GF108GLM [NVS 5200M] [1028:1535]
Драйвер ядра в использовании: vfio-pci
Ядровые модули: nouveau
01:00.1 Аудиоустройство [0403]: NVIDIA Corporation GF108 High Definition Audio Controller [10de:0bea] (rev a1)
Подсистема: Dell GF108 High Definition Audio Controller [1028:1535]
Драйвер ядра в использовании: vfio-pci
Ядровые модули: snd_hda_intel
lsmod|grep vfio
vfio_pci 57344 0
irqbypass 16384 2 vfio_pci,kvm
vfio_virqfd 16384 1 vfio_pci
vfio_iommu_type1 36864 0
vfio 36864 2 vfio_iommu_type1,vfio_pci
/etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on,igfx_off iommu=pt pcie_acs_override=downstream vfio-pci.ids=10de:0dfc,10de:0bea apparmor=1 security=apparmor udev.log_priority=3"
/etc/mkinitcpio.conf
MODULES="vfio vfio_iommu_type1 vfio_pci vfio_virqfd vhost-net"
FILES=""
HOOKS="base udev autodetect modconf block keyboard keymap filesystems"
journalctl -b|grep -i vfio
19 апр. 18:54:41 lions-den kernel: Командная строка: BOOT_IMAGE=/boot/vmlinuz-5.4-x86_64 root=UUID=9aadff70-70e9-4adf-ac3c-e9b737d68ee4 rw quiet intel_iommu=on,igfx_off iommu=pt pcie_acs_override=downstream vfio-pci.ids=10de:0dfc,10de:0bea apparmor=1 security=apparmor udev.log_priority=3
19 апр. 18:54:41 lions-den kernel: Командная строка ядра: BOOT_IMAGE=/boot/vmlinuz-5.4-x86_64 root=UUID=9aadff70-70e9-4adf-ac3c-e9b737d68ee4 rw quiet intel_iommu=on,igfx_off iommu=pt pcie_acs_override=downstream vfio-pci.ids=10de:0dfc,10de:0bea apparmor=1 security=apparmor udev.log_priority=3
19 апр. 18:54:41 lions-den kernel: VFIO - версия мета-драйвера пользовательского уровня: 0.3
19 апр. 18:54:41 lions-den kernel: vfio-pci 0000:01:00.0: vgaarb: изменены VGA декодирования: старые декодирования=io+mem, декодирования=io+mem: владеет=none
19 апр. 18:54:41 lions-den kernel: vfio_pci: добавлено [10de:0dfc[ffffffff:ffffffff]] класс 0x000000/00000000
19 апр. 18:54:41 lions-den kernel: vfio_pci: добавлено [10de:0bea[ffffffff:ffffffff]] класс 0x000000/00000000
19 апр. 18:54:45 lions-den kernel: vfio-pci 0000:01:00.0: vgaarb: изменены VGA декодирования: старые декодирования=io+mem, декодирования=io+mem: владеет=none
19 апр. 18:54:45 lions-den kernel: vfio-pci 0000:01:00.0: optimus возможности: включено, статус динамического питания, поддерживается кодек hda bios
sudo virsh dumpxml win10
<domain type="kvm" xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
<name>win10</name>
<uuid>6d92b905-bb5e-48cf-92da-ae1584aa12a3</uuid>
<metadata>
<libosinfo:libosinfo xmlns:libosinfo="http://libosinfo.org/xmlns/libvirt/domain/1.0">
<libosinfo:os id="http://microsoft.com/win/10"/>
</libosinfo:libosinfo>
</metadata>
<memory unit="KiB">10485760</memory>
<currentMemory unit="KiB">10485760</currentMemory>
<vcpu placement="static" current="7">8</vcpu>
<cputune>
<vcpupin vcpu='0' cpuset="0"/>
<vcpupin vcpu='1' cpuset="4"/>
<vcpupin vcpu='2' cpuset="1"/>
<vcpupin vcpu='3' cpuset="5"/>
<vcpupin vcpu='4' cpuset="2"/>
<vcpupin vcpu='5' cpuset="6"/>
<vcpupin vcpu='6' cpuset="3"/>
</cputune>
<os>
<type arch="x86_64" machine="pc-q35-4.2">hvm</type>
<loader readonly='yes' type="pflash">/usr/share/ovmf/x64/OVMF_CODE.fd</loader>
<nvram>/var/lib/libvirt/qemu/nvram/win10_VARS.fd</nvram>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<hyperv>
<relaxed state="on"/>
<vapic state="on"/>
<spinlocks state="on" retries="8191"/>
<vendor_id state="on" value="1234567890ab"/>
</hyperv>
<kvm>
<hidden state="on"/>
</kvm>
<vmport state="off"/>
<ioapic driver="kvm"/>
</features>
<cpu mode="host-passthrough" check='none'>
<topology sockets="1" cores="4" threads="2"/>
</cpu>
<clock offset="localtime">
<timer name="rtc" tickpolicy='catchup'/>
<timer name="pit" tickpolicy='delay'/>
<timer name="hpet" present="no"/>
<timer name="hypervclock" present="yes"/>
</clock>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>destroy</on_crash>
<pm>
<suspend-to-mem enabled='no'/>
<suspend-to-disk enabled='no'/>
</pm>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type="file" device="disk">
<driver name="qemu" type="raw"/>
<source file="/home/rebel/libvirt/images/win10.img"/>
<target dev='vda' bus="virtio"/>
<address type="pci" domain='0x0000' bus="0x08" slot="0x00" function='0x0'/>
</disk>
<disk type="file" device="cdrom">
<driver name="qemu" type="raw"/>
<source file="/home/rebel/ISOs/Win10_1909_English_x64.iso"/>
<target dev='sdb' bus="sata"/>
<readonly/>
<address type="drive" controller="0" bus="0" target="0" unit="1"/>
</disk>
<disk type="file" device="cdrom">
<driver name="qemu" type="raw"/>
<source file="/home/rebel/ISOs/virtio-win-0.1.173.iso"/>
<target dev='sdc' bus="sata"/>
<readonly/>
<address type="drive" controller="0" bus="0" target="0" unit="2"/>
</disk>
<controller type="usb" index='0' model="qemu-xhci" ports="15">
<address type="pci" domain='0x0000' bus="0x03" slot="0x00" function='0x0'/>
</controller>
<controller type="sata" index='0'>
<address type="pci" domain='0x0000' bus="0x00" slot="0x1f" function='0x2'/>
</controller>
<controller type="pci" index='0' model="pcie-root"/>
<controller type="pci" index='1' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="1" port="0x10"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x0' multifunction='on'/>
</controller>
<controller type="pci" index='2' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="2" port="0x11"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x1'/>
</controller>
<controller type="pci" index='3' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="3" port="0x12"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x2'/>
</controller>
<controller type="pci" index='4' model="pcie-to-pci-bridge">
<model name="pcie-pci-bridge"/>
<address type="pci" domain='0x0000' bus="0x01" slot="0x00" function='0x0'/>
</controller>
<controller type="pci" index='5' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="5" port="0x13"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x3'/>
</controller>
<controller type="pci" index='6' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="6" port="0x14"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x4'/>
</controller>
<controller type="pci" index='7' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="7" port="0x15"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x5'/>
</controller>
<controller type="pci" index='8' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="8" port="0x16"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x6'/>
</controller>
<controller type="pci" index='9' model="pcie-root-port">
<model name="pcie-root-port"/>
<target chassis="9" port="0x17"/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x02" function='0x7'/>
</controller>
<controller type="virtio-serial" index='0'>
<address type="pci" domain='0x0000' bus="0x05" slot="0x00" function='0x0'/>
</controller>
<interface type="network">
<mac address="52:54:00:ad:bc:10"/>
<source network='default'/>
<model type="virtio"/>
<address type="pci" domain='0x0000' bus="0x02" slot="0x00" function='0x0'/>
</interface>
<channel type="spicevmc">
<target type="virtio" name="com.redhat.spice.0"/>
<address type="virtio-serial" controller="0" bus="0" port="1"/>
</channel>
<input type="tablet" bus="usb">
<address type="usb" bus="0" port="1"/>
</input>
<input type="mouse" bus="ps2"/>
<input type="keyboard" bus="ps2"/>
<graphics type="spice" autoport="yes">
<listen type="address"/>
<image compression='off'/>
<gl enable="no" rendernode="/dev/dri/by-path/pci-0000:00:02.0-render"/>
</graphics>
<sound model="ich9">
<address type="pci" domain='0x0000' bus="0x00" slot="0x1b" function='0x0'/>
</sound>
<video>
<model type="qxl" ram='65536' vram='65536' vgamem='16384' heads="1" primary='yes'/>
<address type="pci" domain='0x0000' bus="0x00" slot="0x01" function='0x0'/>
</video>
<hostdev mode="subsystem" type="pci" managed='yes'>
<source>
<address domain='0x0000' bus="0x01" slot="0x00" function='0x0'/>
</source>
<rom bar="on" file="/home/rebel/libvirt/vbios_10de_0dfc.rom"/>
<address type="pci" domain='0x0000' bus="0x07" slot="0x00" 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="0x09" slot="0x00" function='0x0'/>
</hostdev>
<watchdog model="i6300esb" action='shutdown'>
<address type="pci" domain='0x0000' bus="0x04" slot="0x05" function='0x0'/>
</watchdog>
<memballoon model="virtio">
<address type="pci" domain='0x0000' bus="0x06" slot="0x00" function='0x0'/>
</memballoon>
</devices>
<qemu:commandline>
<qemu:arg value="-audiodev"/>
<qemu:arg value="pa,id=snd0,server=unix:/tmp/pulse-socket"/>
</qemu:commandline>
</domain>
Одной из вещей, которой может не хватать, является фальшивая запись в ACPI таблице батареи. Смотрите здесь для деталей:
https://github.com/jscinoz/optimus-vfio-docs/issues/2
Драйвер Nvidia выполняет различные проверки, чтобы определить, заплатил ли клиент достаточно за свою GPU (т.е. купил Quadro) перед тем, как ему будет разрешено запускать эту GPU в виртуальной машине. Ранее они проверяли только наличие признаков гипервизора, но для графических процессоров серии 10xx и 20xx они также проверяют наличие батареи.
Я сталкивался с той же проблемой, но это исправило её для меня.
Если у вас все еще есть код 43, проверьте dmesg на наличие ошибок резервирования памяти после запуска виртуальной машины, если у вас есть аналогичные ошибки, это может быть причиной:
$ dmesg | grep BAR
vfio-pci 0000:09:00.0: BAR 3: cannot reserve [mem 0xf0000000-0xf1ffffff 64bit pref]
Узнайте, к какому PCI мосту подключена ваша графическая карта. Это даст фактическую иерархию устройств:
$ lspci -t
Перед запуском ВМ выполните следующие команды, заменив ID на фактические из предыдущего вывода.
# echo 1 > /sys/bus/pci/devices/0000\:00\:03.1/remove
# echo 1 > /sys/bus/pci/rescan
Например, мой lspci -t
вернул следующую информацию, указывая, что моя GPU подключена к PCI мосту 0000:00:03.1. Измените вышеуказанную команду в соответствии с вашим PCI мостом, если это применимо.
> -[0000:00]-+-00.0
> +-00.2
> +-01.0
> +-01.1-[01]----00.0
> +-01.3-[03-25]--+-00.0
> | +-00.1
> | \-00.2-[20-25]--+-00.0-[21]--
> | +-01.0-[22]----00.0
> | \-04.0-[25]--+-00.0
> | \-00.1
> +-02.0
> +-03.0
> +-03.1-[26]--+-00.0 <--- Моя GPU на PCI адресе 26
> | +-00.1
> | +-00.2
> | \-00.3
Ответ или решение
Ошибка 43, возникающая при передаче GPU NVIDIA через KVM, является распространённой проблемой, которую многие пользователи сталкиваются при работе с виртуализацией и графическими картами NVIDIA, особенно в конфигурациях с Optimus, таких как ваша Dell Latitude E6530. Давайте подробно рассмотрим этот вопрос и возможные способы его решения.
Анализ проблемы
Ошибка 43 связана с определёнными проверками, которые драйверы NVIDIA выполняют на этапе загрузки. NVIDIA использует эти проверки, чтобы определить, запущена ли карта в виртуализированной среде, и если это так, драйвер может не разрешить использование GPU, выдавая ошибку 43. Это особенно актуально для ноутбуков с дублирующим графическим процессором (dGPU) и интегрированной графикой (iGPU).
Шаги для устранения ошибки 43
-
Проверка конфигурации VFIO:
Убедитесь, что модулиvfio_pci
,irqbypass
,vfio_virqfd
, и другие правильно загружены, как видно в выводеlsmod | grep vfio
. Вы это уже сделали, и модули выглядят правильно. Однако важно также проверить, что другие модули, такие какnouveau
, не загружаются для вашей графической карты. Убедитесь, что они черным списком. -
Настройка GRUB:
Перепроверьте настройки вашей конфигурации GRUB. В вашем случае используется параметрintel_iommu=on,igfx_off
, что правильно, но не забудьте добавитьkvm.ignore_vmware=yes
для игнорирования некоторых виртуализационных проверок. -
Добавление
vendor_id
:
Попробуйте добавить специфичныйvendor_id
в XML вашей виртуальной машины, это может помочь предложить вашей виртуальной машине больше привилегий и заставить драйверы NVIDIA забыть, что она работает в виртуализированной среде.<hyperv> <vendor_id state="on" value="1234567890ab"/> </hyperv>
-
Добавление подделанного ACPI:
Как отмечается в ваших источниках, наличие подделанного ACPI-записи "Battery" может разрешить ошибку 43. Это связано с тем, что некоторые современные модели NVIDIA проверяют наличие батареи (особенно для мобильных GPU, таких как NVS 5200M). Вы можете попробовать добавить сообщество разрабатываемую таблицу ACPI в вашу конфигурацию. -
Устранение ошибок, связанных с памятью:
Обратите внимание на выводdmesg
и проверьте, нет ли сообщений о неудачной попытке резервирования памяти, особенно с упоминаниемBAR
. Выполните команды, которые удаляют и пересканируют устройство для восстановления:echo 1 > /sys/bus/pci/devices/0000:00:03.1/remove echo 1 > /sys/bus/pci/rescan
Не забудьте заменить
0000:00:03.1
на адрес вашего PCI-держателя, если он отличается. -
Проверка BIOS:
Убедитесь, что в настройках BIOS включена поддержка виртуализации. Это является критическим требованием для корректной работы KVM. -
Применение vBIOS:
Использование vBIOS может иногда помочь с ошибками, связанными с инициализацией GPU. Убедитесь, что путь к vBIOS правильно указан в XML-документе вашей VM.
Заключение
Ошибка 43 может появляться по разным причинам, связанным с системой NVIDIA и её проверками на виртуализацию. Следуя перечисленным шагам, вы сможете устранить основные проблемы, которые могут приводить к этой ошибке. Каждое из предложений имеет свои особенности, так что не забывайте делать резервные копии ваших конфигураций и изменений, чтобы можно было откатиться к стабильному состоянию системы.
Если проблема сохраняется, ищите дополнительные ресурсы и сообщества, где вы можете получить новую информацию по этой специфической проблеме. Работая последовательно и методично, можно добиться успешного GPU passthrough на KVM.