GPU Passthrough設定及一些眉角分享 - Linux

Iris avatar
By Iris
at 2021-05-30T14:12

Table of Contents

雖然說自己很早之前就有接觸這塊,KVM目前搞GPU Passthrough還是透過VFIO來做

不過從最後一次玩到現在也已經有幾年的時間,就沒什麼在追了

直到最近NVIDIA在3月底的時候宣布開放GeForce顯卡也可以在KVM上做Passthrough後

就又燃起了一些興趣,在經過一些搜索整理後,貼一個給各位分享

請注意: 1. 文章很長
2. 裡面會有一些截圖以及貼在pastebin的一些指令或參數說明的網址

https://i.imgur.com/Sxcl2MQ.png
https://i.imgur.com/U9Lww9C.png






事前準備:硬體與BIOS

先列一下我的配備
---------------------------------------------------
CPU: AMD Ryzen 5 5600X
MB: ASUS ROG STRIX B550-E
RAM: Patriot Viper Steel DDR4-3200 16GB*2
Host GPU: AMD Radeon VII or AMD Radeon RX 6900XT
Guest GPU: NVIDIA GeForce RTX 3090
SSD1: Seagate 火梭魚 1TB M.2
SSD2: Plextor M9PeGN
HDD: WD 1TB 黑標
---------------------------------------------------
Host OS: Fedora 34 Workstation
Guest OS: Windows 10 21H1
---------------------------------------------------


之所以用Fedora的原因是Fedora在Kernel還有一些KVM套件上都很新
但最主要的原因是Ubuntu 20.04的Mesa版本還沒有辦法支援Big Navi GPU
以及很早之前做的時候也是使用Fedora才會選擇繼續使用

硬體方面,有兩張GPU以上(包含內顯)、且CPU還有BIOS都支援IOMMU的話就可以嘗試
AMD的CPU基本上在IOMMU這部分幾乎是支援的,Intel就要看
而且就算CPU支援,板廠還不一定有BIOS選項可以開
雖然說這部分有所謂的ACS Override這個方法可以做,但那是下下策

以我目前這個平台為例,主要確定IOMMU是啟用的就行了
但需要注意Resizable BAR(就是AMD自稱的SAM技術)請務必關閉
目前這個已經確定會影響到Passthrough的運作

另外,設定與使用VM的過程中可能會需要另外接訊號線或是鍵鼠
因此建議使用有多個輸入切換的螢幕,並且另外準備一組鍵盤或滑鼠











事前準備:Fedora 34設定

裝完系統後,首先必須先開啟IOMMU功能。請編輯/etc/default/grub檔案
在GRUB_CMDLINE_LINUX內加入:
amd_iommu=on
iommu=pt
(P.S 如果是Intel就改成intel_iommu即可)

(P.S.S 這兩個選項在Kernel 5.8之後的AMD平台上不用加也會默認啟用IOMMU,至少在
Ubuntu 20.04還有Fedora 34上面是如此,不過我們也有對IOMMU運作模式做設定
因此建議還是加一下)

--

另外Windows 10會有因KVM的msrs糾錯導致BSOD的問題,因此也將忽略msrs的選項也加入
kvm.ignore_msrs=1
kvm.report_ignored_msrs=0

加入之後會變下圖這樣:
https://i.imgur.com/8iDiBAb.png

完畢之後產生新的GRUB啟動設定檔,在EFI模式下的Fedora 34是使用以下指令:
# grub2-mkconfig -o /boot/grub2/grub.cfg
(* 33以前的請改路徑成/boot/efi/EFI/fedora/grub.cfg)

--

重開機後,使用以下的bash script檢查要掛載的GPU是否在獨立的IOMMU群組中
https://i.imgur.com/4NrmGM5.png

執行script會出現像下圖圖片的樣子
https://i.imgur.com/YqloBRA.png
以這張圖為例,要掛的RTX3090在IOMMU群組ID是17,所謂獨立的意思是
在17這個群組內除了RTX3090還有它的HDMI輸出裝置外,沒有其他的PCI-E裝置存在

如果有存在其他的裝置,只有兩個方法可以處理:
1. 將其他裝置連同GPU一起被VFIO掌控,但這些裝置在Linux系統內將不會運作
2. 使用ACS Override Patch

--

