快轉到主要內容

Arch Linux如何將Nvidia GPU直通給Windows QEMU/KVM虛擬機

Linux系統 虛擬機與容器技術 GPU Passthrough Arch Linux QEMU
🗓️ 民國112年 癸卯年
✍ 切換正體/簡體字
目錄

1. 目標
#

Linux上用QEMU/KVM安裝的Windows虛擬機最缺乏的是3D圖形效能,為此利用Linux提供的VFIO(Virtual Function I/O)核心模組將實體機(Host)的獨立顯示卡綁定,直通(passthrough)給虛擬機(Guest)使用。

這樣虛擬機便能使用3D硬體加速,用於建模彩現、跑AI運算,或是用Looking Glass玩遊戲。

尚能同時使用二個系統作業。

當然獨顯直通給虛擬機時,實體機自然就無法利用獨顯運算,需將虛擬機關機實體機才可重新使用顯示卡。文中會介紹如何在虛擬機關機後,把顯示卡還給實體機存取。

2. 環境
#

  • Host OS: Arch Linux
  • 核心版本:6.6.10
  • 桌面環境:KDE Plasma X11
  • Libvirt版本:9.0.5
  • QEMU版本:8.0.4
  • Guest OS: Windows 11 22H2
  • 主機板:ASUS K31CDK,UEFI開機,關閉Secure boot
  • CPU: Intel i5-7400
  • GPU: Intel UHD 630 (內顯)
  • GPU: Nvidia GTX-1050Ti (要直通的獨顯)
  • RAM:16GB

本文屬雙GPU直通,電腦需同時有內顯+獨顯,準備二個螢幕(或者第二個螢幕用HDMI欺騙器取代,再配合Looking Glass存取)。

GPU直通前接線是這樣,內顯處於閒置狀態。

但在啟用GPU直通(啟用VFIO、改用內顯開機)後,內顯HDMI接主螢幕,獨顯HDMI接副螢幕。

3. 安裝Windows 11虛擬機
#

首先安裝 Virt Manager和QMEU/KVM

安裝Windows 11虛擬機

Windows 11虛擬機必須使用UEFI(OVMF)開機,至少需要分配4核心CPU、8GB RAM、64GB硬碟。不可安裝SPICE Tools。

安裝好後將虛擬機關機。

4. 啟用IOMMU
#

啟用IOMMU將裝置分組。

  1. 編輯GRUB設定檔
sudo vim /etc/default/grub
  1. GRUB_CMDLINE_LINUX_DEFAULT這行後面加入核心參數,啟用Intel CPU的iommu。
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt video=efifb:off"
  1. 重新產生設定檔,重開機
sudo grub-mkconfig -o /boot/grub/grub.cfg
sudo reboot
  1. 終端機貼上指令稿查找顯示卡的IOMMU群組:
#!/bin/bash
shopt -s nullglob
for g in /sys/kernel/iommu_groups/*; do
    echo "IOMMU Group ${g##*/}:"
    for d in $g/devices/*; do
        echo -e "\t$(lspci -nns ${d##*/})"
    done;
done;
  1. 應會看到顯示卡的分組,例如我的GTX1050 Ti被分到Group 1:
IOMMU Group 1:
        01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP107 [GeForce GTX 1050 Ti] [10de:1c82] (rev a1)
        01:00.1 Audio device [0403]: NVIDIA Corporation GP107GL High Definition Audio Controller [10de:0fb9] (rev a1)
  1. 將顯示卡的硬體ID記下來,例如這裡是10de:1c8210de:0fb9

5. 將顯示卡綁定vfio-pci
#

設定開機就將顯示卡綁給vfio-pci,並禁止載入Nvidia核心模組。

儘管Githu開發者bryansteiner曾經分享用libvirt hook達成「開機後將Nvidia顯示卡直通給虛擬機,關機後Nvidia顯示卡還給實體機」的自動化操作,但是在Arch似乎會造成libvirt卡死,所以我選擇在實體機需要時Nvidia時再手動將Nvidia核心模組載入回來。

  1. 編輯mkinitcpio.conf
sudo vim /etc/mkinitcpio.conf
  1. 設定開機載入vfio核心模組
MODULES=(vfio_pci vfio vfio_iommu_type1)
  1. 再度編輯GRUB:sudo vim /etc/default/grubvideo=efifb:off防止系統走顯示卡,vfio-pci加入VFIO顯示卡的硬體ID,以逗號分隔。最後面kvm.ignore_msrs=1是為了防止KVM錯誤更正導致Windows進入BSOD。
GRUB_CMDLINE_LINUX_DEFAULT="intel_iommu=on iommu=pt video=efifb:off vfio-pci.ids=10de:1c82,10de:0fb9 kvm.ignore_msrs=1 kvm.report_ignored_msrs=0"
  1. 新增開機禁止載入的核心模組列表
sudo vim /etc/modprobe.d/blacklist.conf
  1. 填入以下內容,禁止開機載入Nvidia顯示卡的核心模組(也請檢查modprobe.d下有無其他檔案包含載入nvidia的選項)
blacklist nvidia
blacklist nouveau
  1. 刪除Xorg的設定檔
sudo rm /etc/X11/xorg.conf
  1. 更新initramfs和GRUB
sudo mkinitcpio -p linux
sudo grub-mkconfig -o /boot/grub/grub.cfg

