前言
這篇其實是延續上一篇,成功在 mac 上利用 wimlib
分割檔案的方式製作好 Win10 安裝碟之後,我試著在乾淨的機器裡嘗試安裝,到了安裝階段卻不斷出現安裝失敗的提示,於是我只好暫時放棄 Windows,轉而先灌 Arch Linux1。
想要在同一顆硬碟上裝雙系統通常都會先灌 Windows 再灌 Linux,因為 Windows 會把啟動磁區覆蓋掉。而我既然已先灌好 Arch Linux ,雙系統這條路可以說是走不通了,為了不想繼續和 Windows ISO 糾纏太久(但又很想玩遊戲),只好開始研究其他解決方案。
解決方案是有的——把 Windows 裝在虛擬機內就好了啊!
只是一般的虛擬機如果想要拿來打遊戲,效能絕對不敷使用,我們需要使用 QEMU + KVM 2。
如果有時間的話,推薦直接去看這篇 ArchWiki,那邊的資訊非常詳盡,這篇只記錄重點步驟。
安裝前準備/確認系統需求
參考 ArchWiki: KVM (Checking support for KVM)
實際動手之前,我們必須確認硬體支援,我們需要:
- 至少兩個 GPU(例如一個內顯、一個獨顯)3
- CPU 支援虛擬化技術及 IOMMU(確認方式下面詳述)
- 主機板支援 IOMMU
- 不確定的話請參考這個 wiki
- 要給虛擬機使用的 GPU ROM 支援 UEFI
- 這個網站可以查,基本上 2012 年之後的 GPU 應該都有支援
確認 CPU 有支援虛擬化技術
KVM 需要有支援此功能才能正常運作,Intel 會叫做 VT-x,AMD 則會叫做 AMD-V,你可以用以下指令確認:
LC_ALL=C lscpu | grep Virtualization
# or
grep -E --color=auto 'vmx|svm|0xc0f' /proc/cpuinfo
如果上述指令沒有 return 任何結果,代表你的硬體不支援虛擬化技術,你可以洗洗睡了4。
確認 Kernel 支援
如果你是使用最新的 Arch Linux kernel,那麼應該有支援,或者你也可以輸入以下指令:
zgrep CONFIG_KVM /proc/config.gz
確認 kvm 以及 kvm_amd/kvm_intel 之一有出現在列表中,並且值為 y
或 m
。
並且確認該 kernel 模組有自動載入:
lsmod | grep kvm
如果上述指令沒有 return 任何結果,你必須手動載入5:
modprobe kvm
安裝/設定必要套件
# qemu
sudo pacman -S qemu
# 管理 vm 的圖形介面
sudo pacman -S libvirt virt-manager
# 連接網路需要的套件
sudo pacman -S ebtables dnsmasq bridge-utils openbsd-netcat
# UEFI support
sudo pacman -S edk2-ovmf
權限設定
由於要使用 virt-manager
的圖形介面調整 libvirt
的設定,需要把自己加入 libvirt
的 group 內,以免發生權限問題
# 編輯設定檔
sudo vim /etc/polkit-1/rules.d/50-libvirt.rules
加入以下內容
/* Allow users in kvm group to manage the libvirt
daemon without authentication */
polkit.addRule(function(action, subject) {
if (action.id == "org.libvirt.unix.manage" &&
subject.isInGroup("kvm")) {
return polkit.Result.YES;
}
});
並且也把自己加入 kvm
group:
sudo usermod -a -G kvm $(whoami)
啟動服務
sudo systemctl enable libvirtd.service # optional, 每次開機自動啟動
sudo systemctl start libvirtd.service
sudo systemctl start virtlogd.service
建立虛擬機
我們使用 virt-manager
的圖形介面來建立虛擬機,圖形介面很直覺,不多贅述,依照自己需求修改即可,需要特別注意如下:
- 在建立前的最後一步,勾選「Customize before install」
- 在「Overview」選項內,將「Firmware」選項選為「UEFI x86_64」
因為建立之後就沒有辦法修改 firmware 了,所以一定要在這時修改。
完成各項設定後,虛擬機就開好了,接着來安裝作業系統!
安裝作業系統
把 ISO 檔掛載到虛擬機就可以安裝了,非常簡單,安裝時有一個畫面是需要填序號,可以先不填,一樣可以安裝成功。
安裝成功之後應該可以正常使用 Windows,但這時候效能還很慘,我們必須把 GPU 直通給虛擬機使用。
GPU passthrough
# 複製原本的 boot loader,畢竟不是每次都想 passthrough,也避免改錯有個保險
sudo cp /boot/loader/entries/arch.conf /boot/loader/entries/arch-kvm.conf
sudo vim /boot/loader/entries/arch-kvm.conf
這時根據 CPU 不同,
- AMD 的 CPU(AMD-Vi),加上
options amd_iommu=on
- Intel 的 CPU(VT-d),加上
options intel_iommu=on
因此 loader 設定會變成這樣(以 intel 爲例):
title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /linux-kvm.img
options root=PARTUUID=<UUID> rw
options intel_iommu=on
重新開機,然後確認 dmesg
訊息:
dmesg | grep -i -e DMAR -e IOMMU
確認 IOMMU Groups
以下指令可以列出 IOMMU Groups
#!/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;
輸出應該會類似:
IOMMU Group 1:
00:01.0 PCI bridge: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port [8086:0151] (rev 09)
IOMMU Group 2:
00:14.0 USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller [8086:0e31] (rev 04)
IOMMU Group 4:
00:1a.0 USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 [8086:0e2d] (rev 04)
IOMMU Group 10:
00:1d.0 USB controller: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 [8086:0e26] (rev 04)
IOMMU Group 13:
06:00.0 VGA compatible controller: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1)
06:00.1 Audio device: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1)
一個 IOMMU Group 是可以直通給虛擬機的最小單位,在此範例中,顯卡位於 IOMMU Group 13
,和音效卡同一個 group,必須一起直通給虛擬機使用。
請記下 10de:13c2
及 10de:0fbb
,這是它們的 device ID,待會會用到。
Isolating the GPU
使用 vfio-pci
綁定指定裝置
一樣編輯 /boot/loader/entries/arch-kvm.conf
,新增一行 options,加上 vfio-pci.ids=[你的 device id]
,範例:
options vfio-pci.ids=10de:13c2,10de:0fbb
盡早載入 vfio-pci
# 複製一份專用設定
cp /etc/mkinitcpio.conf /etc/mkinitcpio-kvm.conf
# 編輯
sudo vim /etc/mkinitcpio-kvm.conf
找到 MODULES 及 HOOKS 區塊,加上以下模組:
MODULES=(... vfio_pci vfio vfio_iommu_type1 vfio_virqfd ...)
...
HOOKS=(... modconf ...)
然後產生一份新的 initramfs
:
# linux-kvm.img 這個名稱可以自己決定
mkinitcpio -c /etc/mkinitcpio-kvm.conf -g /boot/linux-kvm.img
產生完成後再調整一下 boot loader 設定:sudo vim /boot/loader/entries/arch-kvm.conf
title Arch Linux
linux /vmlinuz-linux
initrd /intel-ucode.img
initrd /linux-kvm.img
options root=PARTUUID=<UUID> rw
options intel_iommu=on
options vfio-pci.ids=10de:13c2,10de:0fbb
重新開機,確認 vfio-pci
的設定生效:
dmesg | grep -i vfio
調整顯示卡設定
開啓 virt-manager
設定,按右鍵依序選擇「Add Hardware > PCI Host Device」,在列表中找到剛剛設定好直通的設備新增,然後開機。
如果上面的設定都沒問題,系統應該可以偵測到我們直通進去的那張顯卡,可能會需要上網抓最新的驅動程式。
在 Windows 裝置管理員檢查顯示卡,按「右鍵 > 內容」,如果裝置狀態爲「這個裝置正常運作中」,那就沒問題了!
疑難排解
重新啟動之後網路無法連線6
# 注意,你可能會需要加 `sudo` 才看得到列表
virsh net-list --all
# 假設你是用 default
virsh net-autostart default
virsh net-start default
有抓到顯卡,但是看起來沒什麼作用
因爲顯卡必須偵測到有螢幕接上才能正常使用,你有 2 個選擇:
-
如果你有 2 臺以上的螢幕,你可以直接將螢幕接到顯卡上,然後在「系統 > 顯示器 > 多部顯示器」設定內,調整爲「只在 2 顯示」。
-
或者你像我一樣,只有 1 臺螢幕。就需要在「系統 > 顯示器 > 圖形設定」自行選擇要使用該顯卡來輸出的應用程式7。
系統更新 pacman -Syu
之後 arch-kvm 無法開機
再跑一次以下指令,重新產生 initramfs 應該就可以正常起動了:
mkinitcpio -c /etc/mkinitcpio-kvm.conf -g /boot/linux-kvm.img
提示權限錯誤,無法開啓虛擬機
如果更新後出現 permission denied
之類的訊息,那就有可能是權限設定跑掉了。
請更新 /etc/libvirt/qemu.conf
:
sudo vim /etc/libvirt/qemu.conf
找到 user
和 group
,他們預設應該會被設爲 "root"
並註解,改爲你的 user 和 group:
[...]
# Some examples of valid values are:
#
# user = "qemu" # A user named "qemu"
# user = "+0" # Super user (uid=0)
# user = "100" # A user named "100" or a user with uid=100
#
user = "akccakcctw"
# The group for QEMU processes run by the system instance. It can be
# specified in a similar way to user.
group = "kvm"
[...]
確認 user 在 kvm
group 內:
sudo usermod -a -G kvm $(whoami)
虛擬機容量不夠
先確認虛擬機名稱並關閉:
$ sudo virsh list
Id Name State
-----------------------
4 win10 running
$ sudo virsh shutdown win10
取得虛擬機檔案路徑:
sudo virsh domblklist win10
查看檔案 info:
sudo qemu-img info ~/vbox/win10.qcow2
擴充虛擬機磁碟大小
sudo qemu-img resize ~/vbox/win10.qcow2 + 10G
注意如果有開啓 snapshot,需要先移除所有 snapshot,才有辦法擴充磁碟
sudo virsh snapshot-list win10
sudo virsh snapshot-delete --domain win10 --snapshotname snapshot
sudo virst snapshot-list win10
參考資料
- ArchWiki: KVM
- ArchWiki: libvirt
- ArchWiki: PCI passthrouth via OVMF
- Archlinux 下使用 KVM 代替 Vmware
- [Linux KVM] 半虛擬化驅動(Paravirtualization Driver)
- reddit: Help turning on iommu (Arch Linux)
- reddit: GPU Passthrough - Or How To Play Any Game At Near Native Performance In A Virtual Machine
- GitHub: GPU Passthrough from Arch Linux
- Intel GVT-g
- Cannot access storage file, Permission denied Error in KVM Libvirt
- How To extend/increase KVM Virtual Machine (VM) disk size
Footnotes
-
注意 archlinux 2020.05 的 ISO 檔有問題,我改下載 2020.04 的才能正常安裝。 ↩
-
其實只有一個 GPU 也行,不過不在本文討論範圍內,可參考 https://github.com/joeknock90/Single-GPU-Passthrough ↩
-
別妄想用 VirtualBox 之類的一般虛擬機來玩遊戲,跑不動的。 ↩
-
https://www.reddit.com/r/VFIO/comments/6iwth1/network_default_is_not_active_after_every/djayhqu/ ↩
-
測試過只有設定的應用程式才會使用該顯卡運算,否則就算 CPU 跑到 100%,顯卡還是穩穩的維持在 0%。 ↩