確定GPU處在獨立的IOMMU群組後就可以進行下一步,把VFIO模組給帶起來
首先到/etc/dracut.conf.d/內,建立一個新的conf檔案
然後在檔案內寫入以下資訊

add_drivers+=" vfio vfio_pci vfio_iommu_type1 vfio_virqfd "
(注意包含空格)

儲存後使用dracut -fv產生新的initramfs檔案

--

接著再編輯/etc/default/grub檔案,在同一個位置的後面再新增幾個參數:

rd.driver.pre=vfio-pci
vfio-pci.ids=<GPU的裝置ID>,<GPU HDMI的裝置ID>
video=efifb:off (選擇性)

兩個的裝置ID都可以透過上面的IOMMU群組查詢指令或者是使用lspci -n去找到
以RTX3090為例,其GPU本身還有HDMI的裝置ID寫進grub內會是:

vfio-pci.ids=10de:2204,10de:1aef

(P.S vfio-pci.ids這個在比較早的作法是可以直接加入進/etc/modprobe.d內就行了
但VFIO在Kernel 5.8後開始就已被整合進核心套件中而不再是單純的Module
因此使用modprobe.d的方式在部分Linux Distro上會無效)

另外video=efifb:off這個參數
這個是如果要掛的卡是插在主機板的第一條PCI-E上,才必須要加的參數

加完之後會像下圖這樣:
https://i.imgur.com/YZjY0lw.png

重開機後:使用lspci -k指令檢查GPU是否已被vfio-pci使用,成功的話如下圖:
https://i.imgur.com/P3nylrL.png

這樣前置作業就算完成。











設定網路、安裝套件並建立VM

首先先建立給VM用的bridge,我是直接使用NetworkManager的指令去建立的
可以Google一下怎麼建立

之後安裝VM管理套件
$ sudo dnf install @virtualization

另外還需要安裝OVMF,這個是讓VM可以使用UEFI環境的韌體套件
由於目前新的顯卡大多都已經是UEFI韌體,因此VM也必須建立在UEFI模式下
$ sudo dnf install edk2-ovmf

由於Fedora的virt-manager沒辦法透過登出再登入的方式直接取得權限,因此需要重開機

--

準備好Windows 10的ISO以及VirtIO driver的ISO,照一般建立VM的程序下去安裝

在建立VM的時候留意以下幾點就好(也可以裝好Win10之後再做):
1. 安裝的時候機器類型選擇Q35,並且將韌體改為UEFI類型的韌體 (不帶secboot的)
2. CPU model請改為host-passthrough,並且設定好CPU拓樸(尤其是Socket的部分)
3. 網路model請改成virtio,效能比較好
4. 虛擬磁碟的部分請先使用SATA就好,原因後面會說
5. 別忘了也要把VirtIO driver的ISO另外建立一個虛擬光碟機掛載起來

--

安裝完Win10並手動上好網路驅動後,先下載好NVIDIA的驅動在系統內,然後關機

關機後把要給VM用的顯卡及其HDMI音源給掛進去
https://i.imgur.com/YGMJprZ.png

--

接下來有兩種方式可以選擇
1. 直接開機,並且用virt-manager的視窗裝驅動
2. 把虛擬顯卡還有Spice顯示器給拿掉,並把鍵盤滑鼠的USB給掛進去
然後掛載的卡接上螢幕 (USB掛載方式如圖)
https://i.imgur.com/VnQLcgM.png

我個人會比較推第二種,原因是就過去經驗,N卡驅動對於QXL這類的虛擬顯卡不太友善
為了不要在安裝或者日後使用過程產生side-effect,所以我會習慣接螢幕來裝

--

裝驅動的過程與結束就是見真章的時候了
NV在3月底公布自R465版本的驅動開始支援KVM的GPU Passthrough
因此從這版本之後就不需再加一些額外的VM參數來繞過驅動的檢查機制
基本上不會再有裝完驅動出現Code 43的問題存在,有的話較大的可能是硬體或KVM問題

但如果是掛A卡的話就需要留意了,A卡部分型號會有Code 43或者是沒辦法reset的問題
目前所知道的是舊的Polaris系列多多少少都有這問題存在,其他的還沒有測試過














後續的一些調校

主要是針對VM設定還有CPU做一些優化上的調整,包括了模擬Hyper-V、CPU核心綁定
以及虛擬平台上的一些設定參考

