【Ubuntu(ZORIN OS)】【QEMU/KVM】KVMによる仮想化WindowsへのGPUパススルー設定(+Win11化)@2025

1.はじめに

engetu21.hatenablog.com

過去仮想化を実施しましたが、新しいPCでやってみたいと思います。

環境はこれ。

・CPU:Ryzen 7 9700X (8C/16T、3.8GHz、TDP 65W、AM5、Radeon Graphics) BOX W/O cooler
マザボASRock X870 Steel Legend WiFi
・メモリ:DDR5-6000 64G(CP2K32G60C40U5W)
・グラボ:GV-N5070WF3OC-12GD(GIGABYTE NVIDIA Geforce RTX5070)
・M.2:Acer Predator Gen5 M.2 SSD 2TB GM9 NVMe2.0 2280 PCIe Gen5×
・電源:MSI MAG A850 GL PCIE5 WHITE 80PLUS GOLD
・ケース:NZXT H6 Flow White
・CPUクーラー:ALSEYE CPUクーラーM90
・ホストOS:ZORIN OS 17.3(Ubuntu)

今回はクリーンインストールではなく、動いているPC(旧PC)のWindows10を吸い出して、それを仮想環境(以下VM)で動くようにします。
 

2.旧PCのCドライブのイメージ吸い出し

普通のPCはCドライブにOSを入れていると思いますが、このCドライブをまるごとイメージ化します。
旧PCはイメージの吸い出しで使うのは、LinuxのLive版をインストールしたUSBメモリ
Linuxディストリビューションはどれでもいいですが、今回はZORIN OSにしました。

Live版ZORIN OSを起動し、

左下のボタンから[端末]を選択。

各ディスクの確認をします。

$ sudo fdisk -l
(略)
ディスク /dev/sdc: 232.89 GiB, 250059350016 バイト, 488397168 セクタ
Disk model: CT250MX500SSD1
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 4096 バイト
I/O サイズ (最小 / 推奨): 4096 バイト / 4096 バイト
ディスクラベルのタイプ: gpt
ディスク識別子: 0524FBBE-95C3-11F0-BCBB-B827EBCF3D67
(略)

Windowsが入っているドライブはMicrosoftとか名前が入っていたり、パーティションが別れているのでわかりやすく、私の環境では/dev/sdcが該当することがわかります。

あとはこれをddコマンドでイメージにするだけ。ファイルの吐き出し先は外付けUSB接続の3TBドライブとします。
接続した3TBは/media/zorin配下にマウントされているため、そちらをddコマンドのoutputに指定。
読み書きの速度はオプションで指定しないと激遅になるため、適当に10MBとします。

$ sudo dd if=/dev/sdc of=/media/zorin/3TB/win10.dd bs=10M

書き出しが完了したらLive版ZORIN OSはシャットダウンでOK。
※ちなみに6項で触れますが、この作業はもう一回やりました。

3.新PCへのZORIN OSのインストール

2項で使ったLive版ZORIN OSを使ってインストールをします。
USBメモリを指して起動、デスクトップにあるインストールボタンを押すだけであとは適当に次へを押せば完了するため、省略。
 

4.仮想環境の構築

7年ぐらい前はIntelでしたが、今回はRyzenなので、やり方が少し異なります。

4−1.IOMMUの有効化

IOMMUの適用についての確認をします。
ただこのコマンドはIntelでやった場合のみで、AMDでは表示が変わらないらしいです。
https://www.reddit.com/r/Proxmox/comments/13v04hx/trying_to_get_iommu_to_work/?tl=ja

$ sudo dmesg | grep -e DMAR -e IOMMU
[ 1.442903] pci 0000:00:00.2: AMD-Vi: IOMMU performance counters supported
[ 1.486483] perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank).

GRUBカーネルコマンドラインパラメータを変更します。

$ sudo vi /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"

GRUB_CMDLINE_LINUX_DEFAULT="quiet splash amd_iommu=on iommu=pt video=efifb:off"

今回はRyzen(AMD)なので、「amd_iommu=on」を入れます。
また、こちらのサイトを参考すると、「iommu=pt」「video=efifb:off」が推奨になっていたため、今回は入れます。
qiita.com

