KVM/QEMUの仮想化Windows環境でGTX1070をパススルーする
いままで使っていたWindowsマシンをLinux環境上に移行します。WindowsではGPUを使っていたのでパススルーをして仮想環境上でも使えるようにします。ホストのLinux機はDebianを使用します。
以下に機材の構成を示します。
Core i7-6700 (Skylake) ASUSTeK Intel H170 MSI GTX 1070 GAMING X 8G
Intel CPUでパススルーを使うためにはVT-d (Virtualization Technology for Directed I/O )に対応している必要があります。
まずは、Debianの公式サイトからインストーラーのisoイメージをダウンロードします。
DHCP環境であればisoサイズの小さいnetinstが良いでしょう。
USBメモリに書き込むにはUniversal USB Installerやrufusを使うと簡単にできます。
VT-dは初期設定で無効になっていることがあるので、BIOSから有効にします。また、ホスト側でCPUのHD Graphicsを使うのであればiGPUを有効にします。
BIOSの設定が終わったらUSBデバイスからブートし、Debianをインストールします。今回はインストール時にLVMをセットアップしました。インストールが終わったのち再起動しますが、Geforceのドライバが上手く動かないことがあります。その時はGRUBのOS選択画面で起動パラメータを以下のように変更します。
quiet ↓ quiet modprobe.blacklist=nouveau
GUIが上がってきたら先程の起動パラメータが恒久的に適用されるよう変更します。加えて、パススルーを使うためintel_iommu=onを追記しIOMMUを有効化します。
[jinglan@host-debian]$ cat /etc/default/grub # If you change this file, run 'update-grub' afterwards to update # /boot/grub/grub.cfg. # For full documentation of the options in this file, see: # info -f grub -n 'Simple configuration' GRUB_DEFAULT=0 GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian` GRUB_CMDLINE_LINUX_DEFAULT="quiet modprobe.blacklist=nouveau intel_iommu=on" GRUB_CMDLINE_LINUX="" ... [jinglan@host-debian]$ [jinglan@host-debian]$ [jinglan@host-debian]$ sudo update-grub Generating grub configuration file ... Found background image: /usr/share/images/desktop-base/desktop-grub.png Found linux image: /boot/vmlinuz-4.9.0-7-amd64 Found initrd image: /boot/initrd.img-4.9.0-7-amd64 done [jinglan@host-debian]$
次に、仮想化に必要なソフトウェアをインストールします。
[jinglan@host-debian]$ sudo apt-get install qemu bridge-utils virt-manager ovmf
仮想化管理デーモンであるlibvirtdを起動します。
[jinglan@host-debian]$ sudo systemctl status libvirtd ● libvirtd.service - Virtualization daemon Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2018-12-21 21:57:45 JST; 1min 41s ago Docs: man:libvirtd(8) http://libvirt.org Main PID: 2571 (libvirtd) CGroup: /system.slice/libvirtd.service mq2571 /usr/sbin/libvirtd Dec 21 21:57:45 host-debian systemd[1]: Starting Virtualization daemon... Dec 21 21:57:45 host-debian systemd[1]: Started Virtualization daemon. [jinglan@host-debian]$ [jinglan@host-debian]$ [jinglan@host-debian]$ sudo systemctl enable libvirtd Synchronizing state of libvirtd.service with SysV service script with /lib/systemd/systemd-sysv-install. Executing: /lib/systemd/systemd-sysv-install enable libvirtd [jinglan@host-debian]$
続いてネットワークを設定します。ゲスト環境がネットワークに接続できるようブリッジを構成します。
[jinglan@host-debian]$ cat /etc/network/interfaces # This file describes the network interfaces available on your system # and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* # The loopback network interface auto lo iface lo inet loopback auto enp4s0 iface enp4s0 inet manual auto br0 iface br0 inet dhcp bridge_ports enp4s0 [jinglan@host-debian]$
コンピュータを再起動し、設定が反映されているか確認します。
[jinglan@host-debian]$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp4s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state UP group default qlen 1000 link/ether 70:8b:cd:9e:b7:0a brd ff:ff:ff:ff:ff:ff inet 192.168.11.75/24 brd 192.168.11.255 scope global dynamic enp4s0 valid_lft 171164sec preferred_lft 171164sec 3: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000 link/ether 70:8b:cd:9e:b7:0a brd ff:ff:ff:ff:ff:ff inet 192.168.11.75/24 brd 192.168.11.255 scope global br0 valid_lft forever preferred_lft forever inet6 fe80::728b:cdff:fe9e:b70a/64 scope link valid_lft forever preferred_lft forever [jinglan@host-debian]$
また、IOMMUが有効になっているのか確認します。
[jinglan@host-debian]$ sudo dmesg | grep -e DMAR -e IOMMU [ 0.000000] ACPI: DMAR 0x00000000A2EA18F8 0000A8 (v01 INTEL SKL 00000001 INTL 00000001) [ 0.000000] DMAR: IOMMU enabled [ 0.052829] DMAR: Host address width 39 [ 0.052830] DMAR: DRHD base: 0x000000fed90000 flags: 0x0 [ 0.052835] DMAR: dmar0: reg_base_addr fed90000 ver 1:0 cap 1c0000c40660462 ecap 7e3ff0505e [ 0.052836] DMAR: DRHD base: 0x000000fed91000 flags: 0x1 [ 0.052838] DMAR: dmar1: reg_base_addr fed91000 ver 1:0 cap d2008c40660462 ecap f050da [ 0.052839] DMAR: RMRR base: 0x000000b3b7f000 end: 0x000000b3b9efff [ 0.052840] DMAR: RMRR base: 0x000000b5800000 end: 0x000000b7ffffff [ 0.052841] DMAR-IR: IOAPIC id 2 under DRHD base 0xfed91000 IOMMU 1 [ 0.052842] DMAR-IR: HPET id 0 under DRHD base 0xfed91000 [ 0.052842] DMAR-IR: Queued invalidation will be enabled to support x2apic and Intr-remapping. [ 0.054170] DMAR-IR: Enabled IRQ remapping in x2apic mode [ 0.515358] DMAR: No ATSR found [ 0.515677] DMAR: dmar0: Using Queued invalidation [ 0.515680] DMAR: dmar1: Using Queued invalidation [ 0.515864] DMAR: Setting RMRR: [ 0.515925] DMAR: Setting identity map for device 0000:00:02.0 [0xb5800000 - 0xb7ffffff] [ 0.515962] DMAR: Setting identity map for device 0000:00:14.0 [0xb3b7f000 - 0xb3b9efff] [ 0.515966] DMAR: Prepare 0-16MiB unity mapping for LPC [ 0.515999] DMAR: Setting identity map for device 0000:00:1f.0 [0x0 - 0xffffff] [ 0.516008] DMAR: Intel(R) Virtualization Technology for Directed I/O [ 0.540870] AMD IOMMUv2 driver by Joerg Roedel <jroedel@suse.de> [ 0.540870] AMD IOMMUv2 functionality not available on this system
IOMMU enabledとあれば有効になっています。 以下のスクリプトを使ってIOMMUグループを確認します。
[jinglan@host-debian]$ ./check_iommu.sh IOMMU Group 0 00:00.0 Host bridge [0600]: Intel Corporation Skylake Host Bridge/DRAM Registers [8086:191f] (rev 07) IOMMU Group 10 02:00.0 PCI bridge [0604]: ASMedia Technology Inc. ASM1083/1085 PCIe to PCI Bridge [1b21:1080] (rev 04) IOMMU Group 11 04:00.0 Ethernet controller [0200]: Realtek Semiconductor Co., Ltd. RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller [10ec:8168] (rev 15) IOMMU Group 12 05:00.0 Non-Volatile memory controller [0108]: Intel Corporation Device [8086:f1a6] (rev 03) IOMMU Group 1 00:01.0 PCI bridge [0604]: Intel Corporation Skylake PCIe Controller (x16) [8086:1901] (rev 07) IOMMU Group 1 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP104 [GeForce GTX 1070] [10de:1b81] (rev a1) IOMMU Group 1 01:00.1 Audio device [0403]: NVIDIA Corporation GP104 High Definition Audio Controller [10de:10f0] (rev a1) IOMMU Group 2 00:02.0 VGA compatible controller [0300]: Intel Corporation HD Graphics 530 [8086:1912] (rev 06) IOMMU Group 3 00:14.0 USB controller [0c03]: Intel Corporation Sunrise Point-H USB 3.0 xHCI Controller [8086:a12f] (rev 31) IOMMU Group 4 00:16.0 Communication controller [0780]: Intel Corporation Sunrise Point-H CSME HECI #1 [8086:a13a] (rev 31) IOMMU Group 5 00:17.0 RAID bus controller [0104]: Intel Corporation SATA Controller [RAID mode] [8086:2822] (rev 31) IOMMU Group 6 00:1c.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #3 [8086:a112] (rev f1) IOMMU Group 7 00:1c.3 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #4 [8086:a113] (rev f1) IOMMU Group 8 00:1d.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #9 [8086:a118] (rev f1) IOMMU Group 9 00:1f.0 ISA bridge [0601]: Intel Corporation Sunrise Point-H LPC Controller [8086:a144] (rev 31) IOMMU Group 9 00:1f.2 Memory controller [0580]: Intel Corporation Sunrise Point-H PMC [8086:a121] (rev 31) IOMMU Group 9 00:1f.3 Audio device [0403]: Intel Corporation Sunrise Point-H HD Audio [8086:a170] (rev 31) IOMMU Group 9 00:1f.4 SMBus [0c05]: Intel Corporation Sunrise Point-H SMBus [8086:a123] (rev 31)
今回はGeForce GTX 1070をパススルーするのでGroup 1を使います。 パススルーするデバイスにVFIOドライバを割り当てるよう設定します。
[jinglan@host-debian]$ cat /etc/modprobe.d/vfio.conf options vfio-pci ids=8086:1901,10de:1b81,10de:10f0 [jinglan@host-debian]$
起動時にVFIOドライバを読み込むよう設定します。
[jinglan@host-debian]$ cat /etc/modules-load.d/modules.conf # /etc/modules: kernel modules to load at boot time. # # This file contains the names of kernel modules that should be loaded # at boot time, one per line. Lines beginning with "#" are ignored. vfio-pci [jinglan@host-debian]$
再起動後にVFIOドライバが読み込まれていることを確認します。
[jinglan@host-debian]$ sudo dmesg | grep -i vfio [ 2.818521] VFIO - User Level meta-driver version: 0.3 [ 2.826175] vfio_pci: add [8086:1901[ffff:ffff]] class 0x000000/00000000 [ 2.844215] vfio_pci: add [10de:1b81[ffff:ffff]] class 0x000000/00000000 [ 2.864241] vfio_pci: add [10de:10f0[ffff:ffff]] class 0x000000/00000000 [jinglan@host-debian]$ [jinglan@host-debian]$ lspci -nnk -d 10de:1b81 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GP104 [GeForce GTX 1070] [10de:1b81] (rev a1) Subsystem: Micro-Star International Co., Ltd. [MSI] GP104 [GeForce GTX 1070] [1462:3302] Kernel driver in use: vfio-pci Kernel modules: nouveau [jinglan@host-debian]$
次に、LVMで仮想環境用のストレージを確保します。まずは現在の状態を確認します。
[jinglan@host-debian]$ sudo vgdisplay --- Volume group --- VG Name host-debian-vg System ID Format lvm2 Metadata Areas 1 Metadata Sequence No 5 VG Access read/write VG Status resizable MAX LV 0 Cur LV 2 Open LV 2 Max PV 0 Cur PV 1 Act PV 1 VG Size 446.89 GiB PE Size 4.00 MiB Total PE 114404 Alloc PE / Size 27907 / 109.01 GiB Free PE / Size 86497 / 337.88 GiB VG UUID gNTxoB-nh5M-4mTK-V7fa-24uO-oRnJ-RYSewh [jinglan@host-debian]$ [jinglan@host-debian]$ sudo lvdisplay --- Logical volume --- LV Path /dev/host-debian-vg/swap_1 LV Name swap_1 VG Name host-debian-vg LV UUID DdzeNe-qgxE-1GP6-oQt4-g2uY-9pVr-1RdcPt LV Write Access read/write LV Creation host, time host-debian, 2018-12-21 20:51:58 +0900 LV Status available # open 2 LV Size 15.88 GiB Current LE 4066 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:0 --- Logical volume --- LV Path /dev/host-debian-vg/root LV Name root VG Name host-debian-vg LV UUID Tb8tjV-1Ig6-pzGt-o8Fc-UdqV-R5di-jY8T5e LV Write Access read/write LV Creation host, time host-debian, 2018-12-21 20:53:02 +0900 LV Status available # open 1 LV Size 93.13 GiB Current LE 23841 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:1 [jinglan@host-debian]$
今回は80GB分の容量を確保します。
[jinglan@host-debian]$ sudo lvcreate -L80G -n /dev/host-debian-vg/vm-win10-disk Logical volume "vm-win10-disk" created. [jinglan@host-debian]$ sudo lvscan ACTIVE '/dev/host-debian-vg/swap_1' [15.88 GiB] inherit ACTIVE '/dev/host-debian-vg/root' [93.13 GiB] inherit ACTIVE '/dev/host-debian-vg/vm-win10-disk' [80.00 GiB] inherit [jinglan@host-debian]$
今回はゲストとしてWindows10 Proをインストールします。WIndowsのISOイメージは公式のMedia Creation Toolを使って取得することができます。
また、Windows用のドライバを以下のサイトからダウンロードしておきます。
virt-installコマンドでゲストを作成します。
[jinglan@host-debian]$ sudo virt-install --name win10main --ram 4096 --vcpus 4 --os-type windows --disk path=/dev/host-debian-vg/vm-win10-disk,bus=sata --network bridge=br0,model=virtio --graphics=vnc,listen=0.0.0.0,port=5901 --cdrom=/home/jinglan/virt/iso/Windows10media.iso --cdrom=/home/jinglan/virt/iso/virtio-win.iso --boot uefi WARNING Graphics requested but DISPLAY is not set. Not running virt-viewer. WARNING No console to launch for the guest, defaulting to --wait -1 Starting install... Creating domain... | 0 B 00:00:00 Domain installation still in progress. Waiting for installation to complete. Domain has shutdown. Continuing. Domain creation completed. Restarting guest. [jinglan@host-debian]$
VNCを使ってlocalhost:1へ接続するとUEFIのオープンソース実装であるOVMFファームウェアが起動し、Windowsのインストール画面になることが確認できます。GeForceを使う場合はUEFIで起動しないとドライバがエラー43となり使うことができません。
Windowsのインストールが終了したらGPUパススルーのため一部設定を変更します。 ここにあるように、NVIDIAのGPUを使うときは以下の設定を追加します。
... <features> <hyperv> ... <vendor_id state='on' value='0123456789ab'/> ... </hyperv> ... <kvm> <hidden state='on'/> </kvm> </features> ...
続いて、パススルーするデバイスIDを指定します。
[jinglan@host-debian]$ sudo virsh edit win10main ... <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x0'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> </hostdev> <hostdev mode='subsystem' type='pci' managed='yes'> <source> <address domain='0x0000' bus='0x01' slot='0x00' function='0x1'/> </source> <address type='pci' domain='0x0000' bus='0x00' slot='0x08' function='0x0'/> </hostdev> ... [jinglan@host-debian]$
再度、仮想Windowsを起動するとGPUを認識しているはずです。少々待つとWinidowsが自動的にNVIDIAのドライバをインストールしてくれます。
自分の場合はWindowsのライセンス認証が上手くいかず、MSに電話することになりました。購入していたのはパッケージ版なので仮想環境に移すのはOKらしいのですが、移すたび電話認証が必要になるかもしれないとのこと。