Источник: https://mathiashueber.com/pci-passthrough-ubuntu-2004-virtual-machine/ (перевод ещё в процессе), но сама суть доступна
Преамбула
Всё нижеизложенное — наиболее простой способ проброса PCI устройства в Ubuntu 20. Я постараюсь вносить изменения в операционную систему по минимуму, но тем не менее изложу все шаги как можно более тщательно, чтобы даже новички в Linux смогли повторить изложенное.
Финальный результат будет работать под Xubuntu 20.04 как хостовой системой, а гостевой системой будет Windows 10 2004, которая будет использоваться в основном под игры.
К сожалению, процесс настройки может быть довольно сложным. Он состоит из определённых базовых, некоторых изменчивых и нескольких дополнительных настроек (в основном, что касается производительности). Чтобы сохранить читабельность этой статьи, а также из-за того, что виртуальная машина будет использоваться только для игр, я приуменьшил различные части настроек для оптимизации задержек. Сами необходимые статьи для настроек указаны в статье ниже — надеюсь это поможет 🙂
Об этой статье
Это руководство предназначено для Ubuntu 20.04 и основано на моих предыдущих руководствах для хост-систем Ubuntu 18.04 и 16.04.
Однако это руководство должно быть применимо и к Pop!_OS 19.04 и новее. Если вы хотите использовать Pop!_OS как хост-систему вы можете это делать, просто обращайте внимание на пометки специально для Pop!_OS.
Критические изменения для старых настроек проброса для Ubuntu 20.04
Версия ядра
Начиная с версии ядра 5.4, драйвер “vfio-pci” больше не является модулем ядра, он встроен в ядро. Нужно найти другой способ вместо использования конфигурационных файлов initramfs-tools/modules, как я рекомендовал, например, в руководстве для 18.04.
Версия QEMU
Ubuntu 20.04 поставляется с QEMU версии 4.2, где есть некоторые исправления в аудио части. Так что будьте внимательней, когда будете переносить конфигурацию машины со старой системы.
Если же хочется использовать новейшую версию QEMU, то инструкция лежит тут.
Загрузчик
“Проблемой” для Ubuntu 20.04 загрузчик не является, но, по крайней мере, есть некоторые нюансы для одного популярного дистрибутива, который основан на Ubuntu – Pop!_OS 20.04
Я думаю, что начиная с версии 19.04, Pop!_OS использует systemd в качестве менеджера загрузки, а не grub. Это означает, что запуск команд ядра работает по-разному в Pop!_OS
Введение в понятия VFIO, PCI passthrough и IOMMU
Виртуальная функция ввода-вывода (или VFIO) обеспечивает виртуальной машине (ВМ) прямой доступ к аппаратному ресурсу PCI, такому как графический процессор (GPU). Виртуальные машины с настроенным пробросом GPU могут получить близкую к реальному железу производительность, что делает возможным запуск игр на виртуальной машине Windows.
Позвольте сделать следующие упрощения, чтобы утверждение в начале статьи о её дружелюбности к новичкам в Linux не было ложным:
Устройства PCI организованы в так называемые группы IOMMU. Чтобы пробросить устройство в виртуальную машину, мы должны передать все устройства одной и той же группы IOMMU. В идеальном мире каждое устройство имеет свою собственную группу IOMMU. К сожалению, мы живём не в идеальном мире.
Проброшенные устройства изолированы и, таким образом, больше не доступны для хост-системы. Кроме того, одновременно можно изолировать только все устройства одной группы IOMMU.
Это означает, что даже если какое-либо устройство не используется в виртуальной машине, оно всё равно не доступно для хоста, даже если если оно состоит в одной группе IOMMU переданного устройства.
Системные требования
Железо
Чтобы успешно следовать этому руководству, необходимо, чтобы используемое оборудование поддерживало виртуализацию и правильно разделяло группы IOMMU.
Используемое оборудование
- AMD Ryzen7 1800x (CPU)
- Asus Prime-x370 pro (Материнская плата)
- 2x 16 GB DDR4-3200 running at 2400MHz (RAM)
- Nvidia GeForce 1050 GTX (GPU хоста; PCIE слот 1)
- Nvidia GeForce 1060 GTX (GPU для гостя; PCIE слот 2)
- 500 GB NVME SSD (Гостевая ОС; слот M.2)
- 500 GB SSD (Хостовая ОС; SATA)
- 750W БП
При сборе комплектующих системы я стремился избежать необходимости патчинга ядра. Так что, патч переопределения ACS не требуется для указанной комбинации материнской платы и процессора
Если ваша материнская плата не имеет надлежащего разделения IOMMU, вы можете попытаться решить эту проблему с помощью исправленного ядра или пропатчить ядро самостоятельно.
Настройки BIOS
Включите следующие опции в вашем BIOS:
Advanced \ CPU config - SVM Module -> enable
Advanced \ AMD CBS - IOMMU -> enable
Внимание
Материнские платы ASUS Prime x370/x470/x570 pro с версией BIOS, поддерживающей процессоры AMD Ryzen 3000 серии (версии 4602 – 5220), будут выдавать ошибку проброса PCI:
Error: «Unknown PCI header type ‘127’“
Версии BIOS до 4406 включительно (2019.03.11) работают
Версии BIOS начиная с 5406 включительно (2019.11.25) тоже рабтают.
Я использую версию 4207 (от 2018.12.07)
Настройки операционной системы хоста
Имеется установленная Xubuntu 20.04 x64 в режиме UEFI, взятая отсюда.
Ubuntu 20.04 LTS поставляется с ядром версии 5.4, которое хорошо работает с VFIO. Проверить можно через uname -r
Внимание
Любое ядро, начиная с версии 4.15, работает для проброса для процессоров Ryzen.
За исключением версий ядра 5.1, 5.2 и 5.3, включая все их подверсии.
Прежде чем продолжить убедитесь что ваше ядро хорошо работает в среде VFIO
Установка необходимого ПО
Установите QEMU, Libvirt, менеджер виртуализации и связанное с ним программное обеспечение:
sudo apt install qemu-kvm qemu-utils libvirt-daemon-system libvirt-clients bridge-utils virt-manager ovmf
Настройка проброса PCI
Следующие устройства будут проброшены в виртуальную машину:
- 1x GPU: Nvidia GeForce 1060 GTX
- 1x USB host controller
- 1x SSD: 500 GB NVME M.2
Включение функционала IOMMU
Включите функцию IOMMU через конфигурацию grub. В системе с процессором AMD Ryzen запустите следующую команду:
sudo nano /etc/default/grub
Отредактируйте строку, которая начинается с GRUB_CMDLINE_LINUX_DEFAULT, чтобы она соответствовала этой строке:
GRUB_CMDLINE_LINUX_DEFAULT="amd_iommu=on iommu=pt"
В случае если у вас Intel строка должна быть такой:
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on"
Как только вы закончите редактирование, сохраните изменения и выйдите из редактора (CTRL+S, CTRL+X).
Затем выполните
sudo update-grub
→ Перезагрузите систему, когда команда будет завершена.
Проверьте, включен ли IOMMU, запустив после перезагрузки следующую команду:
dmesg | grep AMD-Vi
Вывод будет примерно такой:
[ 0.792691] AMD-Vi: IOMMU performance counters supported [ 0.794428] AMD-Vi: Found IOMMU at 0000:00:00.2 cap 0x40 [ 0.794429] AMD-Vi: Extended features (0xf77ef22294ada): [ 0.794434] AMD-Vi: Interrupt remapping enabled [ 0.794436] AMD-Vi: virtual APIC enabled [ 0.794688] AMD-Vi: Lazy IO/TLB flushing enabled
Настройки для загрузчика в Pop!_OS
Можно использовать модуль kernelstub загрузчика systemd. Используйте его вот так:
sudo kernelstub -o "amd_iommu=on amd_iommu=pt"
Выбор пробрасываемого GPU в гостевую систему
Внимание
После выполнения следующих шагов GPU для гостевой системы будет не виден в хостовой ОС. То есть у вас должен быть второй графический процессор для хостовой ОС.
Здесь мы идентифицируем и изолируем устройства, прежде чем передавать их виртуальной машине. Мы ищем видеокарту и USB-контроллер в подходящих группах IOMMU. Это означает, что либо оба устройства имеют свою собственную группу, либо они совместно используют одну группу.
Сам план состоит в том, чтобы применить драйвер vfio-pci к пробрасываемой видеокарте, прежде чем обычный драйвер видеокарты сможет взять её под контроль.
Это самый важный шаг в процессе проброса. Если ваша материнская плата не поддерживает правильную группировку IOMMU, вы можете попробовать исправить свое ядро с помощью патча ACS override.
Можно использовать скрипт bash типа такого для определения устройств и их группировки:
#!/bin/bash #change the 999 if needed shopt -s nullglob for d in /sys/kernel/iommu_groups/{0..999}/devices/; do n=${d#/iommu_groups/}; n=${n%%/} printf 'IOMMU Group %s ' "$n" lspci -nns "${d##*/}" done;
источник: wiki.archlinux.org + добавлена сортировка для первых 999 групп IOMMU
Синтаксис результирующего вывода выглядит следующим образом:
Интересующие нас части шины PCI выделены красным на рис.1, а оранжевым выделены идентификаторы устройств.
Вот эти устройства нас интересуют:
NVME M.2 ======== IOMMU group 1401:00.0 Non-Volatile memory controller [0108]: Micron/Crucial Technology P1 NVMe PCIe SSD [c0a9:2263] (rev 03)
Driver: nvme
Guest GPU - GTX1060 ================= IOMMU group 17 0c:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP104 [GeForce GTX 1060 6GB] [10de:1b83] (rev a1) Driver: nvidia 0c:00.1 Audio device [0403]: NVIDIA Corporation GP104 High Definition Audio Controller [10de:10f0] (rev a1) Driver: snd_hda_intel USB host ======= IOMMU group 20 0d:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Family 17h (Models 00h-0fh) USB 3.0 Host Controller [1022:145c] Driver: xhci_hcd
Мы изолируем GTX 1060 (PCI-bus 0c:00.0
и 0c:00.1
; device id 10de:1b83
, 10de:10f0
)
USB контроллер (Шина PCI 0d:00.3
; device id 1022:145c
) используется позже
Накопитель NVME может быть проброшен без идентификационных номеров. Однако крайне важно, чтобы у него была своя группа.
Изоляция гостевого GPU
Чтобы изолировать графический процессор, у нас есть два варианта. Выберите устройства по адресу шины PCI (PCI bus address) или по идентификатору устройства (device ID). Оба варианта имеют свои плюсы и минусы.
Применение драйвера VFIO-pci по идентификатору устройства (через загрузчик)
Этот параметр следует использовать только в том случае, если видеокарты в системе различаются по названию.
Обновим grub еще раз и добавьте идентификаторы устройств PCI с параметром vfio-pci.ids
Запустите sudo nano /etc/default/grub и обновите строку GRUB_CMDLINE_LINUX_DEFAULT:
GRUB_CMDLINE_LINUX_DEFAULT="amd_iommu=on iommu=pt kvm.ignore_msrs=1 vfio-pci.ids=10de:1b83,10de:10f0"
Примечание
Команда “kvm.
ignore_msrs” необходима только для Windows 10 версии выше 1803 (в противном случае получите синий экран).
Сохраните и закройте файл. После этого выполните:
sudo update-grub
Внимание!
После перезагрузки пробрасываемая видеокарта будет проигнорирована хостовой ОС. Так что вы должны использовать другой графический процессор для хостовой ОС!
→ Перезагрузите систему.
Для загрузчика systemd, такой как Pop!_OS 19.04 и новее, вы можете использовать:
sudo kernelstub --add-options "vfio-pci.ids=10de:1b80,10de:10f0,8086:1533"
Применение драйвера VFIO-pci по идентификатору шины PCI (через скрипт)
Этот метод работает, даже если вы хотите изолировать одну из двух идентичных карт. Однако обратите внимание, что в случае добавления или удаления PCI-оборудования из системы идентификаторы шин PCI будут меняться (также такое будет иногда случаться после обновления BIOS).
Создайте еще один файл с помощью sudo nano /etc/initramfs-tools/scripts/init-top/vfio.sh и добавьте следующие строки:
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
for dev in 0000:0c:00.0 0000:0c:00.1
do
echo "vfio-pci" > /sys/bus/pci/devices/$dev/driver_override
echo "$dev" > /sys/bus/pci/drivers/vfio-pci/bind
done
exit 0
Спасибо /u/nazar-pc на reddit. Убедитесь, что строка
for dev in 0000:0c:00.0 0000:0c:00.1
имеет правильные идентификаторы шины PCI для графического процессора, который вы хотите пробросить. Теперь сохраните и закройте файл.
Сделайте скрипт исполняемым:
sudo chmod +x /etc/initramfs-tools/scripts/init-top/vfio.sh
Создайте еще один файл с помощью sudo nano /etc/initramfs-tools/modules
И добавьте следующие строки:
options kvm ignore_msrs=1
Сохраните и закройте файл.
Когда все будет сделано, выполните:
sudo update-initramfs -u -k all
Внимание!
После перезагрузки пробрасываемая видеокарта будет проигнорирована хостовой ОС. Так что вы должны использовать другой графический процессор для хостовой ОС!
→ Перезагрузите систему.
Проверка проброса
Для проверки правильного проброса устройства выполните следующие действия:
lspci -nnv
найдите строку «Kernel driver in use
» для графического процессора и его звуковой части. В нем должно быть указано vfio-pci
0b:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP104 [GeForce GTX 1060 6GB] [10de:1b83] (rev a1) (prog-if 00 [VGA controller]) Subsystem: ASUSTeK Computer Inc. GP104 [1043:8655] Flags: fast devsel, IRQ 44 Memory at f4000000 (32-bit, non-prefetchable) [size=16M] Memory at c0000000 (64-bit, prefetchable) [size=256M] Memory at d0000000 (64-bit, prefetchable) [size=32M] I/O ports at d000 [size=128] Expansion ROM at f5000000 [disabled] [size=512K] Capabilities:Kernel driver in use: vfio-pci Kernel modules: nvidiafb, nouveau, nvidia_drm, nvidia
Поздравляю, самая трудная часть сделана! 🙂
Создание виртуальной машины Windows
Виртуализация осуществляется с помощью эмулятора машины с открытым исходным кодом и виртуализатора под названием QEMU. Можно либо запустить QEMU напрямую, либо использовать графический интерфейс virt-manager для создания машины и её запуска.
Я предпочитаю графический интерфейс. К сожалению, не все настройки поддерживаются в virt-manager. Таким образом, я определяю основные настройки в пользовательском интерфейсе, делаю быстрый запуск виртуальной машины и “принудительно останавливаю” ее сразу после того, как вижу, что графический процессор передан правильно. После этого можно отредактировать недостающие опции в конфигурацию виртуальной машины с помощью virsh edit
Убедитесь, что ваш ISO-файл Windows, а также драйверы virtio для Windows загружены и готовы к установке.
Предварительная настройка
Как я уже говорил, множество разных вариантов настроек может усложнить это руководство. Прежде чем мы сможем продолжить, нужно принять решение о типе хранилища виртуальной машины
Создание образа диска (если нужно)
В этой статье я пробрасываю свой SSD NVME M. 2 виртуальной машине. Еще одним годным решением является использование образа диска в raw-формате, дополнительную информацию смотрите в разделе хранилище данных.
Создание моста Ethernet
Мы будем использовать соединение типа «мост» для виртуальной машины. Для этого требуется проводное подключение к компьютеру.
Я просто следовал статье от Хейко.
Можете посмотреть статью настройки сети здесь.
Создание новой виртуальной машины
Как уже было сказано ранее мы используем графический интерфейс virtual machine manager для создания виртуальной машины с базовыми настройками
Для этого запустите диспетчер и нажмите кнопку “Создать новую виртуальную машину”
Шаг 1
Выберите “Local install media” и продолжайте дальше (см. рис. 3)
Шаг 2
Теперь нам нужно выбрать ISO-файл Windows, который мы хотим использовать для установки (см. рис. 3). Также проверьте автоматическое обнаружение системы. Подсказка: используйте кнопку “browse local” (одна из кнопок на правой стороне), чтобы перейти к местоположению ISO.
Шаг 3
Введите объем оперативной памяти и процессорных ядер, которые вы хотите передать, и продолжите работу с мастером. Я хочу использовать 8 ядер (максимум 16, скриншот показывает 12 по ошибке!) и 16384 Мб оперативной памяти в моей виртуальной машине.
Шаг 4
Если вы используете файл образа, выберите ранее созданный файл и продолжите работу. Я снимаю флажок “Enable storage for this virtual machine” и добавляю свое устройство позже.
Шаг 5
На последних шагах требуется чуть больше кликов
Введите осмысленное имя для виртуальной машины. Оно будет использоваться в имени конфигурационного файла xml. Думаю, что не стоит использовать имя с пробелами в названии. Это конечно не вызовет особых проблем, но я всё же был достаточно осторожен, чтобы так не делать ранее.
Кроме того, убедитесь, что вы установили флажок “Customize configuration before install”.
Для раздела “network selection” выберите “Specify shared device name” и введите имя сетевого моста, который мы создали ранее. Вы можете использовать ifconfig в терминале для отображения ваших устройств Ethernet. В моем случае это “bridge0”. (Также при использовании netplan будет выведен список созданных ранее мостов. По мне — это удобнее. (прим. переводчика))
Замечание! Количество процессоров на рисунке 7 неверно. Он должен быть 8, если вы выполняли инструкции выше.
Первая настройка
После нажатия кнопки “Готово” откроется окно конфигурации виртуальной машины. В левом столбце отображаются все аппаратные устройства, используемые этой виртуальной машиной. Щелкнув по ним левой кнопкой мыши, вы увидите параметры устройства с правой стороны. Вы можете удалить аппаратное обеспечение с помощью щелчка правой кнопкой мыши. Вы можете добавить больше оборудования с помощью кнопки ниже. Обязательно нажимайте кнопку Применить после каждого изменения.
Следующие скриншоты могут немного отличаться от вашего графического интерфейса (так как я добавил и удалил некоторые аппаратные устройства).
Общее
На первом пункте в списке убедитесь, что для “Firmware” выбран параметр UEFIx86_64 […] OVMF [ … ]. “Chipset” должен быть Q35 см. рис. 8.
Процессоры
В секции “Model:” нажмите в раскрывающемся списке, как если бы это было текстовое поле, и введите
host-passthrough
Это передаст всю информацию о процессоре гостевой машине. Для получения дополнительной информации вы можете прочитать главу информация о модели процессора в руководстве по производительности
Для параметра “Topology” установите флажок “Manually set CPU topology” со следующими значениями:
- Sockets: 1
- Cores: 4
- Threads: 2
Диск 1, гостевой жесткий диск
В зависимости от этапа предварительной настройки хранилища вы должны выбрать подходящий тип хранения для вашего диска (raw формат или проброшенное реальное оборудование). Дополнительные параметры см. в статье Хранение.
Настройка, если выбран raw файл
Когда вы впервые войдете в этот раздел, там будет написано “IDE Disk 1”. Мы должны изменить значение “дисковая шина:” на VirtIO.
Настройка, если выбран проброс диска
Узнайте правильный идентификатор устройства диска через lsblk, чтобы получить имя диска.
При первом редактировании конфигурации виртуальной машины добавьте следующий блок в раздел <devices> (одна строка после </emulator> должна быть подходящей).
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' io='native' discard='unmap'/>
<source dev='/dev/nvme0n1'/>
<target dev='sdb' bus='sata'/>
<boot order='1'/>
<address type='drive' controller='0' bus='0' target='0' unit='1'/>
</disk>
Отредактируйте строку
<source dev='/dev/nvme0n1'/>
Чтобы соответствовать вашему имени диска
VirtIO Драйвер
Далее мы должны добавить драйвер virtIO ISO, чтобы он использовался во время установки Windows. В противном случае установщик не сможет распознать объем хранилища, который мы только что изменили с IDE на virtIO.
Для того чтобы добавить драйвер нажмите кнопку “Добавить оборудование”, выберите пункт “Хранилище”, выберите загруженный файл образа.
В поле “Тип устройства:” выберите устройство CD-ROM. Для параметра “тип шины:” выберите IDE, иначе windows также не найдет компакт-диск (см. рис. 11).
Проброс видеокарты
Наконец-то! Чтобы выполнить проброс GPU, мы должны добавить наш гостевой GPU и USB-контроллер в виртуальную машину. Нажмите кнопку “Добавить оборудование”, выберите “хост-устройство PCI” и найдите устройство по его идентификатору. Проделайте это три раза для:
- 0000:0c:00.0 для GeForce GTX 1060
- 0000:0c:00.1 для GeForce GTX 1060 Audio
- 0000:0d:00.3 для USB контроллера
Примечание: В случае, если вы позже добавите дополнительное оборудование (например, другое устройство PCI-E), эти идентификаторы могут быть изменены. Так что имейте в виду, что если вы измените оборудование, просто повторите этот шаг с обновленными идентификаторами.
Так и должно быть. Подключите вторую мышь и клавиатуру к USB-портам проброшенного контроллера (см. рис. 2).
Нажмите кнопку “Начать установку”, и на мониторе, подключенном к GTX 1060, должен появиться логотип Tiano core. Если всплывает забавная бело — желтая оболочка, то введите exit, чтобы выйти из неё.
Если ничего не происходит, убедитесь, что у вас есть оба устройства CD-ROM (по одному для ISO образа Windows 10 и драйвера virtIO) в вашем списке. Также проверьте запись “параметры загрузки”.
Как только вы увидите установку Windows, используйте “force off” из virt-manager, чтобы принудительно остановить виртуальную машину.
Окончательная конфигурация и дополнительные шаги
Для редактирования конфигурации виртуальных машин используйте в консоли: virsh edit your-windows-vm-name
После завершения редактирования вы можете использовать CTRL+S CTRL+X, чтобы сохранить изменения и выйти из редактора.
Я добавил следующие изменения в свою конфигурацию:
Оптимизация процессора AMD Ryzen
(будет дописано позже)
Hugepages для лучшей производительности оперативной памяти
Этот шаг является необязательным и требует предварительной настройки: Подробнее см. Hugepages.
найдите строку, которая заканчивается на </currentMemory>, и добавьте за ней следующий блок:
<memoryBacking>
<hugepages/>
</memoryBacking>
Примечание: убедитесь, что <memoryBacking> и <currentMemory> имеют одинаковый отступ.
Если драйвера не видят видеокарту nvidia
то добавьте в конфигурацию машины следующий текст.
<kvm>
<hidden state=’on’/>
</kvm>
Пока на этом всё