這段牽涉到一些XML檔案上的修改,不過新的virt-manager有支援直接編輯的功能了
因此不再需要透過virsh edit去做修改

--

首先在features的部分,目前國外不少都是使用以下的參數設定,照抄即可
https://i.imgur.com/KiPWzKv.png

--

接著如果你希望一些CPU核心能夠被VM完全獨佔的話,可以設定一下CPU綁定
https://i.imgur.com/F03inIY.png

這邊需要注意的是每一個實體核心的編號還有核心架構
通常在有開HT的情況下,每一個線程的編號是根據每一個核心的第一個線程下去排

比如在雙核四線上來說,它的編號會是:
Core #0 thread #0 -> thread #0
Core #1 thread #0 -> thread #1
Core #0 thread #1 -> thread #2
Core #1 thread #1 -> thread #3

也就是說,假設我要讓其中一核的線程都給VM使用,那我對應的設定會是:
vCore #0 <- thread #1
vCore #1 <- thread #3

這樣才是正確的,如果直接照實體核心線程的編號下去排,就會變成跨核心在跑
這會導致VM的效能不好

同時,在分配核心上也需要考慮到跨CCX甚至跨CCD的問題 (Ryzen上面容易遇到)
可以在linux上安裝一款名為lstopo的工具來看實體CPU Topology狀況

最後還需要到CPU的區塊,將其中一個參數加入,以套用CPU綁定的設定
https://i.imgur.com/DRLz74U.png

--

clock的部分也要做修改,除了增加效能外
同時也能夠防止Windows VM的時間在開機時與Host不同步的問題
https://i.imgur.com/AJcyGmE.png





















額外套件或設定

目前GPU Passthrough若要拿來打遊戲的話,都會準備另一台螢幕或鍵鼠
或者是用多輸入的螢幕然後切換訊號源,或者直接掛Host端的鍵鼠
不過如果不想這麼麻煩的話,現在也有一個開源軟體叫looking-glass

https://looking-glass.io/

簡單來說,這套軟體是使用IVSHMEM配合Windows的DXGI去做影像擷取、複製
並且把複製出來的影像資料再透過Host端的client給渲染出來
另外輸入的部分則是使用Spice當作輸入來源
算是可以做到不用另外搬螢幕也不用另外掛鍵鼠進去的一個方案


安裝方式官網上面的wiki專區也有寫,我個人覺得算是寫得很完整
不過要使用這套軟體的話需要注意幾件事:

1. 只有影像,聲音的部分要另外搞

2. 此軟體建議使用EGL而非OpenGL,如果是用AMD顯卡當作Host GPU的話
需要注意amdgpu-pro的Mesa驅動不支援EGL,建議使用Kernel自帶的amdgpu驅動

3. 由於牽涉到影像傳輸,因此使用這套軟體玩遊戲會有部分效能損失
效能損失程度與解析度、畫面變化、還有螢幕更新率有關

4. 用這套就我自己測試,還是要讓Guest GPU接線,只不過可以用dummy代替

--

聲音的部分則可以用Scream代替,並且用網路傳輸的方式將聲音從Guest傳至Host

https://github.com/duncanthrax/scream

具體的安裝與用法可以直接參照github上的說明

或者是透過QEMU用一套Audio Passthrough也是可以

不過Fedora從33後改用pipewire作為音源管理介面後

我還在找有沒有透過pipewire來實作的方式

--

另外,如果希望能夠在VM內使用完整的USB功能

建議將Host端的其中一組USB控制器也掛進去VM內使用

因為KVM自帶的libusb passthrough並不是所有接USB的裝置都可以使用(比如iPhone)

而400跟500系列的USB 3.1 G2是另外獨立出來的控制器

可以考慮將USB 3.1掛進去VM內使用














目前遇到的問題

1. 前面提到的虛擬磁碟為何要選用SATA的原因

這個問題說真的我不太確定是QEMU、Guest端的driver、還是Kernel的問題
簡單來說,我目前只要用virtio-blk或者是virtio-scsi
進系統後用一段時間就會BSOD,Error訊息是VIDEO_DXGIKRNL_FATAL_ERROR
做了很多測試,包括換Kernel、換NV driver等等都無解

但用SATA就一點事情都沒有,後來也發現用SATA的磁碟效能也跟一般差不多
問了不少群組上的老外他們也是一點頭緒都沒有
所以就先用SATA了