6. 用內顯優先開機
#

  1. 重開機,按Delete進入BIOS

  2. 設定優先以CPU內顯開機。ASUS K31CDK主機板的選項在Advanced → System Agent (SA)Configuration → IGFX

  3. 重開機後,用sudo lspci -nnk | grep NVIDIA檢查VFIO狀態:

01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP107 [GeForce GTX 1050 Ti] [10de:1c82] (rev a1)
01:00.1 Audio device [0403]: NVIDIA Corporation GP107GL High Definition Audio Controller [10de:0fb9] (rev a1)
  1. 執行nvidia-smi指令,顯示NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver,確認無法連線到Nvidia顯示卡。

  2. 再執行lspci -k | grep -A 2 -i "VGA"指令,應該會顯示Kernel driver in use: vfio-pci,這樣就是成功了。

如果以上步驟都無效,你還是可以繼續嘗試把Nvidia顯示卡分配給虛擬機。

7. 將Nvidia顯示卡分配給虛擬機
#

  1. 開啟Virt Manager,編輯Windows 11虛擬機的硬體。點選左下角新增硬體,選擇PCI主機裝置,加入Nvidia獨顯和音效裝置至虛擬機

  2. 建議新增USB主機裝置 → 滑鼠,這樣就沒虛擬機吃不到實體機滑鼠的問題。滑鼠在虛擬機出不來的時候,按Ctrl+ALT讓滑鼠回到實體機。

  3. 虛擬機開機後會變成雙螢幕。實體機主螢幕虛擬機視窗會看到Windows畫面,而副螢幕會暫時黑螢幕。

  4. 在虛擬機內下載 Geforce Experience,登入Nvidia帳號,安裝驅動程式。

  5. 之後Windows應該就會正常顯示雙螢幕。

  6. 接著在系統設定 → 顯示器 → 圖形,指定應用程式使用Nvidia顯示卡彩現,而非QXL。

如果副螢幕有喇叭,則Windows的音效會透過HDMI從副螢幕輸出。

8. 來玩遊戲吧
#

理論上遊戲效能在副螢幕(連接到Nvidia顯示卡)最好。像我這種不想接第二個螢幕的,就會將副螢幕換成「HDMI顯卡欺騙器」,約一個轉接頭大小而已,並在Windows顯示設定將螢幕只顯示於虛擬機視窗,就可以用單一螢幕同時操控Linux和Windows。

在虛擬機內部安裝 Looking Glass,這樣便可在實體機主螢幕以客戶端低延遲存取Windows桌面,也就不用接二個實體螢幕了。

使用HDMI顯卡欺騙器前務必先裝好Nvidia驅動,以及設定Looking Glass開機自動啟動。

9. 如何讓Linux實體機重新使用Nvidia獨顯
#

不重開機情況下,將虛擬機關機與解除vfio-pci綁定,再載入Nvidia核心模組即可重新讓實體機存取顯示卡。但同樣地,虛擬機需要顯示卡的話就得將其手動綁回去。

本節內容參考自bryansteiner的作法。前面提過本節的內容可以用libvirt hook自動化執行,可是Arch Linux會卡死,所以只好手動執行。

以下內容可自行寫成獨立的script。

  1. 虛擬機關機。測試nvidia-smi指令,應該會顯示NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver

  2. 利用virt指令,解除綁定vfio-pci裝置(pci_0000_01_00_0來自lscpi結果)

sudo virsh nodedev-reattach pci_0000_01_00_0
sudo virsh nodedev-reattach pci_0000_01_00_1
  1. 移除vfio核心模組
sudo modprobe -r vfio_pci
sudo modprobe -r vfio_iommu_type1
sudo modprobe -r vfio
  1. 嘗試載入Nvidia核心模組
sudo modprobe nvidia_modeset
sudo modprobe nvidia_uvm
sudo modprobe nvidia
  1. 執行nvidia-smi指令看能不能檢測到顯示卡資訊。

此時可能要重新啟動桌面環境,應用程式才會抓得到Nvidia顯示卡,不然就得用Nvidia prime-run指令來指定應用程式用Nvidia顯示卡運算(參見 Nvidia PRIME用法)


如果您要把vfio綁回去給虛擬機使用:

sudo modprobe -r nvidia_modeset
sudo modprobe -r nvidia_uvm
sudo modprobe -r nvidia
sudo modprobe vfio_pci
sudo modprobe vfio_iommu_type1
sudo modprobe vfio
sudo virsh nodedev-detach pci_0000_01_00_0
sudo virsh nodedev-detach pci_0000_01_00_1

參考資料
#

相關文章

Linux系統Intel內顯直通給QEMU/KVM虛擬機的方法,不採用GVT-g
Linux系統 虛擬機與容器技術 GPU Passthrough Arch Linux QEMU
如何在Windows虛擬機玩遊戲 ~ Linux QEMU/KVM雙GPU直通 + Looking Glass安裝過程
Linux系統 虛擬機與容器技術 GPU Passthrough QEMU Linux Windows
在Arch Linux上安裝QEMU/KVM和Virt Manager虛擬機軟體
Linux系統 虛擬機與容器技術 Arch Linux QEMU Libvirt

留言板

此處提供二種留言板。點選按鈕,選擇您覺得方便的留言板。要討論程式碼請用Giscus,匿名討論請用Disqus。

這是Giscus留言板,需要Github帳號才能留言。支援markdown語法,若要上傳圖片請貼Imgur連結。您的留言會在Github Discussions向所有人公開。

這是Disqus留言板,您可能會看到Disqus強制投放的廣告。有時留言可能會被系統判定需審核,導致延遲顯示,請見諒。