ここで再起動。

IOMMUの適用についての確認します。

$ sudo dmesg | grep -e DMAR -e IOMMU
[ 1.447134] pci 0000:00:00.2: AMD-Vi: IOMMU performance counters supported
[ 1.470482] perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank).

噂通り変わらない。。とりあえず、OS上はIOMMUは有効になったという前提で先に進めます。
ちなみに、今回使っているASRock X870 Steel Legend WiFiAMD-Vの有効/無効項目はなく、どうやら最近のAMD向けマザボはデフォルトで有効になっているらしいので、UEFIを弄る必要はないとのこと。
そのため、この状態で土台となるマザボとOSの仮想環境設定は一旦完了しました。
 

4−2.GPUパススルーのための情報収集

前回と同様、グラボのデバイス情報を取得します。

$cd ~/
$ vi aaa

#!/bin/bash
shopt -s nullglob
for d in /sys/kernel/iommu_groups/*/devices/*; do
n=${d#*/iommu_groups/*}; n=${n%%/*}
printf 'IOMMU Group %s ' "$n"
lspci -nns "${d##*/}"
done;

$ sudo chmod 755 aaa
$ ./aaa

(略)
IOMMU Group 13 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation Device [10de:2f04] (rev a1)
IOMMU Group 13 01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:2f80](rev a1)
(略)

赤字の部分が後の工程で絡んでくるのでメモっておきます。
 

4−2−1.vfio-pciの設定はしなくていい?

前回はホストOSでグラボを認識できないよう、あれやこれや↓をしました。
https://engetu21.hatenablog.com/entry/2018/04/03/003642#%EF%BC%91%EF%BC%91vfio-pci%E3%81%AE%E4%BD%BF%E7%94%A8


が、4-1項にてGRUBカーネルコマンドラインパラメータでiommu=ptの指定をしており、これはホストOS(今回はZORIN OS)がグラボを使わないようにする設定だそうなので、以前やっていた「vfio-pciの使用」を設定する必要がなくなるようです。

実施、コマンドでグラボがNVIDIAのドライバを使っていないか(vfio-pciを使うようにしているか)の確認してみるとこんな感じ。

$ lspci -nnk -d 10de:2f04
01:00.0 VGA compatible controller [0300]: NVIDIA Corporation Device [10de:2f04] (rev a1)
Subsystem: Gigabyte Technology Co., Ltd Device [1458:417e]
Kernel driver in use: vfio-pci
Kernel modules: nvidiafb, nouveau
$ lspci -nnk -d 10de:2f80
01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:2f80] (rev a1)
Subsystem: NVIDIA Corporation Device [10de:0000]
Kernel driver in use: vfio-pci
Kernel modules: snd_hda_intel

 
素晴らしい。
 

4−3.virt-managerlibvirtQEMUなどなどのインストール

前回はlibvirtの最新パッケージの更新として

ppa:jacob/virtualisation

を追加で設定していましたが、現在は配信停止されているようなので、素直にaptでインストールします。

$ sudo apt install -y libvirt-daemon-system ovmf libvirt-clients bridge-utils virt-manager qemu-kvm qemu-utils qemu-efi

多分上記のもので大丈夫だと思いますが、ダメだったら「libvirt-bin」「libvirt-dev」「libvirt0」辺りも入れてください。

libvirtの有効化を確認をします。

$ sudo systemctl is-active libvirtd
active

OKですね。
 
QEMUの仮想化が問題ないか確認します。

$ virt-host-validate
QEMU: Checking for hardware virtualization : PASS
QEMU: Checking if device /dev/kvm exists : PASS
QEMU: Checking if device /dev/kvm is accessible : PASS
QEMU: Checking if device /dev/vhost-net exists : PASS
QEMU: Checking if device /dev/net/tun exists : PASS
QEMU: Checking for cgroup 'cpu' controller support : PASS
QEMU: Checking for cgroup 'cpuacct' controller support : PASS
QEMU: Checking for cgroup 'cpuset' controller support : PASS
QEMU: Checking for cgroup 'memory' controller support : PASS
QEMU: Checking for cgroup 'devices' controller support : WARN (Enable 'devices' in kernel Kconfig file or mount/enable cgroup controller in your system)
QEMU: Checking for cgroup 'blkio' controller support : PASS
QEMU: Checking for device assignment IOMMU support : PASS
QEMU: Checking if IOMMU is enabled by kernel : PASS
QEMU: Checking for secure guest support : WARN (Unknown if this platform has Secure Guest support)

