在 Proxmox 上進行 PCI-E 直通
前言
簡單來說, PCI Passthrough 就是將物理機(Host)上的 PCI(E) device 從 Host 上隔離並直通給客戶機(Client)的技術,對於 Client 來說,就會認為他真的插著一個 PCI device。
直通也不一定是直通 PCI device,也有可能是直通透過 SR-IOV 或是其他技術虛擬化出來的資源,不過這就需要硬體及 Driver 的支持,相對來說會更複雜。
因為每個 Host 的配置都不同,每個 Host 的 PCI 直通設定都不完全相同,有時候甚至 PCIE device 插在哪個 PCIE 插槽可能都會有影響,可能別人能用的解決方法你試就沒用,堪稱玄學。而直通顯卡到 Windows Client 更是 PCI 直通中最麻煩的設定,大概率會碰到更多的問題,不同 Host 的解決方法還不一定一樣,我對此的評價只有:玄學中的玄學。
設置
設定這部分我會大致分成四個區塊,第一部分是 PCI Passthrough 一定要做的設定,第二、三部分是我遇到的兩個問題及對我有用的解法,第四部分則是我整理的其他問題可能適用的方法
基礎設定
這部份的設定是 PCI Passthrough 都要進行的設定,如果運氣很好,硬體的組合剛好,那可能只需要這部份的設定就成功直通了。
- 加入 kernel parameter 來開啟 IOMMU
使用 Intel CPU 的話要加的參數是intel_iommu=on
(雖然 PVE 的核心編譯的時候有打開CONFIG_INTEL_IOMMU_DEFAULT_ON
,但仍然需要設定)
AMD CPU 則不需要加參數,只要檢測到支持就會開啟 IOMMU
不管使用什麼 CPU 都建議加上iommu=pt
,如果硬體支援則可以提高性能
視自己使用的 bootloader 來進行更改
如果是在 PVE7 後使用 UEFI 安裝,則 bootloader 會使用 systemd-boot,反之,使用 BIOS 安裝則是使用 Grub,但如果是原本使用 Grub 開機並升級上來的則會繼續使用 Grub
- systemd-boot
編輯/etc/kernel/cmdline
,前面會有一些其他參數,要加的參數直接放在後面,如下
1 |
|
編輯完後使用pve-efiboot-tool refresh
來更新 bootloader
- Grub
編輯/etc/default/grub
找到GRUB_CMDLINE_LINUX
或是GRUB_CMDLINE_LINUX_DEFAULT
,可以將參數加在雙引號之間,只要選擇其中一個加即可
1 |
|
編輯完後使用update-grub
來更新 bootloader
修改完後重新開機,可以使用以下指令來確認是否成功開啟 IOMMU(可以等到後面設定完再一起重新開機)
1 |
|
應該要出現包含一行DMAR: IOMMU enabled
的內容
1 |
|
視不同 CPU 的廠商,會有不同內容,有出現其中一行就 OK
AMD-Vi: Interrupt remapping enabled
DMAR-IR: Enabled IRQ remapping in x2apic mode
- 開機載入
vfio
module
編輯/etc/modules
,加入以下內容
1 |
|
也許在其他教程還會多一個vfio_virqfd
,不過在 kernel6.2 後這個模組不再需要加了,已經包含在vfio
內了
編輯完後使用update-initramfs -u -k all
來更新 initramfs
- 設定顯卡隔離
使用指令來確認要直通的 PCI device 是不是單獨在一個 iommu group 裡。
有些主板的南橋分配會不同,導致插在南橋引出的 PCIE 上會和其他設備分在同一組,解決方式就是換個插槽,或是插到直連 CPU 的 PCIE 上
1 |
|
輸出大概這樣
1 |
|
一般來說一張顯卡會有至少兩個設備,顯示和聲卡兩部分,如果是有 typec 的卡還會有更多的設備
將要直通的設備的 vendor id 和 device id 記起來,我要直通 GK107(GTX650),因此就是10de:0fc6
和10de:0e1b
編輯/etc/modprobe.d/vfio.conf
來設定 vfio 參數, ids 後面加的就是要直通的設備 id,後面 softdep 是讓核心在載入這些模組前優先載入 vfio,避免被 driver 的模組搶先,這邊只有 NVIDIA 的 driver module,如果使用 intel 或是 amd 的顯卡需要改為對應的模組
1 |
|
如果不想用 softdep,也可以直接把 driver 的 module 給 blacklist,編輯/etc/modprobe.d/blacklist.conf
,這邊也只有 blacklist NVIDIA 的 driver module,如果使用 intel 或是 amd 的顯卡需要改為對應的模組
1 |
|
做完這些設定後重新開機,並執行dmesg | grep vfio
如果有看到輸出,那應該就是正確啟動了
如果順利的話,只需要做完這些設定、安裝一個虛擬機,並加入 PCI device 就大功告成了
建議把 PCI-Express 勾起來,如果是直通顯卡則 Primary GPU 也建議勾起來
此時把虛擬機打開應該可以在直通的顯卡連接的螢幕上看到畫面,並且 console 不再有顯示,等到啟動到系統並安裝驅動,如果都沒問題,那就算是成功了
如果沒有成功,可以嘗試我底下提供的其他解法
問題1:顯卡無顯示
問題的具體症狀大概包括這幾個,直通的顯卡沒有輸出任何內容,在 Windows Client 上可以看到 GTX650 的裝置,也可以打上驅動,但是會有 code 43 的 error
由於我使用的 NVIDIA driver 版本>465,所以不是因為驅動發現是虛擬機才顯示 code43(在465的版本前,如果驅動發現是虛擬機會報 code 43 error,需要給 vBIOS 打 patch,並隱藏虛擬機特徵才能通過)
在這個問題上我多設定了幾個地方,但是具體是哪些設定有起效果,我也不知道,反正這個問題解決了
因為在確認 remapping 的時候看到dmesg | grep 'remapping'
的輸出還有一行x2apic: IRQ remapping doesn't support X2APIC mode
,因此 kernel parameter 加上了intremap=no_x2apic_optout
- 給 kernel parameter 加上
video=efifb:off
和intremap=no_x2apic_optout
[1],改完需重啟 - 在
options vfio-pci ids=10de:0fc6,10de:0e1b
後加上disable_vga=1
- 更換 vBIOS(顯卡的 BIOS)
由於顯卡直通會需要顯卡有支援 UEFI 的 vBIOS,可以使用這些指令來把目前顯卡的 vBIOS dump 出來
1 |
|
然後使用 rom-parser 來驗證
1 |
|
輸出應該要像這樣,需要有顯示 type 3 (EFI)
1 |
|
如果只有 type 0,就需要去找對應的有 UEFI 支援的 vBIOS,可以嘗試在 Tech Powerup 上搜尋,只是我在上面找到的 vBIOS 也是沒有 EFI 支援的 vBIOS,後來是在微星的論壇上找到有人提供有 EFI 支援的 vBIOS
我找到對應的 vBIOS 後使用nvflash
刷入顯卡上,可以從 Tech Powerup 上下載nvflash
接著在虛擬機的設定中指定 vBIOS 為 rom file
將剛剛的 vBIOS 移到/usr/share/kvm/
底下
1 |
|
編輯/etc/pve/qemu-server/105.conf
,數字是要直通的虛擬機的 vmid,在hostpci0
後面加上romfile
,如果不設定 romfile,則開機的時候不會顯示,直到進入系統
1 |
|
經過這些設定並重新開機後,問題1解決了,症狀變為問題2
問題2:無法安裝驅動
具體的症狀大概是只要 Windows Client 不裝驅動,那麼就可以正常開機,但是使用連在顯卡上的螢幕裝驅動會裝到一半直接黑屏死機,如果是使用 RDP 遠程連入裝驅動,雖然可以成功安裝,但是開機到進入系統前就會直接死機重開(只能開機到轉圈的地方,猜測是載入驅動的時候內核的問題)
經過一些 googling 後在 UNRAID 的論壇[2]和 Proxmox 的論壇[3]上找到了和我相同問題的提問,給出的解法加上一些 kernel parameter 後在 Windows Client 中使用安全模式安裝驅動,並將顯卡的 MSI(Message Signaled Interrupts)打開,我嘗試後成功解決問題,直通成功。
- kernel parameter 加上
video=efifb:off video=vesafb:off video=simplefb:off
,之前已經加過了video=efifb:off
,所以實際只加video=vesafb:off video=simplefb:off
,更改完需重啟 - 將顯卡的 vBIOS 打上 patch,我不確定這一步有沒有影響,這一步一般來說是用來規避 NVIDIA 舊版本驅動對虛擬機的限制
使用 HEX Editor 打開剛剛 dump 出來或是下載的 vBIOS 文件,找到 55AA 這兩個值,並且他後面應該會有 VIDEO 的文字,將 55AA 前面的內容全部刪掉
- 開啟虛擬機,並進入安全模式
按下 Meta+R,輸入msconfig
,並在開機的選項中把安全啟動勾起來,這樣之後開機都會進入安全模式,直到把安全啟動取消
- 如果之前有嘗試安裝 NVIDIA 驅動則下載 DDU,來徹底刪除驅動並重啟虛擬機
- 在安全模式中安裝 NVIDIA 驅動
- 將顯卡開啟 MSI
可以參考這篇文章[4]來確認目前設備的中斷形式是哪一種,以及如何手動開啟 MSI
要開啟 MSI 可以先嘗試使用 MSI_util,如果有在列表中看到顯卡,就只需要把後面的勾勾起來就好
不過我的顯卡沒有出現在設備列表中,所以我使用更改註冊表來開啟 MSI
首先開啟regedit
,並進入\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\PCI\
在這個項目底下找到對應顯卡對應的子機碼,前面有提到顯卡的 id 是10de:0fc6
,因此進入VEN_10DE&DEV_0FC6&SUBSYS_8A961462&REV_A1\
,他底下應該只有一個子機碼,在裡面找到Device Parameters\Interrupt Management\
,如果底下沒有MessageSignaledInterruptProperties
的子機碼,就直接建立即可,並在這個機碼中建立一個 DWORD,名稱為 MSISupported,值設定為1即開啟 MSI
註:更改註冊表有風險,最好先進行備份
我在完成開啟 MSI,並重開虛擬機後就成功直通顯卡了,且沒有任何錯誤
其他疑難雜症
這邊大概會簡略介紹我看到的其他問題之解法,但不一定適用,建議參考文章[5][6][7]和搜尋進行評估
- code 43
在 NVIDIA 驅動465版本之前,它會檢查機器是不是虛擬機,如果是,即使直通成功,驅動也會報錯誤代碼43
對應的解決方法就是隱藏虛擬機和修補 vBIOS,修補 vBIOS 的方式前面已經提過了,這裡就不重提了
隱藏虛擬機可以透過在虛擬機的設定檔加上參數[8]
1 |
|
或是可以在網路上搜尋其他隱藏的方法並去嘗試,不過現在應該不需要這部份了,前幾年 NVIDIA 放開對於虛擬機的限制,現在不會因為虛擬機而報錯 code43
- 開啟專用 IOMMU group
如果 IOMMU 並沒有給要直通的設備單獨分組可以嘗試給 kernel parameter 加上pcie_acs_override=downstream
,不過 wiki[6]也有提到這是最後的選擇,可能會有風險, VM 可以讀取所有 Proxmox Host 的記憶體
參考
- [SOLVED] - x2apic: IRQ remapping doesn’t support X2APIC mode | Proxmox Support Forum ↩
- Windows 10 VM crashes/breaks during Nvidia driver install for GPU passthrough. - VM Engine (KVM) - Unraid ↩
- [SOLVED] - GPU Passthrough issue | Proxmox Support Forum ↩
- Windows: Line-Based vs. Message Signaled-Based Interrupts. MSI tool. | guru3D Forums ↩
- PCI passthrough via OVMF - ArchWiki ↩
- PCI Passthrough - Proxmox VE ↩
- PCI(e) Passthrough - Proxmox VE ↩
- PCI passthrough Error code 43 | Proxmox Support Forum ↩
- [TUTORIAL] - PCI/GPU Passthrough on Proxmox VE 8 : Installation and configuration | Proxmox Support Forum ↩
- Ultimate Beginner’s Guide to Proxmox GPU Passthrough ↩
- PCI通透 - HackMD ↩
- PVE虚拟机安装流程(推荐) · 游戏串运营教程 · 看云 ↩
- Proxmox显卡直通 - Noodlefighter’s Wiki ↩
- Proxmox VE 直通显卡方案及解决N卡Code43 - moper 工作技术展示 ↩