--

2. 開一些類似監控的軟體偶而會觸發自動重開

像是GPU-Z有時開了會直接讓VM重開機,八成是在偵測PCI-E的時候出問題
另外GPU-Z就算開起來了,在PCI-E資訊那邊也不是顯示正確的資訊
我在猜是否有可能是AMD在KVM上面還是有一點問題在








大約是這樣,目前在這方面還是有不少東西需要去探討與釐清,畢竟這水還滿深的

另外我接觸到國外有在使用的,不少是使用Archlinux,也有使用像Manjaro或是Pop!_OS

也有跟我一樣是使用Fedora的,Ubuntu反而還比較少一點

如果各位硬體條件符合的話多少可以嘗試看看

--
https://i.imgur.com/paUBacY.png
https://i.imgur.com/vsJ0Suy.png

--
Tags: Linux

All Comments

Quintina avatar
By Quintina
at 2021-06-02T13:26
感謝分享,最近也有打算搞一個kvm windows配gpu passth
rough,只是因為是開在無螢幕的伺服器上,不知道到時候
會不會遇到一堆坑XD
Edith avatar
By Edith
at 2021-06-05T12:41
Andy avatar
By Andy
at 2021-06-08T11:56
一樓搞無螢幕的可能需要加一些參數把efifb關掉搶回GPU
Delia avatar
By Delia
at 2021-06-11T11:10
我之前用PVE這樣搞還沒加的時候一pass就會開始閃雪花 然後
直接kernel panic整個連hypervisor一起死掉
Xanthe avatar
By Xanthe
at 2021-06-14T10:25

我之前也在Proxmox VE上面弄好了
GPU Passthrough給Windows 10
Genevieve avatar
By Genevieve
at 2021-06-17T09:40
跑了3DMark感覺還ok
Annie avatar
By Annie
at 2021-06-20T08:54
Emma avatar
By Emma
at 2021-06-23T08:09
Noah avatar
By Noah
at 2021-06-26T07:24
虛擬機的windows可以用原本的隨機版序號啟用嗎?

求救ubuntu無出現在開機選單中

Kama avatar
By Kama
at 2021-05-28T09:08
版上先進好! 昨天在切換雙系統的時候不小心把F10按成F9(Setup Defaults), 導致我要進bios選擇開機碟原本的ubuntu不見了, 請問要如何把它修正回來呢? 還是資料就被洗掉要重灌了? 會接觸linux單純是軟體只支援linux, 如果問到傻問題再麻煩各位包容。 謝謝! ps 電腦 ...

請問如何開warning與如何build出ko檔

Zenobia avatar
By Zenobia
at 2021-05-27T23:50
請較一下 我有個codebase (1) 其中某個makefile: path: kerner/driver/sensor/的某個驅動 makefile只寫 obj-$(CONFIG_XXX) += sensor.o 因為我build完都沒有warning,可是應該會很多warning才對 請問我要怎麼把 ...

pchome騙很大

Ula avatar
By Ula
at 2021-05-26T13:02
上週從 pchome網站訂購一台預裝 freedos的 HP筆電, 到貨立馬安裝 manjaro. 但安裝完後, 才發現硬碟和螢幕規格都與訂單不符. 在這裡抱怨一下, 希望不要再有人被騙. 原訂單規格: SSD硬碟 + FHD(1920x1080)螢幕 https://drive.google.com/fi ...

給想玩Dvorak鍵盤又一時半刻轉不過來的同學們

Ivy avatar
By Ivy
at 2021-05-25T13:37
時隔12年,不知道原作是否還在 Linux 版上。 本文不適用:Wayland, qwerty 目前已知的問題:不管使用哪種 IME,他們都會偷偷把鍵位調回 qwerty 來源:setxkbmap -print -verbose 10 我目前測試過的有 ibus, fcitx, fcitx5,scim 因為 ...

ubuntu >導向不能用在subprocess

Rae avatar
By Rae
at 2021-05-24T19:03
各位前輩您好,由於不知道要放在linux還是python版,若有錯版我會馬上刪文 當我在terminal執行sudo ./sync_to_gps8 andgt;123.txt時,都能夠順利執行,但因為我需要 用python去統整,所以我使用了python的subprocess 模組,但是當我一樣執行sudo ...