(略)

LXC: Checking for cgroup 'devices' controller support : FAIL (Enable 'devices' in kernel Kconfig file or mount/enable cgroup controller in your system)
LXC: Checking for cgroup 'freezer' controller support : FAIL (Enable 'freezer' in kernel Kconfig file or mount/enable cgroup controller in your system)

何やらWARNとFAILが…


higmasan.com
unix.stackexchange.com
このあたりサイトを見ると、どうやら
intel_iommu=on
systemd.unified_cgroup_hierarchy=0
カーネルコマンドラインパラメータに記載し、
grub2-mkconfig
を使って設定を変更すればいいといったことが書かれている。
 
しかし、私が使っているのはAMDのCPUであり、intel iommu=onを書く必要はまずない。
そしてZORIN OSにはgrub2-mkconfigのコマンドはない(grub-mkconfigはある。多分ベースになっているUbuntuも同様?)

discussion.fedoraproject.org
↑の記載を読むと、どうもOSがcgroup2を使っているならfreezeを使う必要はないとのことが書かれている(必要なのはcgroup1とのこと)

gihyo.jp
cgroupはプロセスをグループ化して制限をかけられる技術…とのことだけど、いまいち不明。

cgroupのv1とv2を調べる方法は以下のサイトを参考とし、少なくともZorin OS17.3に関してはcgroup v2が動いている模様。
kazuhira-r.hatenablog.com

$ stat -fc %T /sys/fs/cgroup/
cgroup2fs

cgroup2fsなので、cgroup2みたいですね。
 
freezeはいらんと言っているページを翻訳すると、

同じエラーに遭遇し、冷凍庫を使用する必要性を調べた結果、cgroup2 を使用する場合には冷凍庫は必要ないことがわかりました。もし systemd.unified_cgroup_hierarchy=0 GRUB のコマンド ラインで追加されると、システムは非推奨の cgroups1 を使用することになります。

走ろうとした時に気づいた podman、そして私はcgroup1 を使用していることを助言する警告を得ました。行を削除すると、メッセージが消えました。

私の理解では、FAIL メッセージは次のとおりです virt-host-validate cgroup_freezer は無効にする必要があるため、cgroup2 を使用するシステムには関係ありません

これはWARNとFAILは無視していいのでは…?というのが今の所の結論。
実際のところこの後にQEMUでのVM起動とGPUパススルーは成功したので、(性能は劣化しているかもしれませんが)とりあえず無視します。

4−4.libvirtdとvirtlogdが動いているかsystemctlで確認

