Если после запуска Windows в виртуальной машине в диспетчере устройств появился новый видеоадаптер, значит, vfio-pci отработал ровно так, как нужно. Ниже — вся цепочка: что требуется от железа и ядра, как закрепить драйвер за конкретной картой, как подключить её в virt-manager и как проверить результат.
Сценариев два.
Первый — Windows как гостевая ОС для игр, VR-шлемов и робототехники: SteamVR, Isaac Sim и экзоскелеты до сих пор рассчитывают на Windows-драйверы и DirectX. Вместо переустановки системы ради такого софта ты оставляешь хост Linux, а Windows живёт в VM с настоящей видеокартой вместо программного vga.
Второй — машинное обучение в изоляции. CUDA-контейнеры крутятся прямо в гостевой VM, связь с хостом даёт virtio-net. Вся вычислительная нагрузка ограничена границей виртуальной машины: если эксперимент уронил систему, откатываешь снапшот. Хост при этом продолжает считать своё.
Обе схемы уживаются с двумя картами в системе: одну отдаёшь гостю, вторую оставляешь хосту под Linux. Как развести две видеокарты, включая связку NVIDIA + AMDGPU в одном хосте, я разбирал в статье про multigpu: NVIDIA и AMDGPU одновременно.
Три вещи: работающий IOMMU, правильная разбивка на IOMMU-группы и модуль vfio-pci.
IOMMU — процессорный блок трансляции адресов: на AMD это AMD-Vi, на Intel — VT-d. Без него vfio-pci не изолирует устройство, и libvirt вернёт ошибку про отсутствие поддержки. Проверь, что IOMMU поднялся:
dmesg | grep -iE 'AMD-Vi|Intel-IOMMU|IOMMU'
В параметры ядра добавляется amd_iommu=on либо intel_iommu=on, плюс iommu=pt — режим passthrough. Для NVIDIA iommu=pt не рекомендация, а условие корректной работы CUDA.
IOMMU-группы — минимальные единицы, между которыми IOMMU умеет изолировать друг от друга. Правило простое: в группу карты не должны попадать устройства, нужные хосту. Список групп смотрится так:
for g in /sys/kernel/iommu_groups/*/devices/*; do
dev=$(basename "$g")
printf '%s -> %s\n' "${g%/devices/*}" "$(lspci -nns "$dev")"
done | sort -V
Строки с одинаковым путём группы описывают девайсы одной группы. Если в одной строке с NVIDIA-картой стоит её HDMI-звук, это нормально: отдавай оба устройства в VM. Если рядом оказалась сетевая карта материнской платы — это уже проблема, о ней ниже.
vfio-pci — модуль ядра, который перехватывает PCI-устройства до того, как их увидит nvidia. Список кандидатов показывает lspci -k:
lspci -nnk | grep -A3 -iE 'VGA compatible|3D controller'
Ключевые поля: Kernel driver in use (кем устройство занято сейчас) и Kernel modules (какой модуль может его забрать).
Про isolcpus стоит знать отдельно: на проход GPU он не влияет, гостевой код ядро и так не исполняет в пользовательском пространстве. Если ты изолируешь ядра хостовых задач через isolcpus и nohz_full, эти параметры живут в той же строке GRUB_CMDLINE_LINUX_DEFAULT, что и iommu=pt.
Сначала узнай ID устройства — его нужно указать драйверу по буквам, а не по имени:
lspci -nn | grep -i nvidia
# 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP104 [GeForce GTX 1080] [10de:1b80]
# 01:00.1 Audio device [0403]: NVIDIA Corporation GP104 High Definition Audio [10de:10f9]
Здесь два ID: 10de:1b80 — сама видеокарта, 10de:10f9 — её HDMI-звук. Создай /etc/modprobe.d/vfio.conf:
options vfio-pci ids=10de:1b80,10de:10f9 disable_vga=1
softdep nvidia pre: vfio-pci
Строка options vfio-pci ids=... говорит модулю забрать именно эти устройства. disable_vga=1 выключает legacy VGA framebuffer — с ней карта может не отпустить привязку к консоли. softdep nvidia pre: vfio-pci задаёт порядок загрузки: nvidia не встанет раньше, чем vfio-pci заберёт карту. Без этой строки на быстрых машинах гонка проигрывается непредсказуемо.
Дальше vfio-pci должен оказаться в initramfs, иначе после перезагрузки карта вернётся в хост. Открой /etc/mkinitcpio.conf и допиши модуль:
# в секции MODULES
MODULES=(vfio_pci vfio_iommu_type1)
На ядрах 5.16 и новее отдельный модуль vfio_virqfd больше не нужен, он слит с vfio-pci. Пересобери образ:
mkinitcpio -P
Порядок загрузки в initramfs важен: если модули nvidia собираются через DKMS и попадают туда же, проверь, что vfio идёт первым. Как вообще собрать модуль nvidia — статически или через DKMS — разобрано в статье про DKMS или статическое ядро. Параметры ядра про iommu=pt пропиши в /etc/kernel/cmdline или в /etc/default/grub, затем обнови конфиг GRUB — до перезагрузки ничего не применится.
В virt-manager открой нужную VM, выключи её, нажми «Показать XML» и найди секцию <devices>. Внутри добавь блок:
<hostdev mode='subsystem' type='pci' managed='yes'>
<driver name='vfio-pci'/>
<source>
<address domain='0x0000' bus='0x01' function='0x0'/>
</source>
</hostdev>
Значения bus и function бери из вывода lspci для своей карты. Атрибут managed='yes' разрешает libvirt самому привязать устройство к vfio. Секцию <rom bar='on'/> для NVIDIA обычно не добавляют: включение ROM BAR на некоторых картах приводит к зависанию гостя при старте.
Тот же результат даёт графический путь: «Оборудование» → «Добавить новое» → «PCI-устройство», в списке нужная карта, «Готово». Если машина ещё не создана, включи UEFI (OVMF) вместо устаревшего SeaBIOS — Windows 10 и 11 без него не заведутся.
Не правь XML у запущенной машины: после virsh start конфигурация гостя перезаписывается.
Главная проверка — одна строка lspci:
lspci -nnk -s 01:00.0
# Kernel driver in use: vfio-pci
# Kernel modules: vfio_pci nvidia
Значение vfio-pci вместо nvidia означает, что карта готова к передаче. В списке Kernel modules nvidia ещё присутствует — это нормально, просто vfio-pci забрал устройство раньше. Если в in use всё ещё nvidia, модуль не загрузился вовремя: проверь mkinitcpio -P и строку softdep.
Дополнительно:
dmesg | grep -iE 'vfio|IOMMU' | tail -20
В логе ожидаются строки о биндинге устройства к группе IOMMU. В virt-manager карта в списке PCI-устройств отображается с драйвером vfio.
В гостевой Windows открой диспетчер устройств, раздел «Видеоадаптеры» — там будет модель карты, а nvidia-smi покажет модель, драйвер и объём видеопамяти. Если nvidia-smi ругается на несовпадение версии драйвера и ядра гостя, обнови драйвер внутри VM. Как выбирать версию драйвера на стороне Arch Linux, я писал в статье про установку драйвера NVIDIA на Arch Linux: в хосте и в госте версии могут различаться, и это нормально.
Разбирай по симптомам.
Видеоадаптер есть, но работает как «базовый дисплей» — установлен Microsoft Basic Display Adapter вместо NVIDIA. Скачай официальный установщик NVIDIA под Windows, запусти в гостевой VM и дождись перезагрузки.
Ошибка QEMU_ERROR «несовместимо с этим оборудованием», код 43 — гость не доверяет драйверу. Решение: отключить Secure Boot в UEFI VM либо включить тестовый режим подписи (bcdedit /set testsigning on в командной строке с правами администратора).
После выключения VM карта не возвращается хосту — классический reset bug. Встречается на Maxwell и Pascal (GTX 900, GTX 1000/XT, часть GTX 1080), то есть на картах старше Turing: QEMU не умеет корректно сбросить состояние, и следующий запуск падает с BAR 1: can't reserve region. Лечится модулем vfio-vendor-reset и ядром, собранным под него.
Ошибка «Memory: target too small» или сбой маппинга BAR — не хватило адресного пространства. Включи в UEFI хоста Above 4G Decoding, а гостю выдели больше оперативной памяти, чем он запрашивает.
Ситуация: в группе с картой лежат ещё сетевой адаптер, ACPI-контроллер или устройство SMBus. Пробовать отдать всё это гостю — плохая идея, хост останется без сети.
Что можно сделать по порядку:
IOMMU Group, ACS Enable или PCI Isolation — в зависимости от платы название отличается, но смысл один: дать процессору дробить таблицу DMAR на мелкие группы.dmar=0xfffff. Он заставляет IOMMU округлить DMAR-таблицу и разрезать группу на отдельные устройства. Скорость IOMMU при этом может заметно просесть, поэтому вариант годится для стенда, а не для рабочей машины.Перед этими операциями сохрани текущую раскладку групп, чтобы вернуться назад перезагрузкой.
Нет, если модули nvidia и vfio подписаны. Выключать приходится только ради установки неподписанных модулей — например, vfio-vendor-reset, собранного вручную.
Технически да, но двум картам NVIDIA для игр нужны разные PCIe-корневые комплексы, а не соседние слоты на одной линии. Смешанная связка AMD + NVIDIA в одной VM проблемнее: требования к драйверам разные, и сбой одного гостя утащит за собой второй.
Выключи VM, выполни lspci -nnk -s 01:00.0 и убедись, что в in use стоит nvidia. Если остался vfio-pci, помогает перезагрузка. Если карта не отдаётся и после неё, на картах с reset bug нужен полный сброс питания.
Да. CUDA-передачи и unified memory работают через адресную трансляцию, и без IOMMU ядро гостя получает физические адреса хоста — это и нестабильно, и небезопасно.
Проход NVIDIA в VM сводится к трём точкам: IOMMU включён, IOMMU-группа содержит только нужные устройства, vfio-pci забрал карту раньше nvidia. Проверяется всё одной командой lspci -nnk. Дальше остаётся подключить <hostdev> в XML гостя, поставить в VM драйвер и держать в голове reset bug на старых картах.
Задай вопрос в чате — отвечаем быстро, по делу и без воды.
Комментарии