顯示卡直通(GPU Passthrough) 讓Windows虛擬機能以接近原生效能玩大型3D遊戲。本文Ivon說明如何在Ubuntu安裝Windows虛擬機,並將獨立顯示卡直通給虛擬機。
為什麼要這麼做?Linux的QEMU/KVM的虛擬機的3D性能十分低落,跑不動3D應用程式,為此將顯示卡直通給虛擬機使用。
顯示卡直通(GPU Passthrough)搭配VFIO核心模組,即可讓虛擬機存取宿主機的硬體資源。Proxmox VE系統有採用此技術,現在我們要在一般的Ubuntu桌面系統搞GPU直通。
要做到這點,電腦需要二張顯示卡(一個CPU內顯,一個獨立顯示卡),再準備二台螢幕。
原理是這樣的:將獨顯直通給虛擬機後,宿主機便無法存取獨顯,故需要內顯用於顯示畫面。
我的電腦主機有內顯和獨顯的HDMI連接埠,通常主螢幕是插在Nvidia獨顯的連接埠
而獨顯在直通給虛擬機後,等同與系統隔離,Linux便無法存取Nvidia顯示卡,主螢幕就要改插Intel內顯的連接埠才有畫面,Nvidia獨顯則插上副螢幕。也就是讓Linux畫面輸出到CPU內顯;Windows畫面由獨立顯示卡輸出。
如果你沒有二個螢幕也沒關係!請使用文末提及的「Looking Glass」存取Windows桌面。讓你能夠在使用Linux的時候,透過Looking Glass的視窗與Windows桌面互動。
1. 環境#
- 主機板:ASUS K31CD-K
- CPU:Intel® Core™ i5-7400
- GPU:Intel® UHD Graphics 630 (內顯)
- GPU:NVIDIA GTX 1050 Ti(獨顯),已安裝閉源驅動
- 主螢幕x1
- 副螢幕x1
- 宿主機Host OS:Ubuntu 24.04 LTS
- 虛擬機Guest OS:Windows 11 23H2
- Linux核心版本:6.5.0
- QEMU版本:8.2.2
- Libvirt版本:8.0.0
- Nvidia閉源驅動版本:550
2. 安裝Windows 11虛擬機#
參見 Linux安裝Windows 11虛擬機 (QEMU/KVM)
安裝後將Windows虛擬機關機。
3. 啟用IOMMU#
使用VFIO前必須先啟用IOMMU。
- 編輯GRUB開機選項
sudo vim /etc/default/grub
- 針對Intel CPU,在
GRUB_CMDLINE_LINUX_DEFAULT
後面加入以下內容,啟用IOMMU
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash intel_iommu=on iommu=pt"
- 更新GRUB後重開機。
sudo update-grub
sudo reboot
4. 將Nvidia GPU綁定給VFIO#
VFIO核心模組負責將PCI-E裝置暴露給虛擬機使用。
- (選擇性)如果直通後再也不需要讓宿主機使用Nvidia顯示卡,可以直接解除安裝Nvidia閉源驅動,改裝回nouveau。
sudo apt purge nvidia-driver-535
sudo apt install xserver-xorg-video-nouveau
- 編輯udev規則:
sudo vim /lib/udev/rules.d/71-nvidia.rules
將所有行數全部加上
#
註解掉,防止Nvidia程式一直嘗試載入驅動導致開機卡在NVRM: GPU ... is already bound to vfio-pci.
的訊息。停用nvidia-persistenced服務,防止程式一直嘗試載入Nvidia驅動
sudo systemctl disable nvidia-persistenced
之後要改用Intel內顯開機,不過Intel的顯示驅動不需要裝,通常已經含在Linux的Mesa套件裡面了。
貼上以下指令,查找獨顯和HDMI裝置的ID
#!/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;
- 找到GTX 1050Ti和顯示卡的HDMI音訊裝置,像這裡是Group 2。將後面的二個硬體ID記起來,例如
10de:1c82
和10de:0fb9
。
IOMMU Group 2:
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)
- 修改Linux的initramfs設定檔:
sudo vim /etc/initramfs-tools/modules
- 設定開機儘早載入VFIO,這也可以防止接著Nvidia顯示卡的副螢幕開機時被意外喚醒。最後面
ids=
將Nvidia顯示卡綁定給VFIO。
vfio vfio_iommu_type1 vfio_virqfd vfio_pci ids=10de:1c82,10de:0fb9
- 設定開機載入VFIO核心模組
sudo vim /etc/modprobe.d/vfio.conf
- 加入以下選項
options vfio-pci ids=10de:1c82,10de:0fb9
5. 隔離Nvidia GPU#
接下來的步驟要防止Linux開機的時候搶走Nvidia顯示卡的控制權。這有很多種作法,比如將Nvidia核心模組加入黑名單(blacklist)禁止載入。或者調整核心模組載入順序,確保VFIO可以搶先Nvidia核心模組載入。
- 設定VFIO先於Nvidia驅動載入
sudo vim /etc/modprobe.d/nvidia.conf
- 填入以下內容:
softdep nouveau pre: vfio-pci
softdep nvidia pre: vfio-pci
softdep nvidia* pre: vfio-pci
- 防止KVM錯誤更正導致Windows虛擬機進入BSOD。
sudo vim /etc/modprobe.d/kvm.conf
- 填入以下內容:
options kvm ignore_msrs=1
- 更新initramfs和GRUB,重開機
sudo update-initramfs -u -k all
sudo update-grub
sudo reboot
重開機一直按著delete,進到UEFI,開啟內顯優先模式。我的是在Advanced → System Agent (SA) Configuration,設定「內顯(IGFX)」優先開機,並開啟「混合螢幕輸出」。
主螢幕改插到內顯的HDMI孔,副螢幕插到獨顯的HDMI孔(如果沒有二個螢幕就讓Nvidia顯示卡的孔空著)
重開機進入Linux系統,理論上此時副螢幕應該不會有任何畫面輸出。
執行
sudo lspci -nnk
指令,應該會看到Nvidia顯示卡Kernel driver in use:
是為vfio-pci
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP107 [GeForce GTX 1050 Ti] [10de:1c82] (rev a1)
Subsystem: ASUSTeK Computer Inc. GP107 [GeForce GTX 1050 Ti] [1043:85d6]
Kernel driver in use: vfio-pci
Kernel modules: nvidiafb, nouveau
01:00.1 Audio device [0403]: NVIDIA Corporation GP107GL High Definition Audio Controller [10de:0fb9] (rev a1)
Subsystem: ASUSTeK Computer Inc. GP107GL High Definition Audio Controller [1043:85d6]
Kernel driver in use: vfio-pci
Kernel modules: snd_hda_intel
6. 將Nvidia GPU加入到虛擬機#
開啟Virt Manager,按二下開啟Windows虛擬機,點左上角i編輯硬體
點選左下角添加硬體 → 新增PCI主機裝置,將獨顯和獨顯音訊HDMI都加進去
虛擬機開機後,主螢幕會看到Windows畫面,副螢幕會暫時黑畫面。現在虛擬機有二個螢幕了,一個是虛擬機的QXL顯示卡,一個是Nvidia顯示卡
在虛擬機安裝 GeForce Experience更新Nvidia顯示卡驅動之後,副螢幕應該就會跳出畫面了。
接著在系統設定 → 顯示器 → 圖形,選取應用程式exe,指定使用Nvidia顯示卡彩現,而非QXL。
程式只要指定使用Nvidia顯示卡渲染,就會吃到GPU加速。儘管如此,程式的視窗在副螢幕上時效能最好。你可以編輯虛擬機硬體,將QXL顯示卡設定為None,讓虛擬機只有一個螢幕。
如果副螢幕有喇叭,則Windows的音效會透過HDMI從副螢幕輸出。
7. 安裝Looking Glass#
Looking Glass是為只有一個螢幕的用戶準備的,讓你可以在同一個畫面同時操作Linux和Windows虛擬機。
注意Looking Glass Host與Client的版本需一致。Ubuntu 24.04已收錄looking-glass-client
套件,不需要手動編譯了。
8. 讓宿主機重新使用直通的GPU#
不重開機情況下,將虛擬機關機與解除vfio-pci綁定,再載入Nvidia核心模組即可重新讓實體機存取顯示卡。但同樣地,虛擬機需要顯示卡的話就得將其手動綁回去。
9. 如何解除GPU直通#
把本文的步驟倒過來做。
具體來說,只要移除綁定vfio-pci相關的參數再更新initramfs就可以了,IOMMU可保留。重開機後再用lspci -nnk
檢查GPU的核心模組有無變回nouveau或nvidia。