$ sudo systemctl status libvirtd
● libvirtd.service - Virtualization daemon
Loaded: loaded (/lib/systemd/system/libvirtd.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2025-09-16 16:43:22 JST; 9min ago

$ sudo systemctl status virtlogd
○ virtlogd.service - Virtual machine log manager
Loaded: loaded (/lib/systemd/system/virtlogd.service; indirect; vendor preset: enabled)
Active: inactive (dead)
TriggeredBy: ● virtlogd.socket
● virtlogd-admin.socket
Docs: man:virtlogd(8)
https://libvirt.org

libvirtdの方はすでに起動しており、自動で立ち上がるようになっていると思われるけど、念の為enableは実行しておきます。
virtlogdはinactive (dead)だったので、起動した上でenable実行。

$ sudo systemctl enable libvirtd
$ sudo systemctl enable virtlogd
$ sudo systemctl start virtlogd
$ sudo systemctl status virtlogd

● virtlogd.service - Virtual machine log manager
Loaded: loaded (/lib/systemd/system/virtlogd.service; indirect; vendor preset: enabled)
Active: active (running) since Sat 2025-09-20 00:15:21 JST; 4min 14s ago
TriggeredBy: ● virtlogd-admin.socket
● virtlogd.socket
Docs: man:virtlogd(8)
https://libvirt.org
Main PID: 4741 (virtlogd)
Tasks: 1 (limit: 74024)
Memory: 2.2M
CPU: 5ms
CGroup: /system.slice/virtlogd.service
└─4741 /usr/sbin/virtlogd

5.VMの構築とWindows10のイメージファイルの指定

4-3項のインストールが問題なければ、スタートメニューに「仮想マシンマネージャー」があるはずなので、そちらを起動。

仮想マシンを作ります。

モニタのボタンをクリック。
 

ddコマンドで抽出したイメージを使うので上から3番目を選択。
 

参照ボタンを押して、仮想イメージを指定。
下部のオペレーションシステムの選択は適当に「win」と入力し、出てきたwindows10を選択。


メモリは適当に32GB。
CPUは8としておきます。が、この設定はソケット数らしく、これはWin11へのアップグレードのため、後で変更します。
 

ここでは「インストールの前に設定をカスタマイズする」を必ずチェックします。
 
先程の「インストールの前に設定をカスタマイズする」をチェックしていると、カスタマイズ画面になります。

ここでいくつか設定変更します。
まず1つ目は概要シートのファームウェアを「UEFI」に変更。チップセットは「Q35」のままでOK。
この設定はこの時変更しないと、以降カスタマイズ画面から変更できないため注意(一応、後から対象のXMLファイルを書き換えればできますが、変更が面倒)。
ファームウェアは「UEFI」を選択しましたが、後ほどWindowsが立ち上がったときに確認した限りだと、セキュアブートに対応していたため、他の候補を選択する必要はなさそうです。




CPU数ページを変更。host-passthroughはそのまま。(これにしておくとVM上でもRyzen 7 9700Xとして認識される)
作成時にCPUを8としていましたが、それだとソケット数8個扱いでwin11の2コア以上の条件がクリアにならないようなので、ここはCPUトポロジーを手動設定し、2コア4スレッドに変更。

Windows11に必須のTPMも追加しておきます。カスタマイズ画面の左下の「ハードウェアを追加」を押下。TPMを選択し、

設定はそのままで完了。
 
グラフィックボードを認識させます。
カスタマイズ画面の左下の「ハードウェアを追加」を押下。PCIホストデバイスから、

0000:01:00:0 NVIDIA Corporation
0000:01:00:1 NVIDIA Corporation

をそれぞれ追加します。
これは4-2項で確認した、01:00.0と01:00.1が該当します。まぁ、NVIDIAと書いてあるし、他のNVIDIA製品を使ってない限りは、これしか出てきません。
 
一旦、この状態で左上の「インストールの開始」を実行!
 

おや・・・?Windowsが起動しない。。

6.仮想Windows10が起動しない件と解決策

色々試すと、ファームウェアで「BIOS」を選択するとWindows10起動し、「UEFI」を選択すると起動しませんでした。
これはファイル形式がrawでもqcow2でも同様。選択したUEFIがセキュアブートに対応してないから?と思いましたが、どうも根本的に何かが違うということでさらに調べたところ、どうやら吸い出した際のWindows10のディスクがMBR形式であり、それだとダメで、GPT形式になっている必要がある模様。
なので、吸い出し元の旧PCでMBR→GPTに変換します。
実施方法は別に書き起こしました。
engetu21.hatenablog.com



これをZORIN OSのLive版にてddコマンドで2項と同じようにrawファイルとして書き出し、新PCにファイルコピーします。
 
コピー後、rawファイルはQEMUのディスクイメージ(qcow2)に変換します。ファームウェアが「UEFI」でrawファイルのWIndowsが起動できるのかは謎ですが(試さなかった)、ディスク容量を拡張する必要があるので、このタイミングで変換します(拡張は形式変えなくてもいけるかも?とりあえず変換します)。
参考:
docs.openstack.org

rawファイル→qcow2ファイルへの変換コマンドは以下の通り。

$ qemu-img convert -f raw -O qcow2 win10-2.raw win10-2.qcow2

 
続けて、先程触れたとおり、変換して作った「win10-2.qcow2」ファイルの容量を拡張します。
吸い出したイメージファイルは、上限が吸い出し元の最大ディスク容量分しかない、かつすでに容量カツカツで使っていたため、windows11にアップグレードするために容量を増やしておく必要があります。
とりあえず200GB追加します。

$ sudo qemu-img resize win10-2.qcow2 +200G
Image resized.

 
VMは作り直すか、ディスク追加で先程作ったqcow2ファイルを指定して追加。

[SATAディスク2]が新たに追加されます。この際、元々あった[SATAディスク1]を右クリックから削除します。
すると[SATAディスク2]が[SATAディスク1]に変更されます。(つまりディスクの入れ替えができる)

この状態で再度VMを起動します。



無事起動!

システムの詳細情報を見てみると・・・

すでにグラボが認識されています。デバイスマネージャーを見ても同様。
 
以前はvendor id偽装(【Linux Mint】【QEMU/KVM】KVMによる仮想化Win10へのGPUパススルー設定 - 技術メモ)という面倒な作業を実施しており、というのもTeslaといったGPGPU専用グラボ以外はGPUパススルーができなかったからですが、どうやらAI生成やら諸々の流れでどうやらそういった制約は解除された模様(どこかのページでベータ版とかなんとか書いてあったような)。


7.仮想Windows上でのディスク容量拡張

qcow2イメージファイルに200GBを追加しましたが、Windows上でも拡張処理が必要なので、それをやります。

↓200GB分追加されている

 
ディスクの管理画面で操作してみましたが・・・おや、パーティションの拡張ができない。。
どうやらGPT形式に変更した際にパーティションの位置が変わった模様。
Cドライブ領域が一番右なら拡張できるはずですが、現状はそうではないためOSの機能ではできない模様。。
しょうがないので、ツールを使って対応します。
MiniTool Partition Wizard(https://www.partitionwizard.jp/)をインストールし、起動します。

Cドライブを選択肢、右クリックから[拡張]を押下。
 

ウィザードが出てくるので、空き領域全部を選択(バーを右にグイッとして)、[OK]を押下。
 

画面下のCドライブの領域が増えていること確認し、左下の[適用]を押下

問題なく完了すれば、領域が拡張されます。

8.仮想Windows10をWindows11へアップグレード

システム画面でWindows11へのアップグレードのメニューが出てくればいいんですが、出てこないのでアップグレードアプリから実行します。
キャプチャは忘れましたが、正常性診断のツールでWindows11へのアップグレード要件を満たしていることは確認済み。
 
一応、Windows10のイメージファイル(qcow2ファイル)はバックアップをとってから実行します。VMはこういうときに便利。

www.microsoft.com
から「Windows 11 インストール アシスタント」をダウンロードし、実行。

ひたすら待ちます。



無事、Windows11化完了です。

9.グラボ経由でのモニタ表示

一旦、WindowsVMをシャットダウンし、USBパススルーによる物理キーボードとマウスの接続、及び「ディスプレイSpice」と「ビデオQXL」を削除し、グラボでの画面描写に切り替えます。
これにより、グラボを経由したモニタ表示とホストOSから独立したキーボード/マウスによる操作ができるようになります。
 
無論、「ディスプレイSpice」と「ビデオQXL」を削除せず、ホストOS上で表示しながら操作も可能ですが、もしこのVM環境でゲームをやる場合、GPUを利用した描写ができないため、ゲームはろくに動かないと思われます。
ただ、生成AIを実行する場合に対してはそうではないと思われ、生成AIアプリがグラボを認識してくれれば、画面描写はVMの素の機能、生成AIアプリはグラボを利用と分けられるかもしれません(←やってみました。どうやらできる模様)。
VMを2つ設け、①ゲーム用、②それ以外と分け、お互い同一のWindows11のイメージディスクを指しつつも、必ず同時実行をしないようにしつつ(これは自分で気をつけるしかない)、ゲームしたいときはグラボから画像出力する①、それ以外は②、という風に運用するのも面白いかもしれません。