Про ИИ.
Да, я использовал ИИ, и нет, ИИ не писал этот текст.
Текст написан от и до — мной.
ИИ использовался для поиска и проверки информации, а также написания скриптов. Но с одним ключевым нюансом – я понимаю что я делаю (ну, почти), а не бездумно копирую и вставляю.
Это довольно сложная тема, и сделать так, чтобы работало у всех… я не знаю, как.
То, что вы тут прочитаете это одна конкретная тропинка, одна, но я их прошел десятки, перепробовал ОЧЕНЬ много всего. Поэтому вам и нужны хотя бы базовые знания, о чем и будет написано далее.
Это длинный текст, тут полно команд и скриптов. Я все это делал и одновременно писал и описывал это, и далеко не один день.
Если вы найдете тут ошибку, у вас что-то не будет работать хотя ТОЧНО должно работать – свяжитесь со мной.
Если у вас возникнут проблемы с XML, то вот мой полный XML файл.
Другое железо (не описанное здесь), другой дистрибутив, другое окружение/WM, что-то еще другое — не повод писать. Хотя… я возможно посмотрю.
Предисловие
В этом тексте я покажу, как я настроил KVM на Linux openSUSE Tumbleweed от и до + доп. фичи (Quality-of-Life). Из главного это разумеется проброс и/или эффективное использование:
- SSD
- GPU
- CPU
- RAM
В самом начале, имейте в виду у меня есть iGPU и dGPU и текст писался именно под такой сценарий. Если у вас нет двух GPU, iGPU + dGPU или dGPU + dGPU, вам этот текст не подойдет. И читать его стоит в таком случае, разве что ради общего развития и скриптов.
Ну и важно упомянуть, если вы это читаете с четким намерением и хотением сделать это, то вероятно вы морально готовы к этому, и у вас есть железо. Разумеется слабое железо будет не очень, но чисто технически чтобы сделать, конкретно в данном случае, решает не мощь, а количество – много ОЗУ, ядер и в идеале отдельный диск.
НЕ наличие второй GPU в данном тексте не обсуждается, там совершенно другой подход, потому что с ОДНОЙ GPU вы “используете” ЛИБО хост, ЛИБО гость, а в данном тексте расчет на и то, и другое, одновременно.
Итак. Я выбрал openSUSE Tumbleweed + KDE Plasma. Почему? Нам нужны самые новые релизы всего и вся – rolling-release схема, чтобы сделать этот трюк с виртуалкой с производительностью 1:1 к голому железу. Debian и прочие LTS дистрибутивы не очень подходят.
Очевидный вариант – это Arch. Разработчик выкатил апдейт софта – вы его установили, то что надо. Но из-за этого Arch часто ломается, и приходится мониторить новостную ленту обновлений на предмет “а не сломается ли моя система после апдейта и что я должен сделать руками”, не круто.
Есть Void, это как Arch только обновления автоматически тестируются, вероятность, что система ляжет после обновления сильно меньше. Но Void использует runit вместо systemd, для кого-то это плюс, но systemd мегапопулярен, все делается под него, вам оно надо? Ну и еще там в основном старье, все новое нужно собирать ручками.
И третий вариант — openSUSE Tumbleweed, это как Void, но с systemd и новейшим софтом, а также встроенным GUI приложением YaST через которое можно настроить систему и установить виртуалку буквально в один клик.
Ну, а KDE Plasma, На момент написания этого текста только в KDE Plasma нормально работает 4K HDR 320 Hz, или типа того. потому что она самая навороченная и простая. На первое время + тестов – самое оно.
И все-все будет описано, сказано и показано в контексте Tumbleweed и KDE Plasma. Потому если у вас другие distro/DE/WM и вы вообще не шарите за Linux и ни разу с этим чудом не еб*лись – не делайте этого, по крайней мере на своей рабочей ОС.
Если же вы шарите, и у вас НЕ KDE Plasma ИЛИ вас интересует исключительно холодный проброс dGPU – прочтите это.
Введение
Про мониторы
Подумайте о том, как будете смотреть на Windows. Есть конечно Looking Glass, и я даже покажу, как его настроить, но для игр, особенно экшен игр, это ужасно + оверхед dGPU. В моем случае 2 монитора (оба FULLHD):
Хост:
- Основной – HDMI 1.4
- Второй – DP
Гость:
- Основной – DP
- Второй – HDMI 1.4
То есть перекрестное подключение, а такое оно из-за недостатка входов как на мониторах так и на материнки, будь моя воля, я бы все втыкнул в DP.
Версию HDMI я написал не просто так, у меня 1.4, а это максимум 120 Hz (хоть и программно), в то время как у моего основного монитора 144 Hz.
Логика #1, максимально проста и логична: Делаем основной монитор хоста в DP, в работе я увижу все 144 Hz, а вот то, что в играх будет 144 FPS, я очень сомневаюсь, и поэтому для гостя HDMI на 120 Hz.
Именно так я изначально и сделал, забыв, что NVIDIA не работает с FreeSync, G-Sync и прочими Sync с HDMI <2.1 и то криво, насколько мне известно.
Поэтому, Логика #2: Наоборот, хост не такой гладкий, да, но разница 120 vs 144 не особо заметна, как например 60 vs 75, но при этом все Sync работают с NVIDIA через DP.
В BIOS, он же UEFI Firmware нужно, разумеется, включить аппаратную виртуализацию вашего процессора и IOMMU. Как это сделать гуглите для своего процессора и для своего производителя мат. платы, тут у каждого по-своему.
Также включение IOMMU в ОС (не заменяет настройки BIOS):
YaST –> System –> Boot Loader в конец добавить: amd_iommu=force_isolation iommu=pt. Если у вас Intel, то вместо amd_iommu=force_isolation –> intel_iommu=on.
Перезагрузиться.
Проверить параметры и включен ли IOMMU:
sudo sh -c 'dmesg | grep -i iommu && echo && dmesg | grep -E "Intel-IOMMU|AMD-Vi"'
Узнать, выиграли ли вы в лотерею, можно:
sh -c 'for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do echo "IOMMU Group ${g##*/}:"; for d in $(ls -1 $g/devices); do lspci -nns $d; done; echo; done'
Если каждая железка, ну или только те железки, что вам нужны для проброса в отдельной IOMMU группе – вам повезло. А именно, это нужный SSD и нужная GPU, ну и другое по желанию, что вам нужно. Если нет, то придется применить ACS patch (я опишу это, когда у меня будет достаточно информации).
Про SSD может быть такое, что у вас скажем 3 слота SSD, но 2 из них в одной группе, а 1 в отдельной, уже знаете, что делать, ведь так?
Виртуализация
YaST –> Virtualization –> Install Hypervisor and Tools - KVM server и KVM tools.
Если при установке YaST предложит создать мост, соглашайтесь, если ошибка – значения не имеет.
После установки проверьте:
sudo systemctl status virtqemud
А также добавляемся в группы:
sudo usermod -aG libvirt,kvm $(whoami)
Это нужно, чтобы потом иметь возможность пробросить PCI устройства, а также запинить ядра процессора, сделать hugepages, ну и другое.
Перезагружаемся, проверить, что вы в группе, можно:
groups && grep -E 'libvirt|kvm' /etc/group
А также для W11:
ls /usr/share/qemu/ovmf*
Должен быть /usr/share/qemu/ovmf-x86_64-smm-ms-code.bin, это SMM + Secure Boot.
Создание виртуальной машины
Открываем Virtual Machine Manager и создаем новую виртуалку, Local install media (ISO), да, у вас должен быть образ Windows. RAM/CPU что угодно, сейчас неважно. Storage - тут важно, убрать галочку с Enable storage for this VM. И ВАЖНО поставить галочку Customize configuration before install.
Если “Virtual Network is not active” – sudo virsh net-autostart default и нажмите “Yes”.
Overview:
- Chipset: Q35
- Firmware:
/usr/share/qemu/ovmf-x86_64-smm-ms-code.bin
CPU:
- Copy host CPU configuration (host-passthrough)
Add Hardware –> TPM:
- Type: если у вас есть поддержка TPM, то Passthrough, иначе Emulated
- Model: есть поддержка - CRB, иначе - TIS
Если у вас два TPM в списке, удалите тот, что вы не создавали.
Проброс диска
Есть два способа пробросить диск. Универсальный и если вам повезло с IOMMU группами – VFIO.
Проверьте IOMMU группы:
sh -c 'for g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do echo "IOMMU Group ${g##*/}:"; for d in $(ls -1 $g/devices); do lspci -nns $d; done; echo; done'
Если видите что-то такое:
| |
Или такое:
| |
И все, если в этой группе больше НИЧЕГО нету, вам очень повезло, вы можете пробросить диск самым прямым способом.
В первом случае в группе вместе с диском находится и его мост, такое можно смело пробрасывать, но если там скажем парочка USB, еще один диск, сетевая карта или еще что, то нет, не надо так делать.
Универсальный это через VirtIO драйвер, он не плохой, но задержки больше, потеряете около 3-5% линейной скорости (запись/перемещение файлов), и чуть больше потерь на рандомной записи/чтения (видеомонтаж, рендер, игры и тп.) в сравнении с голым железом.
Также вы можете попробовать сначала одно, потом другое, без пересоздания виртуалки и переустановки Windows, все будет работать.
Делаем:
lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,MODEL
Вывод:
| |
Проверяем наличие нужного диска и отсутствие точек монтирования.
Далее:
ls -la /dev/disk/by-id/ | grep nvme1n1
Нам нужно типа такого nvme-KINGSTON_SKC3000D2048G_xxxx, без _x или -x. Записываем это.
Так мы узнали серийник диска, он нужен, чтобы привязать диск по серийнику (VirtIO), а не по имени. В Linux какой первый диск инициализируется, тот первым и будет. Это значит, то, что вы укажите в настройках виртуалки, после перезагрузки хоста может поменяться, по серийнику не поменяется.
VirtIO (универсально)
Качаем virtio-win драйвер. Он нужен, чтобы Windows могла увидеть этот ваш диск.
Тыкаем Add Hardware –> Storage:
- Select or create custom storage
- Device type: Disk device
- Bus type: VirtIO
- Manage –>
/dev/disk/by-id/nvme-KINGSTON_SKC3000D2048G_xxxx(см. выше) - Advanced options:
- Cache mode: none
- Discard mode: unmap
Снова Add Hardware –> Storage:
- Device type: CDROM
- virtio-win.iso
VFIO
Если вы еще не устанавливали Windows, то пропускаем этот шаг, если уже установили, но хотите VFIO, то загружайтесь в Windows, открываете терминал от имени админа:
bcdedit /set {current} safeboot minimal
Выключаете виртуалку и удаляете текущий VirtIO диск.
Add Hardware –> PCI Host Device, тут надо найти нужный SSD, да это будет чуточку проблематично, но как найдете, тыкаете на него и Finish. Отныне он будет отображаться не как диск, а как “PCI ID” в левой панели, не теряйте.
ВНИМАНИЕ! Это НЕ ID диска, НЕ его серийник, это ID слота PCI.
Если вы переставите диск в другой слот, то нужно будет снова его добавлять.
Но что более ВАЖНО, если вы на его место поставите другой диск, он автоматически пробросится (если не делали изоляцию – то автоматически не пробросится, только при запуске виртуалки). То есть, если вы поменяете его местами, скажем, с системным диском хоста, будет грустно.
Перед такими делами удалите диск из виртуалки, а потом добавьте снова!
Идем в Boot Options и там выбираем тот самый “PCI ID”. Все. Было просто, да?
В безопасный режим желательно входить, когда меняется системный диск, диск тот же, но для Windows был Red Hat, стал не Red Hat – смена диска.Windows должна загрузиться в безопасный режим, выходим из безопасного режима:
bcdedit /deletevalue {current} safeboot
Теперь в диспетчере задач в Performance вы увидите не Red Hat че-то там, а прям свой диск.
Так как изоляцию мы не делали, проброс динамический, когда виртуалка выключена – хост видит диск, когда включена – хост не видит диск. Делать изоляцию смысла особо нету, это ничего не прибавит. Но если вдруг система решит что-то сделать с диском в момент запуска виртуалки, то в худшем случае будет kernel panic :D
Но это не так важно, ничего не сломается. Самое главное, чтобы диск не был примонтирован во время запуска виртуалки, иначе ФС может быть разрушена :)
Когда диск УЖЕ будет в виртуалке, хост ничего с ним не сделает (только если вы не балуйтесь вкл/выкл виртуалкой как светом в комнате). Если вы все-таки хотите его изолировать, то см. Про проброс VFIO.
Вот небольшое сравнение скоростей:
- Голый метал: 6500/6300
- VirtIO: 6300/6100
- VFIO: 6420/6330
Установка Windows
На этапе установки Windows, конкретно выбора диска, вас постигнет ужас, но вы не бойтесь, тыкайте на Load Driver –> “virtio-win\viostor\w11\amd64” и установите это. Ну, а дальше как обычно.
После установки ОС, VirtIO & Windows ISO можно удалить из девайсов, они больше не нужны.
Периферия – Клавиатура и мышь
Рано или поздно это нужно было бы решить, и по-уму – evdev passthrough.
Ищем нужные устройства (нужны mouse и kbd):
ls /dev/input/by-id/ | grep event
В моем случае usb-COMPANY_USB_Device-if01-event-mouse и usb-I-CHIP_MMD_KM40_Receiver_1234-event-kbd.
Добавляем устройства в cgroup_device_acl (придется поискать и изменить, или просто добавить свое – обычно оно все закомментировано по умолчанию):
sudo nano /etc/libvirt/qemu.conf
| |
sudo sh -c 'systemctl restart virtqemud && systemctl status virtqemud'
В Virtual Machine Manager –> Edit –> Preferences: Enable XML editing.
Открываем настройки виртуалки, в Overview переходим на XML, в конце ищем </devices> и внутрь тега добавляем:
| |
Применяем, текст “пропадет”, но он не пропал, он просто переместился повыше. При запуске виртуалки ввод с хоста сразу же пропадет и уйдет в виртуалку. Переключение LCtrl + RCtrl .
Медиа клавиши работать не будут, чтобы они работали их тоже надо добавить, обычно они if01, но я не рекомендую этого делать, потому что далее по настройке звука мы сделаем красиво.
Так же обратите внимание, что донгл и USB провод разные вещи, если вы добавите только что-то одно, то при другом работать не будет (зависит от поведения девайса).
На примере клавиатуры, вы добавили только донгл:
- Включен только донгл – работает
- Включен донгл и провод, но клавиатура принципиально начинает работать через провод – не работает
- Включен донгл и провод, но клавиатура просто заряжается, но работает через донгл – работает
Если решите добавить и то, и то – работать не будет, если что-то из этого отключено, то виртуалка откажется запускаться. Решается через симлинки udev, опишу про это потом.
Pinning CPU ядер & HugePages
Самое интересное и простое. Но для начала предисловие.
У дох*я ядерников Intel не совсем дох*я ядер. Есть P-ядра – производительные, и E-ядра – энергоэффективные, производительные мощные, энергоэффективные так “на подсосе”. Ну скажем легенда i5-14600K, у него 14 ядер, верно? Но…
6 P-ядер и 8 E-ядер, то есть 6 реально крутых ядер, и 8 таких себе ядер. Но (еще раз), в разгоне энергоэффективные ядра бустятся с 2.6 ГГц до 4.0 ГГц, не то чтобы сильно много, но уже не на подсосе. Производительные же с 3.5 ГГц до 5.3 ГГц. Независимо от того в разгоне у вас или нет, кидайте мощные ядра + их потоки в виртуалку, а хосту оставляйте все энергоэффективные. Вот и все.
С AMD все проще, у них нету понятия энергоэффективные ядра. Не придется детектить P и E ядра, нужно будет только связать ядра с потоками, но с AMD особенно с Zen 4 (AM5 сокет) понять какой поток к какому ядру как два пальца. Но (снова), есть исключения, у дох*я ядерников AMD, 12-16 ядер типа R 9, там ядра разделены на два чиплета, и ну… вот лучше не надо в виртуалку кидать кучку ядер с одного чиплета и кучку с другого, лучше только с одного.
lscpu -e=CORE,CPU,CLUSTER,SOCKET,MINMHZ,MAXMHZ,MHZ
- CORE – ядро
- CPU – поток
- CLUSTER – чиплет
У меня не R 9, поэтому точнее показать и сказать, как делать не смогу, у меня просто Ryzen на AM5:
| |
От 0 до 7, у меня 8 ядер, но как обычно оно бывает в таких делах – счет идет не с 1, а с нуля, то есть 0-7 = 1-8 ядер = 8 ядер.
Нужно найти совпадения, ну например CORE 0, мы видим, что в правой колонке напротив нуля есть 0 и 8, это близнецы, то есть это одно целое ядро с двумя потоками (потому что SMT/HT). Далее второе ядро (которое помечено как 1), имеет 1 и 9. То есть вот я нашел 2 ядра и их 2 потока, что суммарно 4 потока, которые я отдам хосту:
- 0,8
- 1,9
Остальные (12 штук) уйдут виртуалке:
- 2,10
- 3,11
- 4,12
- 5,13
- 6,14
- 7,15
Видите? С AMD с одним чиплетом все просто!
Боже, благослови QEMU диспетчер.
Создаем диспетчер, очень удобная и универсальная штука, так же может пригодиться потом для хуков других виртуалок:
sudo nano /etc/libvirt/hooks/qemu
dispatcher.sh
Loading file...Создаем директории с хуками:
VM="win11"; sudo mkdir -p /etc/libvirt/hooks/qemu.d/"$VM"/prepare/begin/ /etc/libvirt/hooks/qemu.d/"$VM"/release/end/
Где win11 название вашей виртуальной машины, узнать можно sudo virsh list --all.
Хук при старте виртуалки:
sudo nano /etc/libvirt/hooks/qemu.d/win11/prepare/begin/50-cpu-pinning-and-hugepages.sh
50-cpu-pinning-and-hugepages.sh
Loading file...Хук при выключении виртуалки:
sudo nano /etc/libvirt/hooks/qemu.d/win11/release/end/50-cpu-pinning-and-hugepages.sh"
50-cpu-pinning-and-hugepages.sh
Loading file...Не забудьте в скриптах поменять потоки ядер и настроить hugepages сколько вам надо. Про hugepages так же будет доп. информация далее, и так же таблица с примерами.
Даем права на исполнение:
sudo chmod +x /etc/libvirt/hooks/qemu
И для хуков:
VM="win11"; sudo find /etc/libvirt/hooks/qemu.d/"$VM" -type f -name '*.sh' \( -path '*/prepare/begin/*' -o -path '*/prepare/end/*' -o -path '*/release/begin/*' -o -path '*/release/end/*' \) -exec chmod +x {} +
Перезапускаем сервис, чтобы обновить хуки:
sudo sh -c 'systemctl restart virtqemud && systemctl status virtqemud'
В моем случае 6 ядер с SMT, то есть 12 потоков. В настройках виртуалки –> CPUs, Cores ставим кол-во ядер (в моем случае 6), а в Threads кол-во потоков на ядро (в моем случае 2) и применяем. Sockets это кол-во процессоров, ставьте 1.
В настройках виртуалки Overview - XML ищем <vcpu placement="static">X</vcpu>, где X какое-то общее кол-во потоков. Вписываем нужное значение:
| |
Здесь cpuset это ядро вашего процессора, а vcpu это поток внутри VM, 12 виртуальных потоков это от 0 до 11, справа я назначаю им РЕАЛЬНЫЕ потоки с хоста. Нужно назначить виртуальной паре – реальную пару (см. выше).
emulatorpin говорит хосту использовать для “поддержания” жизни KVM вот эти ядра, то есть в моем случае указаны ядра, что я оставил хосту – первые 2 ядра (4 потока), то есть чтобы виртуалка не лезла на ядра, что выделены гостю.
Если вы пробрасывали диск через VirtIO, а не VFIO, то после <emulatorpin/> добавьте:
| |
Перезапускаем сервис:
sudo sh -c 'systemctl restart virtqemud && systemctl status virtqemud'
HugePages в XML нужно добавить сразу после тега <currentMemory>:
| |
А также изменить:
| |
Где X – GB * 1048576 , например 42 GB * 1048576 = 44040192 KiB. Указывать это надо очень точно.
Примеры:
| GB | TARGET (хук) | KiB (XML) |
|---|---|---|
| 8 | 4096 | 8388608 |
| 16 | 8192 | 16777216 |
| 24 | 12288 | 25165824 |
| 32 | 16384 | 33554432 |
| 42 | 21504 | 44040192 |
| 48 | 24576 | 50331648 |
Про memoryBacking (size="2") и hugepages-2048kB, размер страницы решает, самый такой крутой вариант это 1024 и hugepages-1048576kB — 1gb, но это как фрагментация диска. Хосту будет (вероятно очень) проблематично найти нужный объем памяти по 1 непрерывному гигабайту, потому что ОЗУ нелинейна. Но задержки станут еще меньше. 2mb это компромисс. Важно, меньше нельзя, больше нельзя, работает только 4kb (дефолт системы), 2mb, 1024mb (1gb) и все.
Также проверить, что hugepages выделены (после запуска VM) можно так:
cat /proc/meminfo | grep Huge
Проброс dGPU
Варианта два. Топорный, но 100%, требует перезагрузки для “переключения режима”. И изящный, но может не сработать. Изящный вариант, это переключение на горячую, запустили виртуалку – dGPU улетела в виртуалку, выключили виртуалку – dGPU вернулась хосту, ах*ено шо пизд*ц. Но это сложно. Может работать сейчас, но перестать потом. Если изящный способ перестанет работать у меня, я обязательно обновлю текст, если у вас… ну тут как бы, я не вы, я не знаю, что у вас.
В начале ПЕРВЫМ делом! Включите ssh сервер, если что-то пойдет не так, пропадет изображение, или еще что – вы могли зайти с телефона и исправить проблему:
sudo sh -c 'systemctl enable --now sshd && firewall-cmd --permanent --add-service=ssh && firewall-cmd --reload && systemctl status sshd'
Когда закончите все делать, ssh сервер можно (и лучше, если не нужен он вам) отключить:
sudo sh -c 'systemctl disable --now sshd && firewall-cmd --permanent --remove-service=ssh && firewall-cmd --reload && systemctl status sshd'
Разлогиньтесь и на экране входа выберите Wayland.
Теперь заставим Wayland работать с iGPU, иначе после проброса dGPU может пропасть изображение.
Узнаем PCI iGPU в десятичной системе (hex to decimal):
lspci -D | grep -E "VGA|3D|Display" | grep -v "NVIDIA" | awk -F'[:. ]' '{printf "\n%s:%s:%s.%s (hex) => PCI:%d:%d:%d (decimal)\n\n", $1, $2, $3, $4, strtonum("0x"$2), strtonum("0x"$3), strtonum("0x"$4)}'
Вывод:
0000:11:00.0 (hex) => PCI:17:0:0 (decimal)
Для AMD:
| |
sudo zypper install xf86-video-amdgpu
Для Intel:
| |
Если Driver “modesetting” не сработал, и вы используете “intel”, то:
sudo zypper install xf86-video-intel
Учтите, что “xf86-video-intel” не обновляется и так себе работает на intel >=11 поколения, и в любом случае – в приоритете использовать Driver “modesetting” для Intel.
Если забыли PCI:
lspci | grep -E "VGA|3D|Display"
Вывод:
01:00.0 VGA compatible controller: NVIDIA Corporation AD104 [GeForce RTX 4070] (rev a1)
11:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Raphael (rev c5)
На этот раз нужно просто 11:00.0. Далее находим DRM устройство по PCI:
ls -la /dev/dri/by-path/ | grep "11:00.0"
Вывод:
lrwxrwxrwx. 1 root root 8 Jun 15 13:11 pci-0000:11:00.0-card -> ../card0
lrwxrwxrwx. 1 root root 13 Jun 15 13:11 pci-0000:11:00.0-render -> ../renderD128
Передаем устройство в KWin – pci-0000:11:00.0-card :
mkdir -p ~/.config/systemd/user/plasma-kwin_wayland.service.d
| |
sudo nano /etc/environment
| |
Обратите внимание на \, это экранирование :, так надо.
systemctl --user daemon-reload
Если вы собираетесь делать горячий проброс – рекомендую прочитать про холодный проброс, знание поможет вам.
NVIDIA (Холодный проброс; VFIO со старта)
sudo nano /etc/modprobe.d/vfio.conf
Там:
install vfio-pci /sbin/vfio-pci-override.sh
Далее:
lspci -nnk | grep -A3 -i nvidia
| |
Записываем 01:00.0 и 01:00.1.
sudo nano /sbin/vfio-pci-override.sh
| |
К тому, что записали ранее, добавляем 0000: – 0000:<ваше_значение> (как в скрипте). Делаем скрипт исполняемым:
sudo chmod +x /sbin/vfio-pci-override.sh
Далее:
sudo nano /etc/dracut.conf.d/vfio.conf
| |
Пересобираем initramfs:
sudo sdbootutil --no-reuse-initrd add-all-kernels
YaST –> System –> Boot Loader –> Kernel Parameters в конце:
| |
Перезагружаемся. Проверяем:
lspci -nnk | grep -A3 -i nvidia
Должно быть Kernel driver in use: vfio-pci:
| |
В настройках виртуалки добавляем новое PCI Host Device устройство (dGPU и ее Audio) как мы делали это с диском, и там же удаляем Display Spice и затем Video <X> (например Video Virtio или Video QXL).
Иначе “этот” дисплей определится Windows и будет как второй/третий… дисплей, ну вы поняли, мешаться будет крч.
NVIDIA (Горячий проброс)
Я делал это с проприетарным драйвером NVIDIA, для НЕ проприетарного драйвера нужно немного поменять скрипты. Как по мне видеокарта NVIDIA без проприетарных драйверов – бесполезна. Поэтому вот так.
Заставляем KWin работать с iGPU, чтобы в будущем отпустил dGPU.
mkdir -p ~/.config/environment.d
Указываем PCI iGPU (lspci | grep -E "VGA|3D|Display"):
| |
systemctl --user daemon-reload
Перезагружаемся.
Проверить можно командой с PCI iGPU:
sudo lsof /dev/dri/by-path/pci-0000:11:00.0-card | grep kwin
Что-то будет. И с PCI dGPU:
sudo lsof /dev/dri/by-path/pci-0000:01:00.0-card | grep kwin
Должно быть пусто. WARNING’и не в счет.
Так же доп. проверка если у вас NVIDIA:
sudo lsof /dev/nvidia* /dev/dri/by-path/pci-0000:01:00.0*
Вот тут вообще должно быть пусто. Но если там что-то есть, и это не что-то системное типа KWin, то нестрашно, хук или ваши руки просто могут убить процесс и все. А вот если это KWin, то так не получится.
Структуру хуков и диспетчер мы настраивали выше в Pinning CPU ядер & HugePages, если вы это пропустили, метнитесь туда, сделайте и вернитесь сюда.
Не забудьте в скриптах поменять PCI на свои.
sudo nano /etc/libvirt/hooks/qemu.d/win11/prepare/begin/10-dgpu-nvidia-detach.sh
detach.sh
Loading file...sudo nano /etc/libvirt/hooks/qemu.d/win11/release/end/90-dgpu-nvidia-attach.sh
attach.sh
Loading file...Сделать хуки исполняемыми:
VM="win11"; sudo find /etc/libvirt/hooks/qemu.d/"$VM" -type f -name '*.sh' \( -path '*/prepare/begin/*' -o -path '*/prepare/end/*' -o -path '*/release/begin/*' -o -path '*/release/end/*' \) -exec chmod +x {} +
Где win11 имя вашей VM.
(KDE), в случае если у вас нету KDE просто ничего не будет. Если KDE есть, но вы не используете KDE то, что-то будет, что-то, что вам вероятно не нужно.Перезапускаем сервис, чтобы обновить хуки:
sudo sh -c 'systemctl restart virtqemud && systemctl status virtqemud'
Тут есть неочевидная проблемка. Если вырубят свет или вы решите пнуть кнопку выключения ПК, пока виртуалка запущена, скрипт на выключение не выполнится. А повторный запуск виртуалки не увенчается успехом, потому что выгружать будет нечего. В таком случае нужно будет выполнить скрипт “при выключении” вручную, ничего особенного.
Последний шаг – посмотреть самый конец главы выше (про добавление PCI dGPU и удаление других устройств).
Периферия – Звук
Все работает, а звука нет, ща исправим. Это также будет работать и с микрофоном.
Будет на примере “PulseAudio (on PipeWire 1.6.7)” – это означает, что реально PipeWire, PulseAudio для совместимости. Узнать что у вас можно pactl info.
sudo zypper in -y qemu-audio-pa qemu-audio-pipewire
Проверить можно:
qemu-system-x86_64 -audiodev help
Должны были появиться pa и pipewire.
Если все ок, перезапускаем сервис:
sudo sh -c 'systemctl restart virtqemud && systemctl status virtqemud'
Создаем конфигурацию:
mkdir -p ~/.config/pipewire/pipewire-pulse.conf.d
| |
Рестартим pipewire сервис:
systemctl --user restart pipewire-pulse
Проверка:
ss -tlnp | grep 4713 && pactl --server=127.0.0.1:4713 info
Должно быть так:
| |
В настройках виртуалки удаляем существующий “Sound X” и создаем новый - ICH9. Далее Overview и там в XML внутри <devices>:
| |
И добавить <audio id="1"/> внутрь тега <sound>.
До запуска виртуалки проверить можно командой:
sudo virsh dumpxml win11 | grep -A3 audio
Это микширование звука, настройте под себя звук внутри VM, а также в микшере хоста. И если помните, я советовал не пробрасывать медиа клавиши клавиатуры, благодаря этому если выровнять звук гостя под хост, чтобы они были примерно одинаковыми, то находясь в госте с захватом клавиш и тыкая на медиа клавиши – вы будете менять сразу и гостя и хост, прям как на “просто одной системе”.
Скрытие и ускорение виртуалки
Это базовое скрытие, полное KVM скрытие – это целая наука и конечно же патчинг QEMU и ядра Linux, что уже труднее и описано здесь не будет, но возможно когда-нибудь я про это напишу. А ускорение это так называемое “Hyper-V Enlightenments” (что тесно связано с базовым, но современным скрытием), чтобы для каких-то вещей не происходил тяжелый VM Exit в хост, а инструкции шли как для Hyper-V (родная среда виртуализации Windows).
Да, казалось бы небольшое противоречие, скрыть факт виртуализации, но при этом прямо сказать системе, что она виртуалка, кажется таким себе решением, но это типа окей.
Все делается в XML, я думаю, вы к этому времени там уже много раз побывали.
В <cpu> у вас уже должно быть типа такого:
| |
Туда же внутрь <cpu> нужно добавить:
| |
А также заменить migratable="on" на migratable="off".
Если у вас AMD (с SMT, а я надеюсь, что с SMT) то также добавить <feature policy="require" name="topoext"/>.
Блок <features> должен выглядеть так:
features.xml xml
Loading file...А блок <clock> должен выглядеть так:
clock.xml xml
Loading file...Найдите в самом верху тег “uuid” и скопируйте значение, также выполните:
sudo dmidecode -s baseboard-serial-number
И скопируйте полученное значение тоже, даже если там “Default string” :D
Вставьте в XML после </cputune>:
sysinfo.xml xml
Loading file...Не забудьте поменять серийник и UUID.
Найдите <os> и добавьте внутрь:
| |
Также ищем <interface type="network">, там меняем MAC адрес на 00:15:5D:xx:xx:xx, где X’ы любое значение, но не 00 и FF. После в госте проверить можно ipconfig /all. 00:15:5D это MAC hyper-v, а 52:54:00 – qemu.
И уберите из <devices>:
| |
Также в самом конце найдите memballoon, и сделайте так (выключите):
| |
memballoon по сути не используется, но существует и делает вызовы, зачем ему делать вызовы и потенциально вызывать фризы, если он не работает, правильно? Также в Windows если заметили процесс “blnsvr.exe” в диспетчере, можно отключить BallonService в сервисах, иначе он так же будет работать вхолостую.
В диспетчере задач “Virtual Machine: Yes”, никуда не пропадет, цель сделать современно и не потерять в производительности, а значит не прям скрыть-скрыть факт виртуализации, а сделать вид, что это “легальная” виртуализация. В терминале – systeminfo, если в самом низу “A hypervisor has been detected. Features required for Hyper-V will not be displayed.” – значит все работает.
Этот статус появляется, если вы включаете в системе Core Isolation или WSL, то бишь это абсолютно легальные функции которые тригерят этот статус. А производительность лучше, потому что Windows не эмулирует вызовы, а использует быстрые “родные” Hyper-V.
Благодаря этим манипуляциям мой средний FPS в бенчмарке Cyberpunk 2077 стал 140 –> 162, в то время как на голом железе он 163. Уровень погрешности. Удивительно, неправда ли?
Настройка сети
Просто небольшая правка, чтобы закрепить IP адрес за виртуалкой (чтобы он не менялся).
В настройках виртуалки –> NIC и там скопируйте MAC адрес.
Далее в главном окне со списком виртуалок –> тык на виртуалку –> Edit –> Connection Details –> Virtual Networks –> XML, в блок dhcp добавить:
| |
Применить, и в том же окне нажать на кнопку Stop Network, затем Start Network.
Проверить можно введя ipconfig в терминале Windows.
Гостевые дополнения
В Windows можно в любом случае или нет установить “гостевые дополнения”, вы можете сделать это сразу, или не делать если оно вам не нужно.
Этот раздел в основном нужен, чтобы ссылаться на него, когда это нужно установить, поэтому в любом случае если это будет нужно, вы об этом узнаете.
Перейти на https://www.spice-space.org/download.html и в разделе “Windows binaries” скачать и установить “spice-guest-tools”.
А также переходим на https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/ качаем и устанавливаем “virtio-win-guest-tools.exe”.
Перезагружаем Windows, разумеется.
Общий буфер обмена и общие папки (Samba)
Самое удобное удобство. Если вкратце, что мы сделаем:
- Общий буфер обмена включая текст и пикчи (только если MIME тип изображения – скриншоты).
- Шара Samba.
- Скрипт для удобного “копирования” файлов на шару без траты TBW (ну чтоб наверняка).
Буфер обмена
Мини предисловие. Я пробовал нативно, много пробовал. Конкретно через полу-spice, как spice только не spice, без графики. Но Wayland не дает читать буфер обмена пока окно не в фокусе, то есть:
копировать –> ткнуть окно spice –> вставить. Неудобно, но конечно же есть костыль с GDK_BACKEND=x11.
Но это не все мины подводные, text/plain работает в обе стороны, но без русского текста. text/plain\;charset=utf=8 работает только из гостя в хост, из хоста в гостя см. воркфлоу выше. Ну и конечно же постоянно ломающееся окружение (полностью нерабочая панель задач и “пуск”) из-за GDK_BACKEND=x11. И еще пара десятков проблем, а потому…
ClipCascade
ClipCascade это такая софтина для (барабанная дробь) шеринга буфером обмена по сети, и все, только для этого. Прям то что надо. С этим способом будет небольшая задержка передачи данных буфера обмена между системами, но пока вы переключаете ввод, чтобы вставить оно уже передаст. Без докера будет тяжко.
sudo zypper in docker-compose docker-compose-switch wl-clipboard
sudo systemctl enable --now docker
sudo usermod -G docker -a $USER
newgrp docker
sudo systemctl restart docker
mkdir -p ClipCascade && cd ClipCascade && nano docker-compose.yaml
| |
mkdir cc_users
docker compose up -d && docker compose logs -f
Далее клиент, качаем архив с репозитория GitHub и распаковываем куда удобно.
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python main.py --gui false --xmode false
--xmode false – это для Wayland.
Попросит войти, логин:пароль – admin:admin123 , остальное тыкайте Enter (или сначала прочитайте текст ниже).
На Windows качаем .exe (portable) или .msi (установщик) отсюда https://github.com/Sathvik-Rao/ClipCascade/releases, если .exe то создаем папку и кидаем туда .exe. Авторизация по тем же данным, но Server URL: http://192.168.122.1:8080.
Крутейшие данные для авторизации в этом случае менять не обязательно (ТОЛЬКО В ЭТОМ СЛУЧАЕ), потому что мы гоняем данные по сети хоста, ничего за пределы вашего ПК не уходит.
Соответственно шифрование тоже можно не использовать, будет работать быстрее и стабильнее.
А также в доп. настройках можно сделать, чтобы пароль сохранялся в файл, тогда не придется каждый раз авторизоваться после перезапуска докер контейнера (а это значит после перезагрузки хоста).
Если все работает то круто. Надо только это автоматизировать, ClipCascade создает DATA файл, там уже все есть, нужно просто запускать приложения в фоне.
Для начала докер, формально уже все есть, но докер стартует раньше libvirt, как итог – он не стартует, потому что нет сети. Варианта два, глобальный для ВСЕХ контейнеров и разовый юнит, предлагаю юнит:
sudo nano /etc/systemd/system/clipcascade-server-docker.service
| |
Не забудьте указать свои пути.
sudo systemctl daemon-reload
sudo sh -c 'systemctl enable --now clipcascade-server-docker.service && systemctl status clipcascade-server-docker.service'
Далее демон клиента ClipCascade:
nano ~/.config/systemd/user/clipcascade.service
| |
%h/ = /home/username/ (работает только в юзерских сервисах).
systemctl --user daemon-reload
systemctl --user enable --now clipcascade.service && systemctl --user status clipcascade.service
Логи можно так поглядеть:
journalctl --user -u clipcascade.service -f
Далее Windows.
Если portable:
Просто сделайте ярлык с ALT и киньте его в WIN + R –> shell:startup.
Если установщик:
Ничего не делать.
Общее:
В параметрах в поиске Firewall –> Windows Defender Firewall –> Allow an app or feature… –> сюда добавить ClipCascade.exe. Чисто на всякий случай.
WIN + R –> intl.cpl –> Administrative –> Change system locale – Use Unicode UTF-8…, и перезагрузить, иначе без этого возможно не сможете копировать и вставлять не английский текст.
Другая автоматизация:
Если вас не устраивает постоянная работа ClipCascade в фоне на хосте, все-таки это Java которая отжирает в среднем 400-900мб ОЗУ просто потому что это Java, можно запуск и выключение запихнуть в хуки.
Далее нужно переключить docker на тот же бэкенд, который использует libvirt в вашей системе, в случае openSUSE это nftables.
Далее где virbr0 – ваш бридж KVM, по дефолту (сеть “default”) это именно “virbr0”. Если запускать докер до VM/при старте ОС, а потом саму VM, то все будет окей. Но если запускать сначала VM, а потом докер, то ломается сеть KVM (1, 2). Это из-за конфликта с другими “владельцами” правил сети.
То что описано ниже это экспериментальная фича в новом docker (>=29) (на момент написания этого текста), и с ней работает не все фичи docker, если у вас домашний ПК, а не сервер где нужен SLA 100% и вы не используете Swarm – то почему бы и нет.
Меняем бэкенд:
sudo nano /etc/docker/daemon.json
Туда добавляем "firewall-backend": "nftables".
Включаем ip forwarding вручную, потому что это так-то делает сам docker, но в моем случае с nftables – не делает, поэтому:
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-ip-forward.conf && sudo sysctl --system
sudo systemctl restart docker && docker ps && systemctl --user restart clipcascade.service && systemctl --user status clipcascade.service
Проверяем, что оно сменилось:
sudo nft list tables
Там должно быть ip docker-bridges/ip6 docker-bridges.
Далее выключаем сервис/клиент и их автозапуск (если вы это включали ранее):
sudo systemctl disable --now clipcascade-server-docker.service && systemctl --user disable --now clipcascade.service
И делаем хуки:
sudo nano /etc/libvirt/hooks/qemu.d/win11/prepare/begin/95-clipcascade.sh
95-clipcascade.sh
Loading file...sudo nano /etc/libvirt/hooks/qemu.d/win11/release/end/95-clipcascade.sh
95-clipcascade.sh
Loading file...Сделать хуки исполняемыми:
VM="win11"; sudo find /etc/libvirt/hooks/qemu.d/"$VM" -type f -name '*.sh' \( -path '*/prepare/begin/*' -o -path '*/prepare/end/*' -o -path '*/release/begin/*' -o -path '*/release/end/*' \) -exec chmod +x {} +
Где win11 имя вашей VM.
Перезагружаем хост, чтоб прям наверняка все проверить, запускаем виртуалку, проверяем буфер обмена, затем выключаем виртуалку.
docker ps && echo && systemctl --user status clipcascade.service
Альтернативы
Если вдруг вам не нравится ClipCascade, то можно попробовать UniClipboard или вовсе KDE Connect, но возможно там не будет работать буфер изображений, только текста (насчет UniClipboard – не уверен, насчет KDE Connect – вероятно не будет).
Общие папки
Разумеется Samba, как же иначе?
Создайте или морально выберите “shared” папку, в моем случае ~/Public/KVM. У папки должны быть права 755 а.к.а drwxr-xr-x, именно с такими правами вы по умолчанию создаете папки от своего имени юзера (не root).
Открываем YaST –> Network Services –> Samba Server. Да можно было и руками, но YaST все сделает за вас, почему бы и нет.
WORKGROUP оставьте WORKGROUP, это неважно.
Start-Up:
- After writing configuration: Start
- After reboot: Start on boot
Shares:
- Add… –> Добавьте свою папку
- Share Name: Что-нибудь связанное с темой (у меня одноименно с названием папки), это вам еще понадобится
- Share Description: Если надо
- Share Type:
- Directory, а не Printer
- Share Path: выберите свою папку что создали ранее
- Read-Only: ❌
- Inherit ACLs: ❌
- Expose Snapshots: ❌
- Utilize Btrfs Features: ❌ (это про снапшоты, вроде как)
- Allow Users to Share Their Directories: ❌
Identity, Trusted Domain и LDAP Settings трогать не надо. Жмите ОК.
Далее чутка изменим конфиг:
sudo nano /etc/samba/smb.conf
В [global]:
unix extensions = no
И там же smb3 directory leases = Yes заменить на No.
Далее найти [kvm] (ваш Share Name) и туда в блок добавить:
| |
Где username ваш юзернейм. Это чтобы Windows делала файлы с правильными правами и вы могли свободно с ними работать на хосте.
testparm если все ok, то все ок.
Перезапускаем сервис:
sudo sh -c 'systemctl restart smb nmb && systemctl status smb nmb'
Установить пароль для юзера samba:
sudo smbpasswd -a username
Где username опять же ваш юзернейм.
Это нужно потому что иначе Windows вас за*ебет, если есть желание покопаться в реестре и групповых политиках, то можете не ставить пароль, но тогда еще придется включить Guest mode для вашей папки в samba (можно сделать в YaST).
Проверка:
smbclient -L 127.0.0.1 -N && smbclient -L 192.168.122.1 -N
Должно быть что-то типа:
| |
На обе команды. И контрольная проверка:
smbclient //192.168.122.1/KVM -N
Где KVM это ваш Share Name.
Правила фаервола, просто на всякий случай:
sudo sh -c 'firewall-cmd --zone=libvirt --add-service=samba --permanent && firewall-cmd --reload && firewall-cmd --zone=libvirt --list-services'
И если выполните:
sudo ss -tlnp | grep 445
То увидите, что samba слушает все адреса, то есть доступна для других ПК в локальной сети, или в интернете (если у вас белый IP и не закрыты порты на роутере). Если вам samba не нужна для других сценариев использования, то лучше сделать так, чтобы она слушала только localhost и сеть KVM соответственно:
sudo nano /etc/samba/smb.conf
В [global]:
| |
lo– localhostvirbr0– дефолтная (буквально “default”) сеть KVM
testparm
sudo sh -c 'systemctl restart smb nmb && systemctl status smb && systemctl status nmb && sudo ss -tlnp | grep 445'
Если вы сделали interfaces = lo virbr0
При настройке общего буфера обмена мы делали так если он должен был запускаться вместе с системой.
Нужно поменять сервисы samba чутка:
sudo systemctl edit smb.service
sudo systemctl edit nmb.service
В оба сервиса добавить:
| |
Это нужно чтобы samba стартовала строго после kvm сети, иначе она упадет потому что сети еще не будет.
Для справки, в чем прикол, если сделать это только для сервиса буфера обмена и запускать его вместе с системой, он будет тригерить запуск kvm сети, из-за чего samba будет работать с interfaces = lo virbr0, но если не запускать сервис буфера обмена вместе с системой то samba не будет работать без этих правок. Но так или иначе лучше это добавить в любом случае если вы используете interfaces = lo virbr0, независимо от того как вы запускаете сервис буфера обмена, так банально надежнее.
В Windows, ПКМ по This PC –> Map network drive –> Folder – \\192.168.122.1\KVM. Connect using different credentials, там ваш username и пароль, и галочка на Remember my credentials. И не забудьте про галочку “Reconnect at sign-in”, чтобы он автоматом подключался.
И проверьте, что все работает, посоздавайте файлы, и проверьте права на хосте ls -l.
Скрипт для симлинков (если надо).
rl.sh
Loading file...nano ~/Scripts/rl.sh
chmod +x ~/Scripts/rl.sh
ln -s ~/Scripts/rl.sh ~/.local/bin/rl
В начале скрипта укажите пути до папок/симлинков на шаре.
Чтобы использовать просто введите rl это help.
rl file– сделать симлинк на файлrl dir/– сделать симлинк на директориюrl file1 file2 dir1 dir2– сделать 4 симлинка.
Скрипт сам детектит диск, если вы делаете симлинк на файл/директорию которые находятся на “Disk 1”, то и симлинк он кинет в “Disk 1” на шаре, аналогично с “Disk 2” и тд. и тп.
Про симлинки на директории, Windows удаляет папки рекурсивно, поэтому при удалении симлинков директорий на Windows, Windows заходит внутрь (так как не знает что это симлинк) и удаляет содержимое. У Windows такого страшного дела сделать не получается и папка не удаляется. Короче говоря, симлинки на папки можно удалять только с хоста.
Если шарите второй диск (для системного диска так лучше не делать!), а он просто не работает (DENIED) и у вас SELinux (на момент написания текста у openSUSE по дефолту SELinux), не забудьте про:
sudo semanage fcontext -a -t samba_share_t "/mnt/second(/.*)?"
sudo restorecon -R -v /mnt/second
Проверить можно так:
sudo semanage fcontext -l | grep second
Где second ваша точка монтирования. Должно вывести samba_share_t.
Дополнительно
Аппаратные штуки
По умолчанию аппаратные фичи отключены по юридическим причинам. Так то темы виртуализации это особо не касается, а скорее про настройку ОС. Но может быть такое, что виртуалка не сможет использовать эти фичи, если их нету на хосте, поэтому я это и добавил, а оно так потому что host-passthrough – дает виртуалки юзать аппаратные фичи процессора.
Аппаратные фичи можно проверить:
grep -E "aes|sha" /proc/cpuinfo
Будет полотно текста, ищите наличие aes и sha. А также:
sudo zypper in libva-utils
vainfo
Если в списке отсутствует H.264 и H.265, то они отключены и их бы включить.
sudo zypper in opi
opi codecs
И со всем соглашайтесь в процессе. Если в процессе все встало и вы видите 403 ошибку, расчехляйте ВПН друзья и попробуйте снова (то что уже установило оно устанавливать не будет).
На будущее, при обновлении системы zypper dup, если будут ошибки с пакетами, так как в openSUSE могли их обновить, а в packman еще нет, выбирайте вариант в стиле “оставить старые версии” и просто попробуйте еще раз через пару дней, иначе лишитесь кодеков.
Снова проверяем:
vainfo
И наблюдаем новые кодеки.
Проверить в Windows это тоже можно.
Для CPU:
Проверить можно через CPU-Z, а конкретно “Instructions”.
Для dGPU (NVIDIA):
nvidia-smi
Должно вывести таблицу. В диспетчере задач в Performance –> GPU должны быть Video Encode и Decode.
Looking Glass (альтернатива переключению на мониторе)
LookingGlass – альтернатива физическому переключению видеовыхода на мониторе, дает больше задержек, и сильнее нагружает систему, но удобно для работы или легких игр типа Kenshi или Sims. Ну, точнее, вам ничего не мешает использовать LG для чего угодно, но нативная картинка прямиком из GPU всегда будет лучше.
Очевидный плюс это окошко, что существует в хосте, а значит вам по-прежнему будут доступны монитор(ы) хоста и при этом вы сможете свободно крутить, вертеть, перемещать, “сворачивать Windows”, удобно.
Все же однажды мечтали “свернуть” Windows?
Looking Glass также умеет пробрасывать клавиатуру, мышь, буфер обмена и звук, что довольно удобно. Но работать это будет через spice, что довольно неудобно, ну на Wayland. Поэтому учитывая что я показывал как все это настроить по отдельности – мы настроим LG чтобы только на Windows глазами глядеть, не более.
Для гостя нужны virtio драйвера см. здесь.
Нужно установить пакеты, но из-за того, что один из пакетов – это kmp, в идеале сначала обновить всю систему sudo zypper dup и перезагрузить ПК. Иначе оно может в качестве зависимости обновить ядро Linux без обновления всего остального, что не есть хорошо.
Пакеты:
sudo zypper install looking-glass-client looking-glass-kvmfr-kmp-default
Looking Glass не умеет в больше 1-го монитора, и Looking Glass захватит тот, что в госте ОСНОВНОЙ. То есть, размер надо рассчитывать исходя из монитора который будет захватываться.
Математика такая:
$$ ((width \times height) \times (pixel\_size \times 2) \div 1024 \div 1024) + 10 \ МиБ $$
Это размер кадра в МиБ + оверхед в 10 МиБ для служебных данных, это нужно округлить до ближайшей степени двойки.
У SDR (32-бит) pixel_size = 4, у HDR (64-бит) = 8.
Ну например FULLHD SDR:
$$ ((1920 \times 1080) \times (4 \times 2) \div 1024 \div 1024) + 10 = 25.8 \approx 32 \ МиБ $$
По порядку
- $\ 1920 \times 1080 = 2073600$
- $\ 2073600 \times 8 = 16588800$
- $\ 16588800 \div 1024 = 16200$
- $\ 16200 \div 1024 = 15.8203125$
- $\ 15.8203125 + 10 = 25.8203125$
- $\ 25.8203125 \to 2^{\lceil \log_2 25.8203125 \rceil} = 32$
Примеры:
| Разрешение | Кадр | + 10 МиБ | Округление до степени 2 |
|---|---|---|---|
| 1920×1080 | 15.8 МиБ | 25.8 МиБ | 32 МиБ |
| 2560×1440 | 28.1 МиБ | 38.1 МиБ | 64 МиБ |
| 3440×1440 (ultrawide) | 37.8 МиБ | 47.8 МиБ | 64 МиБ |
| 3840×2160 (4K) | 63.3 МиБ | 73.3 МиБ | 128 МиБ |
Если вы не минималист, у вас не супер-дупер 32к телевизор и вы не хотите париться – просто делайте 256 МиБ.
Настройка модуля:
echo "options kvmfr static_size_mb=32" | sudo tee /etc/modprobe.d/kvmfr.conf
Где 32 – тот самый размер в МиБ.
echo kvmfr | sudo tee /etc/modules-load.d/kvmfr.conf
sudo modprobe kvmfr
Проверка:
ls -la /dev/kvmfr0
udev (права доступа):
sudo nano /etc/udev/rules.d/71-kvmfr.rules
SUBSYSTEM=="kvmfr", GROUP="kvm", MODE="0660"
sudo sh -c 'udevadm control --reload-rules && udevadm trigger'
В /etc/libvirt/qemu.conf добавить "/dev/kvmfr0" в cgroup_device_acl.
Перезапустить сервис:
sudo sh -c 'systemctl restart virtqemud && systemctl status virtqemud'
Далее:
sudo EDITOR=nano virsh edit <имя_вашей_vm>
Там в самом начале:
| |
И в самом конце, после закрывающегося </devices>, но до закрывающегося </domain> добавить:
| |
33554432 – это 32 МиБ, но в байтах, $32 \times 1024 \times 1024$ .
Проверка:
sudo virsh dumpxml <имя_вашей_vm> | grep -A6 "qemu:commandline"
Поясняю “а че так”. Virtual Manager (GUI) просто не дает отредачить/добавить эти параметры, они просто удалятся при сохранении.
Но, если добавить через virsh edit, а потом менять какой-то XML через Virtual Manager – оно уже не будет удаляться.
Далее конфиг:
mkdir -p ~/.config/looking-glass && nano ~/.config/looking-glass/client.ini
| |
Также рекомендую:
| |
Самое главное, это escapeKey, курсор по желанию. У вас есть клавиша Scroll Lock? А вы о ней хоть раз слышали? Ну вот в LG эта клавиша модификатор по умолчанию, настройка выше ее меняет, зажимаете и видите меню + можете еще тут глянуть.
Если щас запустите LG то получите ошибку о том что Host приложение (на госте) не работает, если так, то хорошо.
На Windows качаем Windows Host Binary вот тут https://looking-glass.io/downloads и устанавливаем.
Permission denied
Если при запуске виртуалки получаете ...can't open backing store /dev/kvmfr0 for guest RAM: Permission denied, то вероятно это SELinux, так как он включен по умолчанию на openSUSE.
Отключать я это не рекомендую, но чтоб наверняка:
sudo getenforce
Или глобально проверить параметр grep '^SELINUX=' /etc/selinux/config.
Если Enforcing – значит включено. Выполните:
sudo setenforce 0
Это переключит в permissive, попробуйте снова запустить виртуалку. Если сработало это из-за SELinux.
Если так. Для начала переключаем обратно:
sudo setenforce 1
Далее:
sudo sh -c 'semanage fcontext -a -t svirt_image_t '/dev/kvmfr0' && restorecon -v /dev/kvmfr0'
Проверка:
ls -Z /dev/kvmfr0
Должно быть svirt_image_t.
А также:
sudo nano /etc/udev/rules.d/71-kvmfr.rules
Туда в конец добавить:
...MODE="0660", RUN+="/usr/sbin/restorecon %E{DEVNAME}"
sudo sh -c 'udevadm control --reload-rules && sudo rmmod kvmfr && sudo modprobe kvmfr && ls -Z /dev/kvmfr0'
Сходу в Looking Glass у вас вероятно будет мыло, чтобы его не было окно LG надо открыть fullscreen, прям вот полный-полный экран, как игры например обычно открываются.
Либо же, если вы хотите ощутить нереальный дзен на WM, ну например Niri, выполняете niri msg windows, ищите там размер окна LG, и через NVIDIA, AMD, Intel создаете кастомное разрешение монитора. Уф! Как же это стильно выглядит :D
Скрипт переключения VFIO (Холодный проброс)
Положите куда-нибудь скрипт и конфиги, ну например:
mkdir -p /home/$USER/Scripts/vfiopt
Создайте скрипт и конфиги с нужным содержимым (см. Проброс dGPU):
touch /home/$USER/Scripts/vfiopt/vfiopt.sh /home/$USER/Scripts/vfiopt/modprobe-vfio.conf /home/$USER/Scripts/vfiopt/dracut-vfio.conf /home/$USER/Scripts/vfiopt/vfiopt.conf
(echo; head -n -0 /etc/{modprobe,dracut.conf}.d/vfio.conf; echo)
Так же в nano /home/$USER/Scripts/vfiopt/vfiopt.conf укажите PCI адрес dGPU и ее аудио:
| |
Сам скрипт:
sudo nano /home/$USER/Scripts/vfiopt/vfiopt.sh
vfiopt.sh
Loading file...sudo chmod 755 /home/$USER/Scripts/vfiopt/vfiopt.sh
Сделайте симлинк:
sudo ln -s /home/$USER/Scripts/vfiopt/vfiopt.sh /usr/local/bin/vfiopt
Перезапустите терминал. И запускать скрипт из любого места:
vfiopt
Про проброс VFIO
Как вы могли заметить в /sbin/vfio-pci-override.sh:
| |
Есть такая запись, в нее можно добавить не только видеокарту, а что угодно, типа:
| |
И все это будет проброшено vfio.
Проброс температур GPU с гостя на хост
Для гостя нужны virtio драйвера см. здесь.
Вам это может вовсе и не нужно, но кому нужно покажу, так же учтите, что главный сценарий проброса температур нужен, если у вас горячий проброс, если у вас холодный проброс, то данный мной python скрипт можно сильно упростить.
Лично мне не хватает встроенного «Smart Fan» в биосе, потому я предпочитаю контролировать кулера процессора и корпуса, ориентируясь на температуру процессора и видеокарты по “MAX”. То есть, если греется проц, то такая кривая, если карта, то такая кривая.
Соответственно, когда карта проброшена в гостя ее температуры в хосте не доступны, а гость не имеет доступа к корпусным кулерам. Также после, я покажу свой пример, как с CoolerControl.
Текст ниже ИСКЛЮЧИТЕЛЬНО для NVIDIA GPU.
Обязательно нужны проприетарные драйвера NVIDIA как на хосте так и госте, так как мы будем использовать nvidia-smi –> NVML.
nvidia-smi это оф. утилита обертка для NVML, которая входит в проприетарный драйвер NVIDIA, и мы будем использовать NVML напрямую.
Итак, начнем.
В настройках виртуалки Add hardware –> Channel:
- Name: org.local.gpu-temp
- Device Type: UNIX socket (unix)
- Auto socket: ✅
Запустите виртуалку. На хосте:
sudo virsh dumpxml win11 | grep -B2 -A2 "org.local.gpu-temp"
Где win11 имя вашей виртуалки. Вывод:
| |
Тут нужен path – /run/libvirt/qemu/channel/2-win11/org.local.gpu-temp – запомните путь, может понадобиться в Python скрипте. Теперь виртуалку можно выключить для дальнейших тестов.
Добавляемся в группу sudo usermod -aG qemu $USER (на всякий случай) и перезагружаемся.
Создаем python скрипт:
sudo mkdir -p /usr/local/sbin/gpu-temp-bridge
sudo nano /usr/local/sbin/gpu-temp-bridge/gpu-temp-bridge.py
gpu-temp-bridge.py
Loading file...Не забудьте поменять имя виртуалки, путь сокета (если отличается) и PCI dGPU на свои.
.so-1 –> .so-2, имейте это в виду.Python скрипт берет температуру с хоста, но если датчик недоступен, то берет температуру из сокета гостя. В случае чего если ничего недоступно ставится температура из FALLBACK_TEMP,
Это не так важно – 50 это ни много ни мало, но лучше конечно поставить индивидуальное значение – ваша температура карты в простое. но это может показаться небезопасно. И оно так и есть, но не совсем.
Про небезопасно, небезопасно для GPU только если вы хотите контролить кулера GPU. Но если вы хотите контролить кулера GPU, то пробрасывать температуру на хост не нужно, хост уже имеет полный доступ к dGPU, когда виртуалка не запущена.
Ровно так же, как и гость имеет полный доступ к dGPU, когда виртуалка запущена. То есть контролить кулера GPU следует на той ОС, где карта сейчас используется. Это же все чисто ради того, чтобы контролить любые другие кулера, опираясь на температуру GPU.
Иными словами, и хост, и гость могут контролировать кулера GPU, когда GPU используется ими, но все остальные кулера может контролировать только хост.
Быстрая проверка, просто запустите скрипт
python3 /usr/local/sbin/gpu-temp-bridge/gpu-temp-bridge.py
И в соседнем терминале:
watch -n 1 cat /dev/shm/gpu-temp
Вы должны увидеть температуру. Нагрузите как-нибудь видеокарту, ну например:
sudo zypper in glmark2
Это такой легчайший бенчмарк, далее запустите его через dGPU:
__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia glmark2
Температура меняется? Если да, то круто.
Далее стартуем виртуалку.
В Windows запустите powershell от имени админа:
| |
И согласитесь (Y). Это чтобы можно было запускать скрипты от имени админа.
Далее создаем скрипт “gpu-temp-bridge.ps1”:
gpu-temp-bridge.ps1 powershell
Loading file...Запускаем, и с гостя чем-нибудь нагружаем видеокарту, если в хосте циферки побежали, то все работает, температура проброшена.
gpu-temp-bridge.ps1 лучше положить куда-нибудь, а не просто на “рабочем столе” оставить, так как далее мы сделаем задачу автозапуска.
Выключаем виртуалку и автоматизируем, сделаем демона и автозапуск.
Создаем демона:
sudo nano /etc/systemd/system/gpu-temp-bridge.service
| |
sudo rm -rf /dev/shm/gpu-temp
sudo systemctl daemon-reload
sudo sh -c 'systemctl enable --now gpu-temp-bridge.service && systemctl status gpu-temp-bridge.service'
Посмотреть логи:
sudo journalctl -u gpu-temp-bridge.service -f
Далее создаем хуки, до выдергивания dGPU и после:
sudo nano /etc/libvirt/hooks/qemu.d/win11/prepare/begin/09-dgpu-bridge-stop.sh
09-dgpu-bridge-stop.sh
Loading file...sudo nano /etc/libvirt/hooks/qemu.d/win11/prepare/begin/11-dgpu-bridge-start.sh
11-dgpu-bridge-start.sh
Loading file...И на всякий случай (чтобы наверняка):
sudo nano /etc/libvirt/hooks/qemu.d/win11/release/end/11-dgpu-bridge-restart.sh
91-dgpu-bridge-restart.sh
Loading file...Проверяйте, запускайте виртуалку, далее автоматизируем powershell.
Создайте временный .ps1 скрипт (он создаст задачу):
| |
C:\Scripts\gpu-temp-bridge.ps1 – не забудьте указать свой путь до мейн скрипта.
Запускаем powershell от имени админа и стартует этот скрипт, выключаем все, включаем все, если все работает без ваших рук, поздравляю, вы извращенец.
Итак, CoolerControl. Если нажать на “+” и там “Custom Sensor” в открывшемся окне можно выбрать Sensor Type: File, и просто указать путь до /dev/shm/gpu-temp. И еще надо отключить обычные сенсоры dGPU там же.
Но CoolerControl все равно дох*я принципиальный и все равно будет использовать dGPU, из-за чего трагически погибнет от рук хука. Можно, конечно и его демона в хук засунуть, но это уже будет неэлегантным решением, а костылем, да это другое.
sudo systemctl edit coolercontrold
Там добавить:
| |
Далее:
sudo sh -c 'sudo systemctl daemon-reload && systemctl restart coolercontrold.service'
Также в CoolerControl надо отключить сенсоры dGPU и запускать сам GUI на iGPU (читать ниже – FATAL: Module X is in use).
Далее нужно заставить появиться кулера, если их нет.
sudo sensors-detect
Везде Enter кроме последнего “Lastly, we can probe the I2C/SMBus adapters for connected hardware…”.
И если в конце вы получили:
| |
Всему виной gigabyte. Так как у меня именно gigabyte я покажу, как это исправить. Если у вас не gigabyte – смотрите это.
git clone https://github.com/frankcrawford/it87 && cd it87/
sudo zypper in dkms
sudo ./dkms-install.sh
Дальше либо все ок, либо:
| |
Это из-за Secure Boot:
sudo mokutil --import /var/lib/dkms/mok.pub
Придумайте какой-нибудь простой пароль, и перезагрузитесь. На этапе загрузки будет MOK экран, где нужно enroll key и ввести придуманный пароль. Аналогично у вас было с драйверами NVIDIA и вероятно root паролем, если у вас Secure Boot.
Проверяем, загрузились ли драйвера:
lsmod | grep it87
Если нет, то делаем все описанное ниже
sudo modprobe it87
Если не сработало, то:
sudo modprobe it87 ignore_resource_conflict=1
И добавить модуль в автозагрузку:
echo "it87" | sudo tee /etc/modules-load.d/it87.conf
И это если на предыдущем шаге не сработало без ignore_resource_conflict=1:
echo "options it87 ignore_resource_conflict=1" | sudo tee /etc/modprobe.d/it87.conf
Проверяем:
sensors
Видите это?
| |
Значит все круто.
И обязательно прочтите readme чтобы знать, как обновлять, это важно.
Если кулера не управляются вручную или через CoolerControl и прочие, то нужно зайти в биос и там в Smart Fan, чтобы “сбросить” кривые, а конкретно сделать ОДНУ точку, потому что Smart Fan как бы переопределяет это. То есть сделать типа такого:
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
|---|---|---|---|---|---|---|---|
| PWM(%) | 25 | 25 | 25 | 25 | 25 | 25 | 100 |
| Temp(C) | 0 | 80 | 80 | 80 | 80 | 80 | 80 |
Где 25 минимальная скорость, которую вы хотите (разумно, не надо делать 0) на случай отвала CoolerControl, чтобы не было перегрева. Где 100, просто 100. Где Temp первое всегда 0, остальные макс. возможное, у меня это 80. Например, если я поставлю 90, перезагружусь снова в биос, то оно сбросится на 80.
Проблемы
FATAL: Module X is in use
sudo lsof /dev/nvidia* /dev/dri/by-path/pci-0000:01:00.0*
Тут разумеется ваш dGPU PCI – lspci | grep -E "VGA|3D|Display".
Проверьте, что использует карту, ну например в моем случае частенько такая штука:
| |
code это VSCode, который слегка прих*ел использовать dGPU, нужно просто закрыть/убить процесс и все. Если там что-то системное, то смотреть ниже про KDE Plasma.
Что если вы не хотите, чтобы приложение убивалось, можно сразу запускать его на iGPU. Но в случае VS Code это не сработает, так как там то, что вы запускаете это обертка, запустив ее с нужными параметрами, сам VSCode не запустится на iGPU, а изменив обертку – обновление VS Code, в случае VS Code проще отключить аппаратное ускорение.
Для остальных приложений, для .desktop:
| |
Для терминала просто:
| |
Обратите внимание __EGL_VENDOR_LIBRARY_FILENAMES и VK_ICD_FILENAMES отличаются в зависимости от вендора Intel/AMD/NVIDIA/что-то другое? Китайцы?
Мигает экран и не запускается VM после обновления ОС (KDE Plasma)
Проверьте PCI dGPU:
sudo lsof /dev/nvidia* /dev/dri/by-path/pci-0000:01:00.0*
Тут разумеется ваш dGPU PCI – lspci | grep -E "VGA|3D|Display".
Там наверняка будет куча всего, куча всего, что юзает вашу dGPU, а не должно, и вероятно это что-то, что отвечает за окружение, вероятно это KWin. А использует он не прям вашу карту (cardX), а только рендеринг EGL/OpenGL, хотя фактически саму карту он не использует (не выводит через нее картинку на экран), из-за чего кажется, что все как бы окей.
Как следствие хук убивает KWin чтоб отвязать карту, а заодно и сам себя (KVM). Из-за трагичной смерти, KWin экстренно возрождается, потому-то экран и мигает.
Поздравляю, дообновлялись :D
Это KWin, познакомьтесь. Вероятно он время от времени будет ломаться из-за обновлений, которые меняют его поведение (логику инициализации GPU), и решение (возможно) искать вам, к слову во время написания текста (до первой публикации), я обновил систему, и в первый раз с этим столкнулся, решением было (что уже описано в главе проброса dGPU) __EGL_VENDOR_LIBRARY_FILENAMES.
Welcome to the «VFIO» club buddy, как говори-ца!
Как сделать так, чтобы не ломалось? Просто сделать нельзя, можно мониторить и отслеживать changelog. Или более радикальный способ – не использовать KWin, то есть не использовать KDE Plasma. Ну или не пробрасывать на горячую, только холодный проброс, но если вы зачем-то хотите именно на горячую, то и смысла на холодную нету.
Да я понимаю тут явное противоречие, я говорил вот это будем использовать, а сейчас наоборот. Но для первого раза, с учетом того, что текст рассчитан на аудиторию, что “шарит, но как бы и не очень, но опыт есть”, мое мнение, и правда лучше использовать rich-GUI штуку для наглядности, если так можно выразиться.
Большинство описанных тут вещей и так сработают без KDE Plasma, просто игнорируете все, где фигурирует KWin (возможно еще X11, зависит от вас) и KDE Plasma соответственно, но придется найти альтернативу для вашей DE/WM – “пересадить” все на iGPU, это почти все, что надо, и не исключено, что “там” в этом плане, будет даже проще (так например на Niri – очень просто).
Я же со своей стороны, даже если буду использовать другую DE/WM, постараюсь быть в курсе и применять фиксы. Но добавлять я их буду бесшовно, то есть как будто бы так надо было с самого начала, но лог обновления оставлю.
Зависание при выключение/перезагрузки VM и 100% CPU
Это баг NVIDIA/AMD связанный с FLR. Для NVIDIA фикса нет. А у меня нету AMD, но для AMD возможно поможет это.
Просто делайте “двойной” shutdown через Virtual Manager. Если это не force off, а именно shutdown, то это безопасно. Либо выключайте из Windows + Shutdown из Virtual Manager, либо два раза shutdown из Virtual Manager.
Или типа такая автоматизация:
| |
Разумеется это костыль.
Итоги
Я за*бался. Мне лень качать бенчмарки и прогонять тесты, поэтому вот вам скриншоты из бенчмарков Cyberpunk 2077 и Forza Horizon 6, других игр со встроенным бенчмарком у меня нету, а эти я все равно переносил.


- My notes/tutorial to achieve KVM with passthrough on OpenSUSE and Ryzen/Threadripper system – Level1Techs
- Fedora 33: Ultimiate VFIO Guide for 2020/2021 [WIP] – Level1Techs
- openSUSE - Docker – openSUSE
- libvirt/QEMU Installation – Looking Glass Docs
- Много-много рандомного интернета и ИИ
