「OVMF による PCI パススルー」の版間の差分
(同期) |
細 (リンクを修正) |
||
(10人の利用者による、間の36版が非表示) | |||
1行目: | 1行目: | ||
+ | {{Translateme|記事が古くなっているとの指摘がありました}} |
||
[[Category:仮想化]] |
[[Category:仮想化]] |
||
[[en:PCI passthrough via OVMF]] |
[[en:PCI passthrough via OVMF]] |
||
+ | [[zh-hans:PCI passthrough via OVMF]] |
||
− | Open Virtual Machine Firmware ([http://www.tianocore.org/ovmf/ OVMF]) は仮想マシンで UEFI を使えるようにするプロジェクトです。Linux 3.9 と新しいバージョンの QEMU では、グラフィックカードをパススルーすることが可能で、仮想マシンでネイティブと同じグラフィック性能を発揮することができます。 |
||
+ | {{Related articles start}} |
||
+ | {{Related|Intel GVT-g}} |
||
+ | {{Related|:en:PCI passthrough via OVMF/Examples}} |
||
+ | {{Related|:en:QEMU/Guest graphics acceleration}} |
||
+ | {{Related articles end}} |
||
+ | Open Virtual Machine Firmware ([https://github.com/tianocore/tianocore.github.io/wiki/OVMF OVMF]) は仮想マシンで UEFI を使えるようにするプロジェクトです。Linux 3.9 以上と最近のバージョンの [[QEMU]] では、グラフィックカードをパススルーすることが可能で、仮想マシンでネイティブと同じグラフィック性能を発揮することができ、グラフィック性能が要求されるタスクにおいて便利です。 |
||
− | デスクトップコンピュータに使用していない GPU が接続されている場合 (内蔵 GPU や古い OEM カードでもかまいません、ブランドが一致している必要はありません)、ハードウェアがサポートしていれば ([[#要件]]を参照)、あらゆる OS の仮想マシンで専用 GPU として(ほぼ)最大限の性能を活用できます。技術的な詳細は [ |
+ | デスクトップコンピュータに使用していない GPU が接続されている場合 (内蔵 GPU や古い OEM カードでもかまいません、ブランドが一致している必要はありません)、ハードウェアがサポートしていれば ([[#要件]]を参照)、あらゆる OS の仮想マシンで専用 GPU として(ほぼ)最大限の性能を活用できます。技術的な詳細は [https://www.linux-kvm.org/images/b/b3/01x09b-VFIOandYou-small.pdf こちらのプレゼンテーション (pdf)] を見てください。 |
== 要件 == |
== 要件 == |
||
9行目: | 16行目: | ||
* CPU がハードウェア仮想化 (KVM) と IOMMU (パススルー) をサポートしていること。 |
* CPU がハードウェア仮想化 (KVM) と IOMMU (パススルー) をサポートしていること。 |
||
− | ** [ |
+ | ** [https://ark.intel.com/ja/Search/FeatureFilter?productType=processors&VTD=true Intel の対応 CPU リスト (Intel VT-x と Intel VT-d)] |
+ | ** Bulldozer 世代以降 (Zen も含む) の AMD 製 CPU は全て対応しています。 |
||
− | ** [http://support.amd.com/en-us/kb-articles/Pages/GPU120AMDRVICPUsHyperVWin8.aspx AMD の対応 CPU リスト (AMD-V と AMD-Vi)] |
||
+ | *** K10 世代 (2007年) の CPU は IOMMU を搭載していないため、[https://support.amd.com/TechDocs/43403.pdf#page=18 890FX] や [https://support.amd.com/TechDocs/48691.pdf#page=21 990FX] チップセットが搭載されたマザーボードが必要です。 |
||
* マザーボードが IOMMU をサポートしていること。 |
* マザーボードが IOMMU をサポートしていること。 |
||
− | ** チップセットと BIOS の両方が対応している必要があります。対応しているかどうかすぐに判断することはできませんが、[ |
+ | ** チップセットと BIOS の両方が対応している必要があります。対応しているかどうかすぐに判断することはできませんが、[https://wiki.xen.org/wiki/VTd_HowTo Xen wiki の対応ハードウェアリスト] や [[wikipedia:List_of_IOMMU-supporting_hardware|Wikipedia の対応リスト]]が存在します。 |
* ゲスト GPU ROM が UEFI をサポートしていること。 |
* ゲスト GPU ROM が UEFI をサポートしていること。 |
||
** [https://www.techpowerup.com/vgabios/ このリストに載っている ROM] に使用している GPU が存在し UEFI をサポートしていると書かれていれば、問題ありません。2012年以降の GPU はサポートされているはずです。Windows 8 との互換性があると売り出すには UEFI のサポートが要件だと Microsoft が決めたためです。 |
** [https://www.techpowerup.com/vgabios/ このリストに載っている ROM] に使用している GPU が存在し UEFI をサポートしていると書かれていれば、問題ありません。2012年以降の GPU はサポートされているはずです。Windows 8 との互換性があると売り出すには UEFI のサポートが要件だと Microsoft が決めたためです。 |
||
19行目: | 27行目: | ||
==IOMMU のセットアップ== |
==IOMMU のセットアップ== |
||
+ | {{Note| |
||
− | IOMMU はシステム固有の IO マッピング機構でほとんどのデバイスで使用することができます。IOMMU は Intel の VT-x/Intel と AMD の AMD-V/AMD-Vi で共通して使われる名前です。 |
||
+ | * IOMMU は Intel VT-d と AMD-Vi の総称です。 |
||
+ | * VT-d は ''ダイレクト I/O 向けインテル VT'' (''Intel Virtualization Technology for Directed I/O'') の略語です。''インテル バーチャライゼーション・テクノロジー'' (''Intel Virtualization Technology'') の VT-x と混同しないようにしてください。 VT-x は単独のハードウェアプラットフォームを複数の「仮想」プラットフォームとして機能することを可能にする機能で、対して VT-d はシステムのセキュリティと信頼性を向上させると共に仮想化環境での I/O デバイスのパフォーマンスを向上させる機能です。 |
||
+ | }} |
||
+ | |||
+ | IOMMU によって PCI パススルーや障害または悪意あるデバイスからのメモリ保護機能を使うことができます。[[Wikipedia:Input-output memory management unit#Advantages]] や [https://www.quora.com/Memory-Management-computer-programming/Could-you-explain-IOMMU-in-plain-English Memory Management (computer programming): Could you explain IOMMU in plain English?] を参照してください。 |
||
+ | |||
===IOMMU の有効化=== |
===IOMMU の有効化=== |
||
− | BIOS の設定で AMD-VI/VT-d |
+ | AMD-Vi/Intel VT-d が CPU によってサポートされていること、BIOS の設定で AMD-VI/VT-d が有効化されていることを確認してください。通常は他の CPU 機能と一緒に設定が並んでいるはずです (オーバークロック関連のメニューに存在することもあります)。設定における名前は機能名 ("Vt-d" あるいは "AMD-Vi") だったり、あるいは "Virtualization technology" などの曖昧な単語だったりします。マニュアルに載っていない場合もあります。 |
+ | |||
+ | 使用している CPU に応じて適切な[[カーネルパラメータ]]を設定し、 IOMMU を有効にしてください: |
||
+ | * Intel 製の CPU (VT-d) であれば {{ic|1=intel_iommu=on}} を設定 |
||
− | また、[[カーネルパラメータ|ブートローダーのカーネルオプション]]でカーネル内の IOMMU のサポートも有効にする必要があります。使用している CPU のタイプにあわせて、Intel 製の CPU (VT-d) であれば {{ic|intel_iommu<nowiki>=</nowiki>on}} を、AMD 製の CPU (AMD-Vi) であれば {{ic|amd_iommu<nowiki>=</nowiki>on}} を使用してください。 |
||
+ | * AMD 製の CPU (AMD-Vi) ではカーネルが BIOS から IOMMU のサポートを検出し、自動で有効化されます |
||
+ | {{ic|1=iommu=pt}} パラメータも追加してください。このパラメータによって Linux がパススルーしないデバイスに触らないようにすることができます。 |
||
再起動して、dmesg で IOMMU が有効になっていることを確認してください: |
再起動して、dmesg で IOMMU が有効になっていることを確認してください: |
||
73行目: | 91行目: | ||
IOMMU Group 1 01:00.1 Audio device: NVIDIA Corporation Device 0fbc (rev a1) |
IOMMU Group 1 01:00.1 Audio device: NVIDIA Corporation Device 0fbc (rev a1) |
||
− | 上記のようにゲスト GPU しか含まれていない場合は問題ありません。他の PCIe スロットに接続した場合や CPU や PCH の配置によって、同じグループに他のデバイスが含まれる場合、そのデバイスも一緒にパススルーすることになります。仮想マシンにデバイスをパススルーしても問題ない場合は次に進んでください。そうでない場合、他の PCIe スロットに GPU を接続してみて他のデバイスと分離できないか試してみてください。もしくは ACS 上書きパッチをインストールする方法もありますが、こちらは欠点があります。 |
+ | 上記のようにゲスト GPU しか含まれていない場合は問題ありません。他の PCIe スロットに接続した場合や CPU や PCH の配置によって、同じグループに他のデバイスが含まれる場合、そのデバイスも一緒にパススルーすることになります。仮想マシンにデバイスをパススルーしても問題ない場合は次に進んでください。そうでない場合、他の PCIe スロットに GPU を接続してみて他のデバイスと分離できないか試してみてください。もしくは ACS 上書きパッチをインストールする方法もありますが、こちらは欠点があります。詳しくは [[#IOMMU グループのバイパス (ACS 上書きパッチ)]] を参照してください。 |
+ | {{note|他のデバイスと一緒にグループ化した場合、起動時に pci のルートポートとブリッジを vfio に紐付けたり VM に追加してはいけません。}} |
||
− | {{note|If they are grouped with other devices in this manner, pci root ports and bridges should neither be bound to vfio at boot, nor be added to the VM.}} |
||
==GPU の分離== |
==GPU の分離== |
||
+ | デバイスを仮想マシンに割り当てるには、ホストマシンとの干渉を避けるためにこのデバイスと同じ IOMMU グループを共有する全てのデバイスがスタブドライバまたは VFIO ドライバに置き換えられている必要があります。この処理はほとんどのデバイスでは VM が起動する直前に行われます。 |
||
− | GPU ドライバーは巨大で複雑なため、動的な再バインドはあまりサポートされておらず、ホストの GPU を透過的に仮想マシンにパススルーすることは通常できません。代わりのドライバーに GPU をバインドすることを推奨します。他のドライバーが GPU を使用できないようにして、仮想マシンが動作していないときは GPU は強制的に活動を停止します。2つの方法が存在しますが、使用しているカーネルがサポートしている場合は vfio-pci を使用することが推奨されます。 |
||
+ | しかし、GPU ドライバーは巨大で複雑なため、動的な再バインドはあまりサポートされておらず、ホストの GPU を仮想マシンにお互いのドライバーが衝突すること無く透過的にパススルーすることは通常できません。 VM が起動する前に代わりのドライバーに GPU を手動でバインドし、他のドライバーが GPU を使用できないようにすることを推奨します。 |
||
− | {{warning|Once you reboot after this procedure, whatever GPU you have configured will no longer be usable on the host until you reverse the manipulation. Make sure the GPU you intend to use on the host is properly configured before doing this.}} |
||
+ | 続くセクションでは、代わりのドライバーがブートプロセスの早期にバインドされるように GPU を構成する詳細な方法を記載します。これにより VM が要求するかドライバーがスイッチバックされるまでデバイスは活動を停止します。これは一旦システムが完全にオンラインになってからドライバを切り替えるよりも問題が少なく、好ましい方法と言えます。2つの方法が存在しますが、使用しているカーネルがサポートしている場合は vfio-pci を使用することが推奨されます。 |
||
− | ===vfio-pci を使う=== |
||
− | Linux 4.1 から、カーネルには vfio-pci が含まれており、pci-stub と同じような機能を持ちながら、使用していないときはデバイスを D3 状態にするなどの機能が追加されています。あなたのシステムが vfio-pci をサポートしている場合、以下のコマンドを実行してみてください。エラーが返ってくる場合、代わりに pci-stub を使用する方法を使ってください。 |
||
+ | {{warning|設定後にマシンを再起動すると、設定を解除しないかぎりホストから GPU は使えなくなります。再起動する前にホストで使用する GPU が正しく (マザーボードがホスト GPU を使って表示するように) 設定されているか確認してください。}} |
||
− | {{hc|$ modinfo vfio-pci| |
||
+ | |||
− | filename: /lib/modules/4.4.5-1-ARCH/kernel/drivers/vfio/pci/vfio-pci.ko.gz |
||
+ | Linux 4.1 から、カーネルには vfio-pci が含まれており、pci-stub と同じような機能を持ちながら、使用していないときはデバイスを D3 状態にするなどの機能が追加されています。 |
||
− | description: VFIO PCI - User Level meta-driver |
||
− | author: Alex Williamson <alex.williamson@redhat.com> |
||
− | ...}} |
||
vfio-pci は基本的に PCI デバイスを ID で指定するため、パススルーしたいデバイスの ID を指定する必要があります。以下の IOMMU グループの場合、vfio-pci を {{ic|10de:13c2}} と {{ic|10de:0fbb}} にバインドします。 |
vfio-pci は基本的に PCI デバイスを ID で指定するため、パススルーしたいデバイスの ID を指定する必要があります。以下の IOMMU グループの場合、vfio-pci を {{ic|10de:13c2}} と {{ic|10de:0fbb}} にバインドします。 |
||
96行目: | 111行目: | ||
IOMMU Group 13 06:00.1 Audio device: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1)}} |
IOMMU Group 13 06:00.1 Audio device: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1)}} |
||
+ | {{note| |
||
− | {{note|ホスト GPU とゲスト GPU のベンダーとデバイス ID が同じ場合 (同じ型番の GPU を使っている場合)、ベンダーとデバイス ID を使ってデバイスを分離させることはできません。そのような場合は[[#ゲストとホストで同じ GPU を使う|ゲストとホストで同じ GPU を使う]]のセクションを読んでください。}} |
||
+ | * ホスト GPU とゲスト GPU のベンダーとデバイス ID が同じ場合 (同じ型番の GPU を使っている場合)、ベンダーとデバイス ID を使ってデバイスを分離させることはできません。そのような場合は[[#ゲストとホストで同じ GPU を使う|ゲストとホストで同じ GPU を使う]]のセクションを読んでください。 |
||
+ | * [[#独立していない CPU ベースの PCIe スロットにゲスト GPU を接続した場合]]にあるように、PCI のルートポートが IOMMU グループに属している場合、ID を {{ic|vfio-pci}} に指定してはいけません。ルートポートを機能させるにはホスト側に割り当てたままにする必要があります。グループ内の他のデバイスも {{ic|vfio-pci}} にバインドされてしまいます。}} |
||
+ | |||
+ | === モジュールとして vfio-pci をロード === |
||
+ | |||
+ | {{Pkg|linux}} カーネルには組み込みモジュールとして vfio-pci が含まれていないため、設定でロードさせる必要があります。 |
||
ベンダーとデバイス ID を vfio-pci に渡されるデフォルトパラメータに追加します: |
ベンダーとデバイス ID を vfio-pci に渡されるデフォルトパラメータに追加します: |
||
{{hc|1=/etc/modprobe.d/vfio.conf|2=options vfio-pci ids=10de:13c2,10de:0fbb}} |
{{hc|1=/etc/modprobe.d/vfio.conf|2=options vfio-pci ids=10de:13c2,10de:0fbb}} |
||
− | {{note|[[#独立していない CPU ベースの PCIe スロットにゲスト GPU を接続した場合|こちら]]にあるように、PCI のルートポートが IOMMU グループに属している場合、ID を {{ic|vfio-pci}} に指定してはいけません。ルートポートを機能させるにはホスト側に割り当てたままにする必要があります。グループ内の他のデバイスも {{ic|vfio-pci}} にバインドされてしまいます。}} |
||
− | 上記の設定だけでは vfio-pci が他のグラフィックドライバーよりも前にロードされるとは限りません。必ずロードされるようにするには、 |
+ | 上記の設定だけでは vfio-pci が他のグラフィックドライバーよりも前にロードされるとは限りません。必ずロードされるようにするには、カーネルイメージの中で静的にバインドされるようにする必要があります。{{ic|vfio_pci}}, {{ic|vfio}}, {{ic|vfio_iommu_type1}}, {{ic|vfio_virqfd}} を [[mkinitcpio]] にこの順番で追加してください: |
− | {{note|[[Kernel_Mode_Setting#Early_KMS_start|初期モードセッティング]]のために他のドライバー ("nouveau", "radeon", "amdgpu", "i915" など) をロードしている場合、以下の VFIO モジュールが先にロードされるようにしてください。}} |
||
− | {{hc|1=/etc/mkinitcpio.conf|2=MODULES="... vfio vfio_iommu_type1 vfio_pci vfio_virqfd ..."}} |
||
+ | {{hc|/etc/mkinitcpio.conf|2= |
||
− | さらに、{{ic|mkinitcpio.conf}} の HOOKS リストに {{ic|modconf}} フックを追加してください: |
||
+ | MODULES=(... vfio_pci vfio vfio_iommu_type1 vfio_virqfd ...) |
||
+ | }} |
||
+ | {{Note|[[カーネルモード設定#KMS の早期開始|初期モードセッティング]]のために他のドライバー ({{ic|nouveau}}, {{ic|radeon}}, {{ic|amdgpu}}, {{ic|i915}} など) をロードしている場合、上記の VFIO モジュールが先にロードされるようにしてください。}} |
||
− | {{hc|1=/etc/mkinitcpio.conf|2=HOOKS="... modconf ..."}} |
||
+ | さらに、{{ic|mkinitcpio.conf}} の HOOKS リストに modconf フックを追加してください: |
||
− | 新しいモジュールを initramfs に追加したら、initramfs を再生成する必要があります。{{ic|/etc/modprobe.d/vfio.conf}} でデバイスの ID を変更した場合も、initramfs を再生成してください。パラメータは起動の初期段階で initramfs で指定される必要があります。 |
||
+ | |||
− | # mkinitcpio -p linux |
||
+ | {{hc|/etc/mkinitcpio.conf|2= |
||
− | {{Note|{{ic|linux-vfio}} など非標準のカーネルを使っている場合、{{ic|linux}} を適当なカーネルに置き換えてください。}} |
||
+ | HOOKS=(... modconf ...) |
||
+ | }} |
||
+ | |||
+ | 新しいモジュールを initramfs に追加したら、[[initramfs を再生成する]]必要があります。{{ic|/etc/modprobe.d/vfio.conf}} でデバイスの ID を変更した場合も、initramfs を再生成してください。パラメータは起動の初期段階で initramfs で指定される必要があります。 |
||
+ | |||
+ | === カーネルに vfio-pci が組み込まれている場合 === |
||
+ | |||
+ | vfio-pci モジュールを組み込んだカーネルを使っている場合、以下のように[[カーネルパラメータ]]でデバイス ID を指定することで GPU を分離できます: |
||
+ | |||
+ | vfio-pci.ids=10de:13c2,10de:0fbb |
||
+ | |||
+ | === 設定を確認 === |
||
再起動して vfio-pci が正しくロードされ適切なデバイスがバインドされていることを確認: |
再起動して vfio-pci が正しくロードされ適切なデバイスがバインドされていることを確認: |
||
+ | |||
− | {{hc|$ dmesg <nowiki>|</nowiki> grep -i vfio | |
||
+ | {{hc|$ dmesg {{!}} grep -i vfio| |
||
[ 0.329224] VFIO - User Level meta-driver version: 0.3 |
[ 0.329224] VFIO - User Level meta-driver version: 0.3 |
||
[ 0.341372] vfio_pci: add [10de:13c2[ffff:ffff]] class 0x000000/00000000 |
[ 0.341372] vfio_pci: add [10de:13c2[ffff:ffff]] class 0x000000/00000000 |
||
[ 0.354704] vfio_pci: add [10de:0fbb[ffff:ffff]] class 0x000000/00000000 |
[ 0.354704] vfio_pci: add [10de:0fbb[ffff:ffff]] class 0x000000/00000000 |
||
− | [ 2.061326] vfio-pci 0000:06:00.0: enabling device (0100 -> 0103) |
+ | [ 2.061326] vfio-pci 0000:06:00.0: enabling device (0100 -> 0103) |
+ | }} |
||
− | {{ic|vfio.conf}} の全てのデバイスが dmesg に出力される必要はありません。起動時にデバイスが出力に現れなくてもゲスト VM から問題なく使うことができます。 |
+ | {{ic|vfio.conf}} の全てのデバイス (期待するデバイスであっても) が dmesg に出力される必要はありません。起動時にデバイスが出力に現れなくてもゲスト VM から問題なく使うことができます。 |
{{hc|$ lspci -nnk -d 10de:13c2| |
{{hc|$ lspci -nnk -d 10de:13c2| |
||
133行目: | 167行目: | ||
Kernel modules: snd_hda_intel}} |
Kernel modules: snd_hda_intel}} |
||
+ | ==OVMF によるゲスト VM のセットアップ== |
||
− | ===pci-stub を使う (古い方法, 4.1 カーネル以前)=== |
||
+ | OVMF は QEMU 仮想マシン用のオープンソース UEFI ファームウェアです。SeaBIOS を使うことでも PCI パススルーと同じような結果を得ることはできますが、セットアップ手順が異なります。一般的にはハードウェアがサポートしているのであれば EFI を使用する方法を推奨します。 |
||
− | 使用しているカーネルが vfio-pci をサポートしていない場合、代わりに pci-stub モジュールを使います。 |
||
+ | ===libvirt の設定=== |
||
− | pci-stub は基本的に PCI デバイスを ID で指定するため、パススルーしたいデバイスの ID を指定する必要があります。以下の IOMMU グループの場合、pci-stub を {{ic|10de:13c2}} と {{ic|10de:0fbb}} にバインドします: |
||
+ | [[libvirt]] は様々な仮想化ユーティリティのラッパーであり、仮想マシンの設定とデプロイを簡単にします。KVM と QEMU の場合、フロントエンドを使用することで QEMU 用にパーミッションを設定する必要がなくなり簡単に様々なデバイスを仮想マシンに追加・削除できます。ラッパーと名乗ってはいますが、QEMU の最新機能全てをサポートしているわけではありません。QEMU の引数を追加するためにラッパースクリプトを使用する必要がある場合もあります。 |
||
+ | {{Pkg|qemu}}, {{Pkg|libvirt}}, {{Pkg|ovmf}}{{Broken package link|置換パッケージ: {{Pkg|edk2-ovmf}}}}, {{Pkg|virt-manager}} をインストールしてから、OVMF ファームウェアイメージとランタイム変数テンプレートのパスを libvirt の設定に追加して、{{ic|virt-install}} や {{ic|virt-manager}} が認識できるようにしてください: |
||
− | IOMMU group 13 06:00.0 VGA compatible controller: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1) |
||
− | IOMMU group 13 06:00.1 Audio device: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1)}} |
||
+ | {{hc|/etc/libvirt/qemu.conf|2= |
||
− | {{note|ホスト GPU とゲスト GPU のベンダーとデバイス ID が同じ場合 (同じ型番の GPU を使っている場合)、ベンダーとデバイス ID を使ってデバイスを分離させることはできません。そのような場合は[[#ゲストとホストで同じ GPU を使う|ゲストとホストで同じ GPU を使う]]のセクションを読んでください。}} |
||
+ | nvram = [ |
||
− | (Arch Linux を含む) ほとんどの Linux ディストリはカーネルイメージの中に静的に pci-stub を組み込んでいます。何らかの理由でモジュールとしてロードしなければならない場合、ディストリが提供しているツールを使用してバインドする必要があります。Arch の場合は {{ic|mkinitpcio}} です: |
||
+ | "/usr/share/ovmf/x64/OVMF_CODE.fd:/usr/share/ovmf/x64/OVMF_VARS.fd" |
||
− | {{hc|<nowiki>/etc/mkinitcpio.conf</nowiki>|<nowiki>MODULES="... pci-stub ..."</nowiki>}} |
||
+ | ] |
||
+ | }} |
||
+ | 設定後、{{ic|libvirtd.service}} とログ出力コンポーネント {{ic|virtlogd.socket}} を[[起動]]・[[有効化]]します。 |
||
− | 手動でカーネルイメージにモジュールを追加する必要がある場合、initramfs を再生成してください: |
||
− | # mkinitcpio -p linux |
||
− | {{Note|{{ic|linux-vfio}} など非標準のカーネルを使っている場合、{{ic|linux}} を使用しているカーネルに置き換えてください。}} |
||
+ | ===ゲスト OS のセットアップ=== |
||
− | カーネルコマンドラインにパススルーする PCI デバイスの ID を追加: |
||
+ | {{ic|virt-manager}} による仮想マシンの設定は画面上の指示に従うだけで完了します。ただし、以下のステップでは特別な注意を払う必要があります: |
||
− | {{hc|<nowiki>/etc/mkinitcpio.conf</nowiki>|<nowiki>... |
||
+ | * 仮想マシンの作成ウィザードで VM の名前を付けるとき、"Customize before install" チェックボックスにチェックを入れてください。 |
||
− | GRUB_CMDLINE_LINUX_DEFAULT="... pci-stub.ids=10de:13c2,10de:0fbb ..." |
||
+ | * "Overview" セクションで、ファームウェアを "UEFI" に設定してください [https://i.imgur.com/73r2ctM.png]。オプションがグレーになっている場合、{{ic|/etc/libvirt/qemu.conf}} でファームウェアの場所が正しく指定されているか確認してください。修正した後 {{ic|libvirtd.service}} を再起動してください。 |
||
− | ...</nowiki>}} |
||
+ | * "CPUs" セクションで、CPU モデルを "host-passthrough" に変更してください。リストに存在しない場合、手動で入力してください。これで libvirt が CPU の機能を実際の CPU と同じように反映するようになって CPU が正しく認識されるようになります。変更しないと、一部のアプリケーションで CPU のモデルが不明だとエラーが発生します。 |
||
− | {{note|[[#独立していない CPU ベースの PCIe スロットにゲスト GPU を接続した場合|こちら]]にあるように、PCI のルートポートが IOMMU グループに属している場合、ID を {{ic|pci-stub}} に指定してはいけません。ルートポートを機能させるにはホスト側に割り当てたままにする必要があります。グループ内の他のデバイスも {{ic|pci-stub}} にバインドされてしまいます。}} |
||
+ | * IO のオーバーヘッドを抑えたい場合、"Add Hardware" から "VirtIO SCSI" モデルの SCSI ドライブのコントローラを追加してください。それからデフォルトの IDE ディスクを SCSI ディスクに変更して作成したコントローラーにバインドしてください。 |
||
+ | ** Windows の仮想マシンはデフォルトでは SCSI ドライブを認識しないため、[https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/ こちら] からドライバーが含まれている ISO をダウンロードして IDE (あるいは Windows 7 以上の場合は SATA) の CD-ROM ストレージデバイスを作成してダウンロードした ISO にリンクしてください。この設定を行わないとインストール時に Windows がディスクを認識できません。Windows をインストールするディスクを選択するときは、''vioscsi'' 下の CD-ROM に含まれているドライバーをロードしてください。 |
||
+ | 他のインストールは通常と同じです。標準の QXL ビデオアダプタをウィンドウで実行します。現時点では、仮想デバイスのためのドライバーをインストールする必要はありません。ほとんどが後で削除されるためです。ゲスト OS のインストールが完了したら、仮想マシンをオフにしてください。最初の VM 起動時にインストールが始まらず UEFI メニューに戻ってしまう場合があります。場合によっては正しい ISO ファイルが自動的に認識されないために、起動ドライブを手動で指定する必要があります。 exit とタイプして "boot manager" に移動するとデバイス選択メニューに入ることができます。 |
||
− | GRUB の設定をリロード: |
||
− | # grub-mkconfig -o /boot/grub/grub.cfg |
||
+ | ===PCI デバイスの接続=== |
||
− | デバイスが pci-stub に割り当てられたことを dmesg の出力で確認: |
||
+ | インストールが完了したら、libvirt でハードウェアの詳細情報を編集して spice チャンネルや仮想ディスプレイ、QXL ビデオアダプタ、マウスやキーボード、USB タブレットデバイスのエミュレートなどの仮想デバイスを削除できます。入力デバイスがなくなるので、仮想マシンに USB ホストデバイスをバインドする場合、ゲストに何かあったときは最低でもひとつのマウスやキーボードをホストに割り当ててください。ここで、先に分離しておいた PCI デバイスを接続することができます。"Add Hardware" をクリックしてパススルーしたい PCI Host Device を選択してください。問題がなければ、GPU に接続されたディスプレイが OVMF のスプラッシュ画面を表示して通常通りに VM が起動します。そこから VM のドライバーの設定をおこなってください。 |
||
− | {{hc|dmesg <nowiki>|</nowiki> grep pci-stub| |
||
− | [ 2.390128] pci-stub: add 10DE:13C2 sub<nowiki>=</nowiki>FFFFFFFF:FFFFFFFF cls<nowiki>=</nowiki>00000000/00000000 |
||
− | [ 2.390143] pci-stub 0000:06:00.0: claimed by stub |
||
− | [ 2.390150] pci-stub: add 10DE:0FBB sub<nowiki>=</nowiki>FFFFFFFF:FFFFFFFF cls<nowiki>=</nowiki>00000000/00000000 |
||
− | [ 2.390159] pci-stub 0000:06:00.1: claimed by stub}} |
||
+ | === Evdev でキーボード・マウスを接続 === |
||
− | ==OVMF によるゲスト VM のセットアップ== |
||
− | OVMF は QEMU 仮想マシン用のオープンソース UEFI ファームウェアです。SeaBIOS を使うことでも PCI パススルーと同じような結果を得ることはできますが、セットアップ手順が異なります。一般的にはハードウェアがサポートしているのであれば EFI を使用する方法を推奨します。 |
||
+ | ゲスト用のスペアのマウスやキーボードを持っておらず、Spice のオーバーヘッドを避けたい場合、evdev を設定することでマウスとキーボードのコントロールをホストとゲストで切り替えることができます。まず、{{ic|/dev/input/by-id/}} からキーボードとマウスのデバイスを探してください。マウスやキーボードに複数のデバイスが関連付けられている場合、{{ic|cat /dev/input/by-id/''device_id''}} を試してみてキーを打ったりマウスを動かして入力が通ったかどうか確認してください。それからデバイスを設定に追加: |
||
− | ===libvirt の設定=== |
||
− | [[libvirt]] は様々な仮想化ユーティリティのラッパーであり、仮想マシンの設定とデプロイを簡単にします。KVM と QEMU の場合、フロントエンドを使用することで QEMU 用にパーミッションを設定する必要がなくなり簡単に様々なデバイスを仮想マシンに追加・削除できます。ラッパーと名乗ってはいますが、QEMU の最新機能全てをサポートしているわけではありません。QEMU の引数を追加するためにラッパースクリプトを使用する必要がある場合もあります。 |
||
+ | {{hc|$ virsh edit [vmname]|<nowiki> |
||
− | {{Pkg|qemu}}, {{Pkg|libvirt}}, {{AUR|ovmf-git}}, {{Pkg|virt-manager}} をインストールしてから、OVMF ファームウェアイメージとランタイム変数テンプレートのパスを libvirt の設定に追加して、{{ic|virt-install}} や {{ic|virt-manager}} が認識できるようにしてください: |
||
+ | ... |
||
+ | <qemu:commandline> |
||
+ | <qemu:arg value='-object'/> |
||
+ | <qemu:arg value='input-linux,id=mouse1,evdev=/dev/input/by-id/MOUSE_NAME'/> |
||
+ | <qemu:arg value='-object'/> |
||
+ | <qemu:arg value='input-linux,id=kbd1,evdev=/dev/input/by-id/KEYBOARD_NAME,grab_all=on,repeat=on'/> |
||
+ | </qemu:commandline> |
||
+ | ... |
||
+ | </nowiki>}} |
||
+ | {{ic|MOUSE_NAME}} と {{ic|KEYBOARD_NAME}} は適切なデバイス id に置き換えてください。それから qemu の設定にデバイスを記述して、ユーザーとグループが入力デバイスにアクセスできるように設定: |
||
− | {{hc|/etc/libvirt/qemu.conf| |
||
+ | |||
− | <nowiki>nvram = [</nowiki> |
||
+ | {{hc|/etc/libvirt/qemu.conf|<nowiki> |
||
− | "/usr/share/ovmf/x64/ovmf_x64.bin:/usr/share/ovmf/x64/ovmf_vars_x64.bin" |
||
+ | ... |
||
+ | user = "<your_user>" |
||
+ | group = "kvm" |
||
+ | ... |
||
+ | cgroup_device_acl = [ |
||
+ | "/dev/kvm", |
||
+ | "/dev/input/by-id/KEYBOARD_NAME", |
||
+ | "/dev/input/by-id/MOUSE_NAME", |
||
+ | "/dev/null", "/dev/full", "/dev/zero", |
||
+ | "/dev/random", "/dev/urandom", |
||
+ | "/dev/ptmx", "/dev/kvm", "/dev/kqemu", |
||
+ | "/dev/rtc","/dev/hpet", "/dev/sev" |
||
] |
] |
||
+ | ... |
||
− | }} |
||
+ | </nowiki>}} |
||
+ | それから使用するユーザーが {{ic|kvm}} と {{ic|input}} [[ユーザーとグループ|グループ]]にアクセスできるようにしてください。{{ic|libvirtd.service}} を再起動してください。これでゲスト OS を起動したら左と右の Control キーを両方同時に押すことでマウスとキーボードを切り替えることができます。 |
||
− | そして {{ic|libvirtd}} とログ出力コンポーネントを起動・[[有効化]]します: |
||
+ | 設定で PS/2 から Virtio の入力に切り替えることもできます: |
||
− | {{bc| |
||
− | # systemctl enable --now libvirtd |
||
− | # systemctl enable virtlogd.socket}} |
||
+ | {{hc|$ virsh edit [vmname]|<nowiki> |
||
− | ===ゲスト OS のセットアップ=== |
||
+ | ... |
||
− | The process of setting up a VM using {{ic|virt-manager}} is mostly self explainatory, as most of the process comes with fairly comprehensive on-screen instructions. However, you should pay special attention to the following steps : |
||
+ | <input type='mouse' bus='virtio'> |
||
− | * When the VM creation wizard asks you to name your VM, check the "Customize before install" checkbox. |
||
+ | <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> |
||
− | * In the "Overview" section, set your firmware to "UEFI". If the option is grayed out, make sure that you have correctly specified the location of your firmware in {{ic|/etc/libvirt/qemu.conf}} and restart {{ic|libvirtd.service}}. |
||
+ | </input> |
||
− | * In the "CPUs" section, change your CPU model to "host-passthrough". If it is not in the list, you will have to type it by hand. This will ensure that your CPU is detected properly, since it causes libvirt to expose your CPU capabilities exactly as they are instead of only those it recognizes (which is the preferred default behavior to make CPU behavior easier to reproduce). Without it, some applications may complain about your CPU being of an unknown model. |
||
+ | <input type='keyboard' bus='virtio'> |
||
− | * If you want to minimize IO overhead, go into "Add Hardware" and add a Controller for SCSI drives of the "VirtIO SCSI" model. You can then change the default IDE disk for a SCSI disk, which will bind to said controller. |
||
+ | <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> |
||
− | ** Windows VMs will not recognize those drives by default, so you need to download the ISO containing the drivers from [https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/latest-virtio/ here] and add an IDE (or SATA for Windows 8.1 and newer) CD-ROM storage device linking to said ISO, otherwise you will not be able to get Windows to recognize it during the installation process. When prompted to select a disk to install windows on, load the drivers contained on the CD-ROM under ''vioscsi''. |
||
+ | </input> |
||
+ | <input type='mouse' bus='ps2'/> |
||
+ | <input type='keyboard' bus='ps2'/> |
||
+ | ... |
||
+ | </nowiki>}} |
||
+ | ゲスト OS を起動してデバイスオン virtIO ドライバーをインストールしてください。 |
||
− | The rest of the installation process will take place as normal using a standard QXL video adapter running in a window. At this point, there is no need to install additional drivers for the rest of the virtual devices, since most of them will be removed later on. Once the guest OS is done installing, simply turn off the virtual machine. |
||
− | |||
− | ===PCI デバイスの接続=== |
||
− | With the installation done, it's now possible to edit the hardware details in libvirt and remove virtual integration devices, such as the spice channel and virtual display, the QXL video adapter, the emulated mouse and keyboard and the USB tablet device. Since that leaves you with no input devices, you may want to bind a few USB host devices to your VM as well, but remember to '''leave at least one mouse and/or keyboard assigned to your host''' in case something goes wrong with the guest. At this point, it also becomes possible to attach the PCI device that was isolated earlier; simply click on "Add Hardware" and select the PCI Host Devices you want to passthrough. If everything went well, the screen plugged into your GPU should show the OVMF splash screen and your VM should start up normally. From there, you can setup the drivers for the rest of your VM. |
||
===注意事項=== |
===注意事項=== |
||
====OVMF ベースの VM で非 EFI イメージを使う==== |
====OVMF ベースの VM で非 EFI イメージを使う==== |
||
+ | OVMF ファームウェアは EFI 以外のメディアの起動をサポートしていません。起動後に UEFI シェルが開かれてしまう場合、EFI ブートメディアに問題がある可能性があります。他の linux/windows イメージを使ってみてイメージに問題がないか確認してください。 |
||
− | The OVMF firmware does not support booting off non-EFI mediums. If the installation process drops you in a UEFI shell right after booting, you may have an invalid EFI boot media. Try using an alternate linux/windows image to determine if you have an invalid media. |
||
==パフォーマンスチューニング== |
==パフォーマンスチューニング== |
||
+ | PCI パススルーを使うのはビデオゲームや GPU を使用する作業など大抵パフォーマンスが重要な場合です。PCI パススルーによってネイティブの性能に近づきますが、仮想マシンを最大限活用するにはホストとゲスト両方で設定が必要です。 |
||
− | Most use cases for PCI passthroughs relate to performance-intensive domains such as video games and GPU-accelerated tasks. While a PCI passthrough on its own is a step towards reaching native performance, there are still a few ajustments on the host and guest to get the most out of your VM. |
||
===CPU ピニング=== |
===CPU ピニング=== |
||
+ | KVM ゲストではデフォルトでゲストから要求された操作を仮想プロセッサを表すスレッドとして実行します。スレッドは Linux のスケジューラによって他のスレッドと同じように管理され、nice 値や優先度にあわせて手隙の CPU コアに割り当てられます。スレッド切り替えにはオーバーヘッドが存在するため (コンテキストスイッチによってコアのキャッシュが強制的に変更されるため)、ゲストのパフォーマンスに悪い影響を与えます。CPU ピニングはこの問題を解決してプロセスのスケジューリングを上書きして VM のスレッドは特定のコアでのみ動作するようになります。例えば、ゲストのコア 0, 1, 2, 3 をホストの 4, 5, 6, 7 番目のコアに割り当てるには: |
||
− | The default behavior for KVM guests is to run operations coming from the guest as a number of threads representing virtual processors. Those threads are managed by the Linux scheduler like any other thread and are dispatched to any available CPU cores based on niceness and priority queues. Since switching between threads adds a bit of overhead (because context switching forces the core to change its cache between operations), this can noticeably harm performance on the guest. CPU pinning aims to resolve this as it overrides process scheduling and ensures that the VM threads will always run and only run on those specific cores. Here, for instance, the guest cores 0, 1, 2 and 3 are mapped to the host cores 5, 6, 7 and 8 respectively. |
||
− | {{hc| |
+ | {{hc|$ virsh edit [vmname]|<nowiki>... |
− | + | <vcpu placement='static'>4</vcpu> |
|
<cputune> |
<cputune> |
||
<vcpupin vcpu='0' cpuset='4'/> |
<vcpupin vcpu='0' cpuset='4'/> |
||
215行目: | 266行目: | ||
<vcpupin vcpu='2' cpuset='6'/> |
<vcpupin vcpu='2' cpuset='6'/> |
||
<vcpupin vcpu='3' cpuset='7'/> |
<vcpupin vcpu='3' cpuset='7'/> |
||
− | </cputune |
+ | </cputune> |
− | ...}} |
+ | ...</nowiki>}} |
====ハイパースレッディングの場合==== |
====ハイパースレッディングの場合==== |
||
+ | CPU がハードウェアによるマルチタスクをサポートしている場合 (Intel のチップではハイパースレッディングと呼ばれます)、CPU ピニングをする方法は2つ存在します。ハイパースレッディングは1つの CPU で2つのスレッドを効率的に動作させる手法であるため、クアッドコア CPU ならば8つの論理コアが使えます。物理コアの負担率が高い場合、論理コアは使われません。VM のスレッドを2つの物理コアに割り当てても、2つのコアが対応できる負担を超える作業では2つの論理コアの補助を得ることができません。4つのコアのうち2つのコアをパススルーしただけだからです。 |
||
− | If your CPU supports hardware multitasking, also known as Hyper-threading on Intel chips, there are two ways you can go with your CPU pinning. That is, Hyper-threading is simply a very efficient way of running two threads on one CPU at any given time, so while it may give you 8 logical cores on what would otherwise be a quad-core CPU, if the physical core is overloaded, the logical core won't be of any use. One could pin their VM threads on 2 physical cores and their 2 respective threads, but any task overloading those two cores won't be helped by the extra two logical cores, since in the end you're only passing through two cores out of four, not four out of eight. What you should do knowing this depends on what you intend to do with your host while your VM is running. |
||
+ | 以下はクアッドコアのマシンでハイパースレッディングが有効になっている場合の {{ic|/proc/cpuinfo}} の要約です: |
||
− | This is the abridged content of {{ic|/proc/cpuinfo}} on a quad-core machine with hyper-threading. |
||
− | {{hc| |
+ | {{hc|$ grep -e "processor" -e "core id" -e "^$" /proc/cpuinfo| |
processor : 0 |
processor : 0 |
||
core id : 0 |
core id : 0 |
||
247行目: | 298行目: | ||
core id : 3}} |
core id : 3}} |
||
+ | 仮想マシンを使っているときにホスト側で負担が重い計算をしない場合 (あるいはホストを全く使わない場合)、仮想マシンのスレッドを全ての論理コアに固定化して、仮想マシンがコアを活用できるようにすると良いでしょう。 |
||
− | If you don't intend to be doing any computation-heavy work on the host (or even anything at all) at the same time as you would on the VM, it would probably be better to pin your VM threads across all of your logical cores, so that the VM can fully take advantage of the spare CPU time on all your cores. |
||
+ | クアッドコアのマシンの場合、以下のようになります: |
||
− | On the quad-core machine mentioned above, it would look like this : |
||
− | {{hc| |
+ | {{hc|$ virsh edit [vmname]|<nowiki>... |
− | + | <vcpu placement='static'>4</vcpu> |
|
<cputune> |
<cputune> |
||
<vcpupin vcpu='0' cpuset='4'/> |
<vcpupin vcpu='0' cpuset='4'/> |
||
263行目: | 314行目: | ||
<topology sockets='1' cores='4' threads='1'/> |
<topology sockets='1' cores='4' threads='1'/> |
||
... |
... |
||
− | </cpu |
+ | </cpu> |
− | ...}} |
+ | ...</nowiki>}} |
+ | ホストとゲストで同時に何か処理を行う場合、一部の物理コアとゲストのスレッドを固定して、後はホストでも使えるようにすると良いでしょう。 |
||
− | If you would instead prefer to have the host and guest running intensive tasks at the same time, it would then be preferable to pin a limited amount of physical cores and their respective threads on the guest and leave the rest to the host to avoid the two competing for CPU time. |
||
+ | クアッドコアのマシンの場合、以下のようになります: |
||
− | On the quad-core machine mentioned above, it would look like this : |
||
− | {{hc| |
+ | {{hc|$ virsh edit [vmname]|<nowiki>... |
− | + | <vcpu placement='static'>4</vcpu> |
|
<cputune> |
<cputune> |
||
<vcpupin vcpu='0' cpuset='2'/> |
<vcpupin vcpu='0' cpuset='2'/> |
||
− | <vcpupin vcpu='1' cpuset=' |
+ | <vcpupin vcpu='1' cpuset='6'/> |
− | <vcpupin vcpu='2' cpuset=' |
+ | <vcpupin vcpu='2' cpuset='3'/> |
<vcpupin vcpu='3' cpuset='7'/> |
<vcpupin vcpu='3' cpuset='7'/> |
||
</cputune> |
</cputune> |
||
282行目: | 333行目: | ||
<topology sockets='1' cores='2' threads='2'/> |
<topology sockets='1' cores='2' threads='2'/> |
||
... |
... |
||
− | </cpu |
+ | </cpu> |
− | ...}} |
+ | ...</nowiki>}} |
===静的ヒュージページ=== |
===静的ヒュージページ=== |
||
+ | 大量のメモリを必要するアプリケーションでは、メモリの遅延が問題になることがあります。使用するメモリページ (メモリ割り当ての基本単位) が増えれば増えるほど、複数のメモリページにまたがる情報にアプリケーションがアクセスするようになる確立が高まります。メモリページの実際のアドレスを解決するには複数のステップを踏まないとならないため、大抵の場合 CPU は最近使用されたメモリページの情報をキャッシュすることで同一ページの使用を高速化します。しかしながらアプリケーションが大量のメモリを使うとすると問題です。例えば仮想マシンが使用する 4GB のメモリが (メモリページのデフォルトサイズである) 4kB に分割されるような場合、頻繁にキャッシュミスが発生することになりメモリの遅延を増大させてしまいます。このような問題を緩和するためにヒュージページが存在します。大きなサイズのページをアプリケーションに割り当てることで、同一ページが使用される可能性を高めます。通常は必要に応じてヒュージページを動的に管理する、透過的ヒュージページが使用されます。 |
||
− | When dealing with applications that require large amounts of memory, memory latency can become a problem since the more memory pages are being used, the more likely it is that this application will attempt to access information accross multiple memory "pages", which is the base unit for memory allocation. Resolving the actual address of the memory page takes multiple steps, and so CPUs normally cache information on recently used memory pages to make subsequent uses on the same pages faster. Applications using large amounts of memory run into a problem where, for instance, a virtual machine uses 4GB of memory divided into 4kB pages (which is the default size for normal pages), meaning that such cache misses can become extremely frequent and greatly increase memory latency. Huge pages exist to mitigate this issue by giving larger individual pages to those applications, increasing the odds that multiple operations will target the same page in succession. This is normally handeled with transparent huge pages, which dynamically manages hugepages to keep up with the demand. |
||
+ | しかしながら仮想マシンで PCI パススルーを使う場合は透過ヒュージページは意味がありません。IOMMU がゲストのメモリ割り当てを必要とし仮想マシンが起動するとすぐに固定化されるためです。したがってヒュージページの効果を得るには静的に割り当てる必要があります。 |
||
− | On a VM with a PCI passthrough, however, it is '''not possible''' to benefit from transparent huge pages, as IOMMU requires that the guest's memory be allocated and pinned as soon as the VM starts. It is therefore required to allocate huge pages statically in order to benefit from them. |
||
+ | {{warning|静的ヒュージページは割り当てられたメモリをロックダウンするため、普通のアプリケーションはそれらのメモリを使用できなくなります。8GB のメモリが搭載されたマシンでヒュージページに 4GB を割り当てると、ホストで使用できるメモリは 4GB だけになります。たとえ VM が実行中でなくてもそれは変わりません。}} |
||
− | {{warning|Do note that static huge pages lock down the allocated amount of memory, making it unavailable for applications that are not configured to use them. Allocating 4GBs worth of huge pages on a machine with 8GBs of memory will only leave you with 4GBs of available memory on the host '''even when the VM is not running'''.}} |
||
+ | 起動時にヒュージページを割り当てるには、カーネルコマンドラインで {{ic|<nowiki>hugepages=x</nowiki>}} を使って適切な量を指定します。例えば {{ic|<nowiki>hugepages=1024</nowiki>}} として1024ページを予約すると、ヒュージページあたりデフォルトで 2048kB のサイズが割り当てられるため、仮想マシンが使用するための 2GB 分のメモリが作成されます。 |
||
− | To allocate huge pages at boot, one must simply specify the desired amount on their kernel comand line with {{ic|<nowiki>hugepages=x</nowiki>}}. For instance, reserving 1024 pages with {{ic|<nowiki>hugepages=1024</nowiki>}} and the default size of 2048kB per huge page creates 2GBs worth of memory for the virtual machine to use. |
||
+ | CPU がサポートしていれば手動でページサイズを設定できます。{{ic|<nowiki>grep pdpe1gb /proc/cpuinfo</nowiki>}} を実行することで 1 GB のヒュージページがサポートされているか確認できます。カーネルパラメータで 1 GB のヒュージページサイズを設定するには: {{ic|<nowiki>default_hugepagesz=1G hugepagesz=1G hugepages=X transparent_hugepage=never</nowiki>}}。 |
||
− | Also, since static huge pages can only be used by applications that specifically request it, you must add this section in your libvirt domain configuration to allow kvm to benefit from them : |
||
+ | |||
− | {{hc|<nowiki>EDITOR=nano virsh edit myPciPassthroughVm</nowiki>|... |
||
+ | また、静的ヒュージページは要求を行ったアプリケーションだけが使用できるため、libvirt のドメイン設定に kvm が割り当てたヒュージページを活用するように設定を追加する必要があります: |
||
+ | {{hc|$ virsh edit [vmname]|<nowiki>... |
||
<memoryBacking> |
<memoryBacking> |
||
<hugepages/> |
<hugepages/> |
||
</memoryBacking> |
</memoryBacking> |
||
− | ...}} |
+ | ...</nowiki>}} |
=== CPU 周波数ガバナー === |
=== CPU 周波数ガバナー === |
||
[[CPU 周波数スケーリング|CPU ガバナー]]の設定によっては、仮想マシンのスレッドによって周波数が引き上がる閾値まで CPU の負担が達しないことがあります。KVM が自力で CPU の周波数を変更することはできないため、CPU の使用率が思うように上がらないとパフォーマンスが出ないという問題になる可能性があります。ゲスト側で CPU 負担が重い作業を実行している間に {{ic|watch lscpu}} によって報告される周波数に変化があるかどうか確認してみてください。周波数が最大値まで上がらない場合、[https://lime-technology.com/forum/index.php?topic=46664.msg447678#msg447678 CPU スケーリングがホスト OS によって制御されている] ことが原因かもしれません。その場合、全てのコアを最大周波数に設定してみてパフォーマンスが改善しないか確認してください。最新の Intel 製チップをデフォルトの P-State ドライバーで使用している場合、cpupower コマンドは[[CPU 周波数スケーリング#CPU 周波数ドライバー|効果がない]]ため、{{ic|/proc/cpuinfo}} を監視して CPU が最大周波数になっていることを確認してください。 |
[[CPU 周波数スケーリング|CPU ガバナー]]の設定によっては、仮想マシンのスレッドによって周波数が引き上がる閾値まで CPU の負担が達しないことがあります。KVM が自力で CPU の周波数を変更することはできないため、CPU の使用率が思うように上がらないとパフォーマンスが出ないという問題になる可能性があります。ゲスト側で CPU 負担が重い作業を実行している間に {{ic|watch lscpu}} によって報告される周波数に変化があるかどうか確認してみてください。周波数が最大値まで上がらない場合、[https://lime-technology.com/forum/index.php?topic=46664.msg447678#msg447678 CPU スケーリングがホスト OS によって制御されている] ことが原因かもしれません。その場合、全てのコアを最大周波数に設定してみてパフォーマンスが改善しないか確認してください。最新の Intel 製チップをデフォルトの P-State ドライバーで使用している場合、cpupower コマンドは[[CPU 周波数スケーリング#CPU 周波数ドライバー|効果がない]]ため、{{ic|/proc/cpuinfo}} を監視して CPU が最大周波数になっていることを確認してください。 |
||
+ | |||
+ | === AMD CPU でパフォーマンスを改善する === |
||
+ | |||
+ | 以前は AMD 環境では Nested Page Tables (NPT) を無効化することで KVM の GPU 性能を引き上げることができました。これは [https://sourceforge.net/p/kvm/bugs/230/ 非常に古いバグ] が原因で、トレードオフとして CPU の性能が落ちて、がたつきが発生することがありました。 |
||
+ | |||
+ | カーネル 4.14 と 4.9 から問題を解決する [https://patchwork.kernel.org/patch/10027525/ カーネルパッチ] がマージされています。公式の {{Pkg|linux}} または {{Pkg|linux-lts}} カーネルを使用している場合、パッチは既に適用されています (最新版のカーネルを使っていることを確認してください)。他のカーネルを使っている場合は手動でパッチを適用する必要があります。 |
||
+ | |||
+ | {{Note|一部の Ryzen ユーザーによって上記パッチがテストされており、問題なく動作し GPU パススルーの性能がほとんどネイティブのレベルまで向上することが確認されています ([https://www.reddit.com/r/VFIO/comments/78i3jx/possible_fix_for_the_npt_issue_discussed_on_iommu/ こちらの Reddit スレッド] を参照)。}} |
||
+ | |||
+ | QEMU 3.1 から TOPOEXT cpuid フラグはデフォルトで無効になっています。AMD の CPU でハイパースレッディングを使うには手動で有効にする必要があります: |
||
+ | |||
+ | <cpu mode='host-passthrough' check='none'> |
||
+ | <topology sockets='1' cores='4' threads='2'/> |
||
+ | <feature policy='require' name='topoext'/> |
||
+ | </cpu> |
||
+ | |||
+ | コミット: https://git.qemu.org/?p=qemu.git;a=commit;h=7210a02c58572b2686a3a8d610c6628f87864aed |
||
== 特殊な構成 == |
== 特殊な構成 == |
||
+ | 特定の構成では特別な設定が必要になります。ホストあるいは VM が正しく動作しない場合、あなたのシステムが以下のどれかにあてはまっていないか確認してください。 |
||
− | Certain setups require specific configuration tweaks in order to work properly. If you're having problems getting your host or your VM to work properly, see if your system matches one of the cases below and try adjusting your configuration accordingly. |
||
=== ゲストとホストで同じ GPU を使う === |
=== ゲストとホストで同じ GPU を使う === |
||
+ | pci-stub と vfio-pci はどちらもベンダー・デバイス id の組み合わせを使って起動時にバインドするデバイスを認識するため、同じ ID の GPU が2つある場合、パススルードライバーをどちらか片方にバインドできません。スクリプトを使って {{ic|driver_override}} の pci バスアドレスによって割り当てる必要があります。 |
||
− | Due to how both pci-stub and vfio-pci use your vendor and device id pair to identify which device they need to bind to at boot, if you have two GPUs sharing such an ID pair you won't be able to get your passthough driver to bind with just one of them. This sort of setup makes it necessary to use a script, so that whichever driver you're using is instead assigned by pci bus address using the {{ic|driver_override}} mechanism. |
||
+ | スクリプトを作成して vfio-pci をブート GPU 以外の全ての GPU にバインドすることができます。{{ic|/usr/bin/vfio-pci-override.sh}} スクリプトを作成: |
||
− | Here, we will make a script to bind vfio-pci to all GPUs but the boot gpu. Create the script "/sbin/vfio-pci-override.sh": |
||
+ | {{bc|<nowiki> |
||
− | #!/bin/sh |
||
+ | #!/bin/sh |
||
− | |||
+ | |||
− | for i in /sys/devices/pci*/*/boot_vga; do |
||
+ | for i in /sys/bus/pci/devices/*/boot_vga; do |
||
− | if [ $(cat "$i") -eq 0 ]; then |
||
+ | if [ $(cat "$i") -eq 0 ]; then |
||
− | GPU="${i%/boot_vga}" |
||
+ | GPU="${i%/boot_vga}" |
||
− | AUDIO="$(echo "$GPU" | sed -e "s/0$/1/")" |
||
+ | AUDIO="$(echo "$GPU" | sed -e "s/0$/1/")" |
||
− | echo "vfio-pci" > "$GPU/driver_override" |
||
+ | echo "vfio-pci" > "$GPU/driver_override" |
||
− | if [ -d "$AUDIO" ]; then |
||
+ | if [ -d "$AUDIO" ]; then |
||
− | echo "vfio-pci" > "$AUDIO/driver_override" |
||
+ | echo "vfio-pci" > "$AUDIO/driver_override" |
||
− | fi |
||
+ | fi |
||
− | fi |
||
+ | fi |
||
− | done |
||
+ | done |
||
− | |||
+ | |||
− | modprobe -i vfio-pci |
||
+ | modprobe -i vfio-pci |
||
+ | </nowiki>}} |
||
{{ic|/etc/modprobe.d/vfio.conf}} を以下の内容で作成: |
{{ic|/etc/modprobe.d/vfio.conf}} を以下の内容で作成: |
||
− | install vfio-pci / |
+ | install vfio-pci /usr/bin/vfio-pci-override.sh |
{{ic|/etc/mkinitcpio.conf}} を編集: |
{{ic|/etc/mkinitcpio.conf}} を編集: |
||
− | + | MODULES からビデオドライバーを全て削除して {{ic|vfio-pci}} と {{ic|vfio_iommu_type1}} を追加してください: |
|
− | MODULES= |
+ | MODULES=(ext4 vfat vfio-pci vfio_iommu_type1) |
− | + | {{ic|/etc/modprobe.d/vfio.conf}} と {{ic|/usr/bin/vfio-pci-override.sh}} を FILES に追加してください: |
|
− | FILES= |
+ | FILES=(/etc/modprobe.d/vfio.conf /usr/bin/vfio-pci-override.sh) |
+ | initramfs を再生成して再起動してください: |
||
− | Regenerate your initramfs, and reboot: |
||
# mkinitcpio -p linux |
# mkinitcpio -p linux |
||
=== ブート GPU をゲストにパススルー === |
=== ブート GPU をゲストにパススルー === |
||
+ | PCI パススルーをするときに {{ic|boot_vga}} とマークされた GPU は特殊なケースになります。ブートメッセージや BIOS の設定メニューなどを表示するのに BIOS がその GPU を必要とするためです。ブート GPU はパススルー時に [https://www.redhat.com/archives/vfio-users/2016-May/msg00224.html 自由に改造できる VGA ブート ROM のコピー] を作成します。システムから認識されるのは改造されたコピーになり、パススルードライバーによって不正な GPU として拒否される可能性があります。一般的には BIOS の設定でブート GPU を変更して代わりにホスト GPU を使用するか、あるいはそれが不可能な場合、マシンのホストとゲストのカードを交換することが推奨されます。 |
||
− | The GPU marked as {{ic|boot_vga}} is a special case when it comes to doing PCI passthroughs, since the BIOS needs to use it in order to display things like boot messages or the BIOS configuration menu. To do that, it makes [https://www.redhat.com/archives/vfio-users/2016-May/msg00224.html a copy of the VGA boot ROM which can then be freely modified]. This modified copy is the version the system gets to see, which the passthrough driver may reject as invalid. As such, it is generally reccomanded to change the boot GPU in the BIOS configuration so the host GPU is used instead or, if that's not possible, to swap the host and guest cards in the machine itself. |
||
=== IOMMU グループのバイパス (ACS 上書きパッチ) === |
=== IOMMU グループのバイパス (ACS 上書きパッチ) === |
||
354行目: | 426行目: | ||
さらに、ACS override パッチはカーネルのコマンドラインオプションで有効にしなければなりません。パッチファイルは以下のドキュメントを追加します: |
さらに、ACS override パッチはカーネルのコマンドラインオプションで有効にしなければなりません。パッチファイルは以下のドキュメントを追加します: |
||
− | + | pcie_acs_override = |
|
− | + | [PCIE] Override missing PCIe ACS support for: |
|
− | + | downstream |
|
− | + | All downstream ports - full ACS capabilties |
|
− | + | multifunction |
|
− | + | All multifunction devices - multifunction ACS subset |
|
− | + | id:nnnn:nnnn |
|
− | + | Specfic device - full ACS capabilities |
|
− | + | Specified as vid:did (vendor/device ID) in hex |
|
通常は {{ic|pcie_acs_override<nowiki>=</nowiki>downstream}} オプションで上手くいきます。 |
通常は {{ic|pcie_acs_override<nowiki>=</nowiki>downstream}} オプションで上手くいきます。 |
||
368行目: | 440行目: | ||
インストールと設定が終わったら、[[カーネルパラメータ|ブートローダーのカーネルパラメータ]]を再設定して {{ic|pcie_acs_override<nowiki>=</nowiki>}} オプションが有効になった状態で新しいカーネルをロードするようにしてください。 |
インストールと設定が終わったら、[[カーネルパラメータ|ブートローダーのカーネルパラメータ]]を再設定して {{ic|pcie_acs_override<nowiki>=</nowiki>}} オプションが有効になった状態で新しいカーネルをロードするようにしてください。 |
||
+ | == QEMU で libvirt を使わない == |
||
− | == libvirtd を使わない (CLI ベースの) QEMU の例 (再起動せずに GPU を切り替え可能) == |
||
+ | libvirt を使って仮想マシンをセットアップするかわりに、QEMU コマンドにカスタムパラメータを付けるだけで PCI パススルーを使用するように VM を起動できます。スクリプトによる設定などで有用です。 |
||
− | This script starts Samba and Synergy, runs the VM and closes everything after the VM is shut down. Note that this method does '''not''' require libvirtd to be running or configured. |
||
+ | [[#IOMMU のセットアップ]]と[[#GPU の分離]]を行ってから、[[QEMU]] の記事に従って仮想環境をセットアップして、[[QEMU#KVM を有効にする|KVM を有効]]にして {{ic|1=-device vfio-pci,host=07:00.0}} フラグを使ってください。識別子の (07:00.0) は GPU を分離するときに使用した実際のデバイスの ID に置き換えてください。 |
||
− | Since this was posted, the author continued working on scripts to ease the workflow of switching GPUs. All of said scripts can be found on the author's GitLab instance: https://git.mel.vin/melvin/scripts/tree/master/qemu. |
||
+ | OVMF ファームウェアを利用するために、{{Pkg|ovmf}}{{Broken package link|置換パッケージ: {{Pkg|edk2-ovmf}}}} パッケージをインストールして、{{ic|/usr/share/ovmf/x64/OVMF_VARS.fd}} から {{ic|/tmp/MY_VARS.fd}} など一時的なディレクトリに UEFI 変数をコピーして QEMU コマンドに以下のパラメータを追加して OVMF のパスを指定します (パラメータの順序は重要です): |
||
− | With these new scripts, is it possible to switch GPUs without rebooting, only a restart of the X session is needed. This is all handled by a tiny shell script that runs in the tty. When you log in the tty, it will ask which card you would like to use if you autolaunch the shell script. |
||
+ | * {{ic|1=-drive if=pflash,format=raw,readonly,file=/usr/share/ovmf/x64/OVMF_CODE.fd}} - OVMF ファームウェアバイナリを指定、readonly オプションに注意してください。 |
||
− | [https://www.redhat.com/archives/vfio-users/2016-May/msg00187.html vfio-users : Full set of (runtime) scripts for VFIO + Qemu CLI] |
||
+ | * {{ic|1=-drive if=pflash,format=raw,file=/tmp/MY_VARS.fd}} - 変数のパスを指定。 |
||
+ | {{Note|OVMF の代わりに QEMU のデフォルトである SeaBIOS を使うこともできますが、パススルーの設定で問題が発生することがあるため推奨されません。}} |
||
− | [https://www.redhat.com/archives/vfio-users/2015-August/msg00020.html vfio-users : Example configuration with CLI Qemu (working VM => host audio)] |
||
+ | QEMU の記事を読んで [[QEMU#virtio ドライバーのインストール|virtio ドライバー]]の使用などパフォーマンスを向上させることができる設定を調べることを推奨します。 |
||
− | The script below is the main QEMU launcher as of 2016-05-16, all other scripts can be found in the repo. |
||
+ | また、{{ic|1=-cpu host,kvm=off}} パラメータを使ってホストの CPU モデル情報を VM に渡して Nvidia などメーカーのデバイスドライバーから仮想環境でないと認識させる必要があるかもしれません。 |
||
− | {{hc|slightly edited from "windows.sh" 2016-05-16 : https://git.mel.vin/melvin/scripts/tree/master/qemu|<nowiki>#!/bin/bash |
||
+ | ==他のデバイスのパススルー== |
||
− | if [[ $EUID -ne 0 ]] |
||
+ | ===USB コントローラ=== |
||
− | then |
||
+ | マザーボードに接続された複数の USB コントローラが複数のグループにマッピングされている場合、USB デバイスの代わりに USB コントローラをパススルーすることができます。個別の USB デバイスではなくコントローラをパススルーすることには以下の利点があります: |
||
− | echo "This script must be run as root" |
||
− | exit 1 |
||
− | fi |
||
+ | * 特定の操作 (スマートフォンのアップデートなど) でデバイスが切断されたり ID が変わったりしても、仮想マシンから突然認識されなくなることはありません。 |
||
− | echo "Starting Samba" |
||
+ | * コントローラによって管理されている USB 端子を VM が直接扱うため、デバイスを接続・切断してもハイパーバイザに通知する必要がありません。 |
||
− | systemctl start smbd.service |
||
+ | * VM を起動したときにゲストにパススルーする USB デバイスがなくなってしまっていても Libvirt はエラーを出力しません。 |
||
− | systemctl start nmbd.service |
||
+ | GPU と違って、大抵の USB コントローラのドライバーでは VM で使用するのに特殊な設定を必要としません。副作用を起こさずにホストとゲストの間で制御を受け渡すことができます。 |
||
− | echo "Starting VM" |
||
− | export QEMU_AUDIO_DRV="pa" |
||
− | qemu-system-x86_64 \ |
||
− | -serial none \ |
||
− | -parallel none \ |
||
− | -nodefaults \ |
||
− | -nodefconfig \ |
||
− | -no-user-config \ |
||
− | -enable-kvm \ |
||
− | -name Windows \ |
||
− | -cpu host,kvm=off,hv_vapic,hv_time,hv_relaxed,hv_spinlocks=0x1fff,hv_vendor_id=sugoidesu \ |
||
− | -smp sockets=1,cores=4,threads=1 \ |
||
− | -m 8192 \ |
||
− | -mem-path /dev/hugepages \ |
||
− | -mem-prealloc \ |
||
− | -soundhw hda \ |
||
− | -device ich9-usb-uhci3,id=uhci \ |
||
− | -device usb-ehci,id=ehci \ |
||
− | -device nec-usb-xhci,id=xhci \ |
||
− | -machine pc,accel=kvm,kernel_irqchip=on,mem-merge=off \ |
||
− | -drive if=pflash,format=raw,file=./Windows_ovmf_x64.bin \ |
||
− | -rtc base=localtime,clock=host,driftfix=none \ |
||
− | -boot order=c \ |
||
− | -net nic,vlan=0,macaddr=52:54:00:00:00:01,model=virtio,name=net0 \ |
||
− | -net bridge,vlan=0,name=bridge0,br=br0 \ |
||
− | -drive if=virtio,id=drive0,file=./Windows.img,format=raw,cache=none,aio=native \ |
||
− | -nographic \ |
||
− | -device vfio-pci,host=04:00.0,addr=09.0,multifunction=on \ |
||
− | -device vfio-pci,host=04:00.1,addr=09.1 \ |
||
− | -usbdevice host:046d:c29b `# Logitech G27` & |
||
+ | {{Warning|USB コントローラがリセットに対応していることを確認してください。[[#リセットに対応していないデバイスのパススルー]]を参照。}} |
||
− | # -usbdevice host:054c:05c4 `# Sony DualShock 4` \ |
||
− | # -usbdevice host:28de:1142 `# Steam Controller` \ |
||
+ | 以下のコマンドを使うことでコントローラや端子とデバイスがどのように PCI デバイスと割り当てられているか確認することができます: |
||
− | sleep 5 |
||
+ | {{hc|$ <nowiki>for usb_ctrl in $(find /sys/bus/usb/devices/usb* -maxdepth 0 -type l); do pci_path="$(dirname "$(realpath "${usb_ctrl}")")"; echo "Bus $(cat "${usb_ctrl}/busnum") --> $(basename $pci_path) (IOMMU group $(basename $(realpath $pci_path/iommu_group)))"; lsusb -s "$(cat "${usb_ctrl}/busnum"):"; echo; done</nowiki>| |
||
− | while [[ $(pgrep -x -u root qemu-system-x86) ]] |
||
+ | Bus 1 --> 0000:00:1a.0 (IOMMU group 4) |
||
− | do |
||
+ | Bus 001 Device 004: ID 04f2:b217 Chicony Electronics Co., Ltd Lenovo Integrated Camera (0.3MP) |
||
− | if [[ ! $(pgrep -x -u REGULAR_USER synergys) ]] |
||
+ | Bus 001 Device 007: ID 0a5c:21e6 Broadcom Corp. BCM20702 Bluetooth 4.0 [ThinkPad] |
||
− | then |
||
+ | Bus 001 Device 008: ID 0781:5530 SanDisk Corp. Cruzer |
||
− | echo "Starting Synergy server" |
||
+ | Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub |
||
− | sudo -u REGULAR_USER /usr/bin/synergys --debug ERROR --no-daemon --enable-crypto --config /etc/synergy.conf & |
||
+ | Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub |
||
− | fi |
||
+ | Bus 2 --> 0000:00:1d.0 (IOMMU group 9) |
||
− | sleep 5 |
||
+ | Bus 002 Device 006: ID 0451:e012 Texas Instruments, Inc. TI-Nspire Calculator |
||
− | done |
||
+ | Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub |
||
+ | Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub}} |
||
+ | 上記のノートパソコンには2つの USB コントローラによる3つの USB ポートがあり、それぞれに IOMMU グループが存在します。例として Bus 001 はひとつの USB ポートを管理していますが (SanDisk の USB ペンドライブが接続されています)、内蔵ウェブカメラや bluetooth カードなど内部デバイスも管理されています。一方 Bus 002 は接続されている電卓以外は何も管理していません。3つ目のポートは空で、リスト上には表示されていませんが、実際は Bus 002 によって管理されています。 |
||
− | echo "VM stopped" |
||
+ | 様々なデバイスを接続してみてどのコントローラがどのポートを管理しているか判断して、どのコントローラをパススルーするか決めたら、ゲスト設定の VM によって制御する PCI ホストデバイスのリストにコントローラを追加してください。他の設定は不要です。 |
||
− | echo "Stopping Synergy server" |
||
− | pkill -u REGULAR_USER synergys |
||
+ | {{Note|USB コントローラがリセットをサポートしていないか、独立したグループにないか、もしくはパススルーできない場合でも、[[udev]] ルールを通じて同様の結果を達成することが可能です。特定の USB ポートに接続された任意のデバイスを仮想マシンに自動的に接続できるようにする [https://github.com/olavmrk/usb-libvirt-hotplug] を参照して下さい。}} |
||
− | echo "Stopping Samba" |
||
− | systemctl stop smbd.service |
||
− | systemctl stop nmbd.service |
||
+ | ===PulseAudio で仮想マシンの音声出力をホストにパススルー=== |
||
− | exit 0</nowiki>}} |
||
+ | libvirt を使うことで仮想マシンの音声出力をアプリケーションとしてホストに転送することが可能です。複数の音声ストリームをホストの出力に転送でき、パススルーをサポートしていない音声出力デバイスで使うことができます。転送するには [[PulseAudio]] が必要です。 |
||
+ | まず、{{ic|<nowiki>#user = ""</nowiki>}} 行のコメントを削除してください。それからクォートの中にユーザー名を入力してください。これで QEMU はユーザーの PulseAudio ストリームを転送するようになります。 |
||
− | == QEMU と libvirtd を使用する例 == |
||
+ | {{hc|/etc/libvirt/qemu.conf| |
||
+ | user <nowiki>=</nowiki> "example"}} |
||
+ | 次に、libvirt の設定を変更してください。 |
||
− | <domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'> |
||
+ | |||
− | <name>win7</name> |
||
+ | 以下の行を: |
||
− | <uuid>a3bf6450-d26b-4815-b564-b1c9b098a740</uuid> |
||
+ | |||
− | <memory unit='KiB'>8388608</memory> |
||
+ | {{hc|virsh edit [vmname]| |
||
− | <currentMemory unit='KiB'>8388608</currentMemory> |
||
+ | <domain type<nowiki>=</nowiki>'kvm'> |
||
− | <vcpu placement='static'>8</vcpu> |
||
+ | }} |
||
− | <os> |
||
+ | |||
− | <type arch='x86_64' machine='pc-i440fx-2.4'>hvm</type> |
||
+ | 以下のように変更してください: |
||
− | <boot dev='hd'/> |
||
+ | |||
− | <bootmenu enable='yes'/> |
||
+ | {{hc|virsh edit [vmname]| |
||
− | </os> |
||
+ | <domain type<nowiki>=</nowiki>'kvm' xmlns:qemu<nowiki>='http://libvirt.org/schemas/domain/qemu/1.0'</nowiki>> |
||
− | <features> |
||
+ | }} |
||
− | <acpi/> |
||
+ | |||
− | <kvm> |
||
+ | そして libvirt の xml ファイルの末尾に QEMU PulseAudio 環境変数を設定してください。 |
||
− | <hidden state='on'/> |
||
+ | |||
− | </kvm> |
||
+ | 以下の行を: |
||
− | </features> |
||
+ | |||
− | <cpu mode='host-passthrough'> |
||
+ | {{hc|virsh edit [vmname]| |
||
− | <topology sockets='1' cores='8' threads='1'/> |
||
− | </ |
+ | </devices> |
+ | </domain> |
||
− | <clock offset='utc'/> |
||
+ | }} |
||
− | <on_poweroff>destroy</on_poweroff> |
||
+ | |||
− | <on_reboot>restart</on_reboot> |
||
+ | 以下のように変更してください: |
||
− | <on_crash>destroy</on_crash> |
||
+ | |||
− | <devices> |
||
+ | {{hc|virsh edit [vmname]| |
||
− | <emulator>/usr/sbin/qemu-system-x86_64</emulator> |
||
+ | </devices> |
||
− | <disk type='block' device='disk'> |
||
+ | <qemu:commandline> |
||
− | <driver name='qemu' type='raw' cache='none' io='native'/> |
||
+ | <qemu:env name<nowiki>=</nowiki>'QEMU_AUDIO_DRV' value<nowiki>=</nowiki>'pa'/> |
||
− | <source dev='/dev/rootvg/win7'/> |
||
+ | <qemu:env name<nowiki>=</nowiki>'QEMU_PA_SERVER' value<nowiki>=</nowiki>'/run/user/1000/pulse/native'/> |
||
− | <target dev='vda' bus='virtio'/> |
||
+ | </qemu:commandline> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> |
||
− | </disk> |
||
− | <disk type='block' device='disk'> |
||
− | <driver name='qemu' type='raw' cache='none' io='native'/> |
||
− | <source dev='/dev/rootvg/windane'/> |
||
− | <target dev='vdb' bus='virtio'/> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x07' function='0x0'/> |
||
− | </disk> |
||
− | <disk type='block' device='cdrom'> |
||
− | <driver name='qemu' type='raw' cache='none' io='native'/> |
||
− | <target dev='hdb' bus='ide'/> |
||
− | <readonly/> |
||
− | <address type='drive' controller='0' bus='0' target='0' unit='1'/> |
||
− | </disk> |
||
− | <controller type='usb' index='0'> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> |
||
− | </controller> |
||
− | <controller type='pci' index='0' model='pci-root'/> |
||
− | <controller type='ide' index='0'> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> |
||
− | </controller> |
||
− | <controller type='sata' index='0'> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> |
||
− | </controller> |
||
− | <interface type='network'> |
||
− | <mac address='52:54:00:fa:59:92'/> |
||
− | <source network='default'/> |
||
− | <model type='rtl8139'/> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x05' function='0x0'/> |
||
− | </interface> |
||
− | <input type='mouse' bus='ps2'/> |
||
− | <input type='keyboard' bus='ps2'/> |
||
− | <sound model='ac97'> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> |
||
− | </sound> |
||
− | <memballoon model='virtio'> |
||
− | <address type='pci' domain='0x0000' bus='0x00' slot='0x06' function='0x0'/> |
||
− | </memballoon> |
||
− | </devices> |
||
− | <qemu:commandline> |
||
− | <qemu:arg value='-device'/> |
||
− | <qemu:arg value='vfio-pci,host=02:00.0,multifunction=on,x-vga=on'/> |
||
− | <qemu:arg value='-device'/> |
||
− | <qemu:arg value='vfio-pci,host=02:00.1'/> |
||
− | <qemu:env name='QEMU_PA_SAMPLES' value='1024'/> |
||
− | <qemu:env name='QEMU_AUDIO_DRV' value='pa'/> |
||
− | <qemu:env name='QEMU_PA_SERVER' value='/run/user/1000/pulse/native'/> |
||
− | </qemu:commandline> |
||
</domain> |
</domain> |
||
+ | }} |
||
+ | |||
+ | user ディレクトリの 1000 はあなたが使用しているユーザーの uid に置き換えてください ({{ic|id}} コマンドを実行することで確認できます)。先に進む前にファイルを保存して終了しないと変更が登録されません。終了後に {{ic|<nowiki>Domain [vmname] XML configuration edited.</nowiki>}} というメッセージが表示されれば、変更が適用されたということです。 |
||
+ | |||
+ | 設定したら {{ic|libvirtd}} サービスと {{ic|pulseaudio.service}} の[[Systemd/ユーザー|ユーザーサービス]]を再起動してください。 |
||
+ | |||
+ | これで仮想マシンの音声出力はアプリケーションとしてホストに転送されるようになります。{{Pkg|pavucontrol}} アプリケーションを使うことで出力デバイスを制御できます。Windows ゲストの場合、[[#ビデオカードの HDMI 出力からの音声がおかしい|メッセージシグナル割り込み]]を使用しないとノイズが発生するので注意してください。 |
||
+ | |||
+ | ==== QEMU 3.0 オーディオの変更 ==== |
||
+ | |||
+ | QEMU 3.0 以降では、オーディオパッチの一部がマージされました ([https://www.reddit.com/r/VFIO/comments/97iuov/qemu_30_released/e49wmyd/ reddit リンク])。パッチのいくつかはまだ正式に上流にマージされていないため、 {{AUR|qemu-patched}}{{Broken package link|パッケージが存在しません}} パッケージにはオーディオパッチが複数含まれています。 |
||
+ | |||
+ | 新しいコードパスを使用するにはあなたの VM のセットアップに応じてチップセットを、例えば {{ic|pc-q35-3.0}} または {{ic|pc-i440fx-3.0}} (qemu 3.0 インストール後) に変更する必要があります: |
||
+ | |||
+ | {{hc|$ virsh edit [vmname]| |
||
+ | <domain type<nowiki>=</nowiki>'kvm'> |
||
+ | ... |
||
+ | <os> |
||
+ | <type arch<nowiki>=</nowiki>'x86_64' machine<nowiki>=</nowiki>'pc-q35-3.0'>hvm</type> |
||
+ | ... |
||
+ | </os> |
||
+ | }} |
||
+ | |||
+ | {{hc|$ virsh edit [vmname]| |
||
+ | <domain type<nowiki>=</nowiki>'kvm'> |
||
+ | ... |
||
+ | <os> |
||
+ | <type arch<nowiki>=</nowiki>'x86_64' machine<nowiki>=</nowiki>'pc-i440fx-3.0'>hvm</type> |
||
+ | ... |
||
+ | </os> |
||
+ | }} |
||
+ | |||
+ | {{Note| |
||
+ | * {{AUR|qemu-patched}}{{Broken package link|パッケージが存在しません}} のコンパイル時間を早めるには {{ic|1=--target-list=x86_64-softmmu}} を使って qemu の x86_64 ゲストサポートのみコンパイルします。 |
||
+ | * Qemu 3.0 以降で PulseAudio をユーザーとして実行している場合に {{ic|1=/etc/libvirt/qemu.conf}} で {{ic|1= nographics_allow_host_audio = 1}} を有効にしたときは、上記の XML 引数 {{ic|qemu:env}} は必要''ありません''。QEMU/Libvirt で別のユーザーを使用する場合は、{{ic|QEMU_PA_SERVER}} 変数を維持する必要があります。そうしないとアクセス許可エラーが発生します。 |
||
+ | }} |
||
+ | |||
+ | ===注意事項=== |
||
+ | ====リセットに対応していないデバイスのパススルー==== |
||
+ | 仮想マシンのシャットダウン時、ゲストが使用していたデバイスは全てシャットダウンの準備時に OS によって deinitialize されます。この状態ではデバイスは機能しなくなり、通常通りに機能させるには電源を入れ直さなくてはなりません。Linux は独自にパワーサイクルを処理しますが、デバイスのリセット方法がわからない場合、無効状態のままになりデバイスが利用不可能になります。Libvirt と Qemu はどちらも仮想マシンを完全に停止する前に全てのホスト PCI デバイスが再接続できる状態になっていることを求めるため、デバイスがリセットできない状態になると、"Shutting down" 状態でフリーズしてホストマシンを再起動するまで仮想マシンを再起動できなくなってしまいます。そのため、カーネルによってリセットが可能な PCI デバイスのみパススルーすることを推奨します。PCI デバイスの sysfs ノードに {{ic|reset}} ファイルが存在するかどうかでリセット可能かどうか確認できます (例: {{ic|/sys/bus/pci/devices/0000:00:1a.0/reset}})。 |
||
+ | |||
+ | 以下の bash コマンドを実行するとどのデバイスがリセットできてどのデバイスがリセットできないか表示されます: |
||
+ | |||
+ | {{hc|<nowiki>for iommu_group in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d);do echo "IOMMU group $(basename "$iommu_group")"; for device in $(\ls -1 "$iommu_group"/devices/); do if [[ -e "$iommu_group"/devices/"$device"/reset ]]; then echo -n "[RESET]"; fi; echo -n $'\t';lspci -nns "$device"; done; done</nowiki>| |
||
+ | IOMMU group 0 |
||
+ | 00:00.0 Host bridge [0600]: Intel Corporation Xeon E3-1200 v2/Ivy Bridge DRAM Controller [8086:0158] (rev 09) |
||
+ | IOMMU group 1 |
||
+ | 00:01.0 PCI bridge [0604]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port [8086:0151] (rev 09) |
||
+ | 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GK208 [GeForce GT 720] [10de:1288] (rev a1) |
||
+ | 01:00.1 Audio device [0403]: NVIDIA Corporation GK208 HDMI/DP Audio Controller [10de:0e0f] (rev a1) |
||
+ | IOMMU group 2 |
||
+ | 00:14.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller [8086:1e31] (rev 04) |
||
+ | IOMMU group 4 |
||
+ | [RESET] 00:1a.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 [8086:1e2d] (rev 04) |
||
+ | IOMMU group 5 |
||
+ | [RESET] 00:1b.0 Audio device [0403]: Intel Corporation 7 Series/C210 Series Chipset Family High Definition Audio Controller [8086:1e20] (rev 04) |
||
+ | IOMMU group 10 |
||
+ | [RESET] 00:1d.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 [8086:1e26] (rev 04) |
||
+ | IOMMU group 13 |
||
+ | 06:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1) |
||
+ | 06:00.1 Audio device [0403]: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1) |
||
+ | }} |
||
+ | |||
+ | 上記の場合 00:14.0 の xHCI USB コントローラはリセットができないため、仮想マシンが正しくシャットダウンできなくなります。00:1b.0 の内蔵サウンドカードと 00:1a.0 および 00:1d.0 のコントローラはリセット可能であるため問題が起こりません。 |
||
==トラブルシューティング== |
==トラブルシューティング== |
||
+ | 以下で問題が見つけられない場合、[[QEMU#トラブルシューティング]]も見てください。 |
||
+ | |||
===Windows の仮想マシンに NVIDIA の GPU をパススルーした場合に "Error 43 : Driver failed to load"=== |
===Windows の仮想マシンに NVIDIA の GPU をパススルーした場合に "Error 43 : Driver failed to load"=== |
||
− | {{Note| |
+ | {{Note|以下の設定により Nvidia ドライバーによって起動時に SYSTEM_THREAD_EXCEPTION_NOT_HANDLED でクラッシュする問題も解決します。}} |
+ | バージョン 337.88 から、Windows の Nvidia ドライバーはハイパーバイザが動作しているかどうかを確認して、動作していることを認識すると Windows のデバイスマネージャに Error 43 を吐くようになりました。QEMU 2.5.0 と libvirt 1.3.3 以上では、ハイパーバイザの vendor_id を偽装することができ、Nvidia ドライバーを騙してロードさせることができます。QEMU コマンドの cpu パラメータに {{ic|<nowiki>hv_vendor_id=whatever</nowiki>}} を追加するか、libvirt のドメイン設定に以下の行を追加するだけです。ID は12文字ちょうどの英数字 (例: '1234567890ab') に設定してください。 |
||
− | Since version 337.88, Nvidia drivers on Windows check if an hypervisor is running and fail if it detects one, which results in an Error 43 in the Windows device manager. Starting with QEMU 2.5.0 and libvirt 1.3.3, the vendor_id for the hypervisor can be spoofed, which is enough to fool the Nvidia drivers into loading anyway. All one must do is add {{ic|<nowiki>hv_vendor_id=whatever</nowiki>}} to the cpu parameters in their QEMU command line, or by adding the following line to their libvirt domain configuration. It may help for the ID to be set to a 12-character alphanumeric (e.g. '123456789ab') as opposed to longer or shorter strings. |
||
− | {{hc| |
+ | {{hc|$ virsh edit [vmname]|<nowiki>... |
− | <nowiki> |
||
<features> |
<features> |
||
<hyperv> |
<hyperv> |
||
553行目: | 614行目: | ||
</kvm> |
</kvm> |
||
</features> |
</features> |
||
− | ... |
+ | ...</nowiki>}} |
− | </nowiki>}} |
||
+ | 古いバージョンの QEMU や libvirt を使用している場合は、ハイパーバイザの拡張を無効化する必要があり、かなり性能が落ちてしまいます。libvirt のドメイン設定ファイルに以下を記述してください: |
||
− | Users with older versions of QEMU and/or libvirt will instead have to disable a few hypervisor extensions, which can degrade performance substentially. If this is what you want to do, do the following replacement in your libvirt domain config file. |
||
− | {{hc| |
+ | {{hc|$ virsh edit [vmname]|<nowiki>... |
− | + | <features> |
|
<hyperv> |
<hyperv> |
||
<relaxed state='on'/> |
<relaxed state='on'/> |
||
569行目: | 629行目: | ||
<clock offset='localtime'> |
<clock offset='localtime'> |
||
<timer name='hypervclock' present='yes'/> |
<timer name='hypervclock' present='yes'/> |
||
− | </clock |
+ | </clock> |
− | ...}} |
+ | ...</nowiki>}} |
{{bc|<nowiki>... |
{{bc|<nowiki>... |
||
591行目: | 651行目: | ||
...</nowiki>}} |
...</nowiki>}} |
||
+ | ====VM を起動した後に dmesg に "BAR 3: can't reserve [mem]" エラーが表示される==== |
||
− | ===CPU 例外によってクラッシュが発生する=== |
||
− | GeForce Experience からサポートされていない CPU が存在するとエラーが吐かれて、ゲームの最適化などの機能が機能しない場合、KVM モジュールに {{ic|1=ignore_msrs=1}} オプションを指定して実装されていない MSR へのアクセスを無視することで問題は解決します: |
||
+ | 上記の方法を試してもコード 43 が発生する場合、dmesg にメモリ予約エラーが記録されていないか確認してください: |
||
− | {{hc|<nowiki>/etc/modprobe.d/kvm.conf</nowiki>|<nowiki>... |
||
− | options kvm ignore_msrs=1 |
||
− | ...</nowiki>}} |
||
+ | vfio-pci 0000:09:00.0: BAR 3: can't reserve [mem 0xf0000000-0xf1ffffff 64bit pref] |
||
− | {{Warning|未知の MSR のアクセスを無視すると、VM 内の他のソフトウェアや他の VM が動作しなくなる可能性があります。}} |
||
+ | |||
+ | 上記のようなメッセージが出力される場合、グラフィックカードを接続している PCI ブリッジを確認してください。以下のコマンドでデバイスツリーを確認できます: |
||
+ | |||
+ | $ lspci -t |
||
+ | |||
+ | VM を起動する前に以下のコマンドを実行してください (ID は上記のコマンドで確認できた実際の ID に置き換えてください): |
||
+ | |||
+ | # echo 1 > /sys/bus/pci/devices/0000\:00\:03.1/remove |
||
+ | # echo 1 > /sys/bus/pci/rescan |
||
+ | |||
+ | 詳しくは [https://www.linuxquestions.org/questions/linux-kernel-70/kernel-fails-to-assign-memory-to-pcie-device-4175487043/ こちらの記事] を参照。 |
||
+ | |||
+ | {{Note|おそらく {{ic|video<nowiki>=</nowiki>efifb:off}} [[カーネルパラメータ]]の設定も必要です [https://pve.proxmox.com/wiki/Pci_passthrough#BAR_3:_can.27t_reserve_.5Bmem.5D_error]。}} |
||
+ | |||
+ | ===CPU 例外によってクラッシュが発生する=== |
||
+ | [[QEMU#特定の Windows のゲームやアプリケーションでクラッシュやブルスクリーンが発生する]]を参照。 |
||
===Windows の仮想マシンを起動したときに "System Thread Exception Not Handled"=== |
===Windows の仮想マシンを起動したときに "System Thread Exception Not Handled"=== |
||
+ | [[QEMU#Windows の仮想マシンを起動したときに "System Thread Exception Not Handled"]] を参照。 |
||
− | Windows 8 or Windows 10 guests may raise a generic compatibility exception at boot, namely "System Thread Exception Not Handled", which tends to be caused by legacy drivers acting strangely on real machines. On KVM machines this issue can generally be solved by setting the CPU model to {{ic|core2duo}}. |
||
===ビデオカードの HDMI 出力からの音声がおかしい=== |
===ビデオカードの HDMI 出力からの音声がおかしい=== |
||
+ | ビデオカードの HDMI 端子を使用したときに、ユーザーによっては仮想マシンの音声出力が遅れたり音が割れたりすることがあります。大抵の場合、グラフィックも遅れるようになります。解決方法としてはデフォルトの割り込み方法 (Line-Based Interrupts) の代わりに MSI (Message Signaled-Based Interrupts) を有効にする方法があります。 |
||
− | For some users VM's audio slows down/starts stuttering/becomes demonic after a while when it's pumped through HDMI on the video card. This usually also slows down graphics. |
||
− | A possible solution consists of enabling MSI (Message Signaled-Based Interrupts) instead of the default (Line-Based Interrupts). |
||
+ | MSI がサポートされているか・有効になっているか確認するには、以下のコマンドを root で実行してください: |
||
− | In order to check whether MSI is supported or enabled, run the following command as root: |
||
# lspci -vs $device | grep 'MSI:' |
# lspci -vs $device | grep 'MSI:' |
||
− | + | `$device` はカードのアドレスに置き換えてください (例: `01:00.0`)。 |
|
+ | 出力は以下のようになります: |
||
− | The output should be similar to: |
||
Capabilities: [60] MSI: Enable'''-''' Count=1/1 Maskable- 64bit+ |
Capabilities: [60] MSI: Enable'''-''' Count=1/1 Maskable- 64bit+ |
||
+ | {{ic|Enable}} の後ろの {{ic|-}} は MSI がサポートされおり VM によって使われていないことを意味します。{{ic|+}} であれば VM によって使われています。 |
||
− | A {{ic|-}} after {{ic|Enabled}} means MSI is supported, but not used by the VM, while a {{ic|+}} says that the VM is using it. |
||
− | + | 有効にする手順は非常に複雑です。[https://forums.guru3d.com/showthread.php?t=378044 こちら] に設定の手順と概要が載っています。 |
|
− | + | 他にも [http://lime-technology.com/wiki/index.php/UnRAID_6/VM_Guest_Support#Enable_MSI_for_Interrupts_to_Fix_HDMI_Audio_Support lime-technology の wiki] や [http://vfio.blogspot.it/2014/09/vfio-interrupts-and-how-to-coax-windows.html VFIO tips and tricks] の記事にヒントが載っています。 |
|
+ | [https://github.com/CHEF-KOCH/MSI-utility MSI Utility (FOSS Version 2)] という UI ツールが64ビットの Windows 10 で動作しこの手順を簡素化します。 |
||
− | Some tools named {{ic|MSI_util}} or similar are available on the Internet, but they didn't work for me on Windows 10 64bit. |
||
− | + | nVidia カードの 0 function の MSI を有効にするだけでは問題が解決しない場合 ({{ic|01:00.0 VGA compatible controller: NVIDIA Corporation GM206 [GeForce GTX 960] (rev a1) (prog-if 00 [VGA controller])}})、他の function の MSI も有効にする必要があります ({{ic|01:00.1 Audio device: NVIDIA Corporation Device 0fba (rev a1)}})。 |
|
+ | === intel_iommu を有効にしたときにホスト側で HDMI から音声が出力されない === |
||
− | ==他のデバイスのパススルー== |
||
− | ===USB コントローラ=== |
||
− | If your motherboard has multiple USB controllers mapped to multiple groups, it is possible to pass those instead of USB devices. Passing an actual controller over an individual USB device provides the following advantages : |
||
+ | {{ic|intel_iommu}} を有効にしたときにホストの Intel GPU の HDMI 出力デバイスが使えなくなった場合、{{ic|igfx_off}} (i.e. {{ic|intel_iommu<nowiki>=</nowiki>on,igfx_off}}) オプションを設定することで音声が出力できるようになることがあります。{{ic|igfx_off}} の設定について詳しくは [https://www.kernel.org/doc/Documentation/Intel-IOMMU.txt Intel-IOMMU.txt] の {{ic|Graphics Problems?}} を読んでください。 |
||
− | * If a device disconnects or changes ID over the course of an given operation (such as a phone undergoing an update), the VM will not suddenly stop seeing it. |
||
− | * Any USB port managed by this controller is directly handled by the VM and can have its devices unplugged, replugged and changed without having to notify the hypervisor. |
||
− | * Libvirt will not complain if one of the USB devices you usually pass to the guest is missing when starting the VM. |
||
+ | === vfio_pci を有効化したあとに X が起動しない === |
||
− | Unlike with GPUs, drivers for most USB controllers do not require any specific configuration to work on a VM and control can normally be passed back and forth between the host and guest systems with no side effects. |
||
+ | ホスト GPU がセカンダリ GPU として認識されている場合、ゲスト GPU のドライバーをロードしようとしたときに X がエラーを起こします。Xorg の設定でホスト GPU の BusID を指定することで解決します。BusID は lspci や Xorg のログで確認できます。 |
||
− | {{Warning|Make sure your USB controller supports resetting :[[#Passing through a device that does not support resetting]]}} |
||
+ | {{hc|/etc/X11/xorg.conf.d/10-intel.conf|<nowiki> |
||
− | You can find out which PCI devices correspond to which controller and how various ports and devices are assigned to each one of them using this command : |
||
+ | Section "Device" |
||
+ | Identifier "Intel GPU" |
||
+ | Driver "modesetting" |
||
+ | BusID "PCI:0:2:0" |
||
+ | EndSection |
||
+ | </nowiki>}} |
||
+ | 詳しくは [https://www.redhat.com/archives/vfio-users/2016-August/msg00025.html] を参照してください。 |
||
− | {{hc|$ <nowiki>for usb_ctrl in $(find /sys/bus/usb/devices/usb* -maxdepth 0 -type l); do pci_path="$(dirname "$(realpath "${usb_ctrl}")")"; echo "Bus $(cat "${usb_ctrl}/busnum") --> $(basename $pci_path) (IOMMU group $(basename $(realpath $pci_path/iommu_group)))"; lsusb -s "$(cat "${usb_ctrl}/busnum"):"; echo; done</nowiki>| |
||
− | Bus 1 --> 0000:00:1a.0 (IOMMU group 4) |
||
− | Bus 001 Device 004: ID 04f2:b217 Chicony Electronics Co., Ltd Lenovo Integrated Camera (0.3MP) |
||
− | Bus 001 Device 007: ID 0a5c:21e6 Broadcom Corp. BCM20702 Bluetooth 4.0 [ThinkPad] |
||
− | Bus 001 Device 008: ID 0781:5530 SanDisk Corp. Cruzer |
||
− | Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub |
||
− | Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub |
||
+ | === Chromium が内蔵グラフィックをアクセラレーションに使わない === |
||
− | Bus 2 --> 0000:00:1d.0 (IOMMU group 9) |
||
− | Bus 002 Device 006: ID 0451:e012 Texas Instruments, Inc. TI-Nspire Calculator |
||
− | Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub |
||
− | Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub}} |
||
+ | Chromium はシステム内の GPU をできるかぎり多く検出してから使用する GPU を選択します (大抵はディスクリートの NVIDIA/AMD グラフィック)。使用する GPU は PCI デバイスによって選択されます。OpenGL レンダラが利用できるかどうかは考慮されません。結果として Chromium は内蔵 GPU を無視して、ゲスト VM が動作していてホスト環境から GPU が使えなくなっているかどうかに関係なく、{{ic|vfio-pci}} ドライバーに紐付けられた専用 GPU を使用しようとすることがあります。その場合 GPU が使えないためにソフトウェアレンダリングが使われることになります (CPU の負担が高まり、動画の再生が途切れがちになったりスクロールがスムーズに機能しなくなったりします)。 |
||
− | This laptop has 3 USB ports managed by 2 USB controllers, each with their own IOMMU group. In this example, Bus 001 manages a single USB port (with a SanDisk USB pendrive plugged into it so it appears on the list), but also a number of internal devices, such as the internal webcam and the bluetooth card. Bus 002, on the other hand, does not apprear to manage anything except for the calculator that is plugged into it. The third port is empty, which is why it does not show up on the list, but is actually managed by Bus 002. |
||
+ | 解決方法は [[Chromium 設定#特定の GPU の使用を強制する]]を見てください。 |
||
− | Once you have identified which controller manages which ports by plugging various devices into them and decided which one you want to passthrough, simply add it to the list of PCI host devices controlled by the VM in your guest configuration. No other configuration should be needed. |
||
+ | === VM がひとつしかコアを使わない === |
||
− | ===注意事項=== |
||
− | ====リセットに対応していないデバイスのパススルー==== |
||
− | When the VM shuts down, all devices used by the guest are deinitialized by its OS in preparation for shutdown. In this state, those devices are no longer functionnal and must then be power-cycled before they can resume normal operation. Linux can handle this power-cycling on its own, but when a device has no known reset methods, it remains in this disabled state and becomes unavailable. Since Libvirt and Qemu both expect all host PCI devices to be ready to reattach to the host before completely stopping the VM, when encountering a device that won't reset, they will hang in a "Shutting down" state where they will not be able to be restarted until the host system has been rebooted. It is therefore reccomanded to only pass through PCI devices which the kernel is able to reset, as evidenced by the presence of a {{ic|reset}} file in the PCI device sysfs node, such as {{ic|/sys/bus/pci/devices/0000:00:1a.0/reset}}. |
||
+ | IOMMU を有効にしてコアのカウントを 1 よりも大きくしても、VM が使用する CPU コアとスレッドがひとつしか現れないことがあります。解決するには {{ic|virt-manager}} で "Manually set CPU topology" を有効にして使用したい CPU ソケット・コア・スレッド数を設定してください。"Threads" は合計スレッド数ではなく各 CPU ごとのスレッド数なので注意してください。 |
||
− | The following bash command shows which devices can and cannot be reset. |
||
+ | === パススルーは機能しているのに出力が表示されない === |
||
− | {{hc|<nowiki>for iommu_group in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d);do echo "IOMMU group $(basename "$iommu_group")"; for device in $(\ls -1 "$iommu_group"/devices/); do if [[ -e "$iommu_group"/devices/"$device"/reset ]]; then echo -n "[RESET]"; fi; echo -n $'\t';lspci -nns "$device"; done; done</nowiki>| |
||
+ | |||
− | IOMMU group 0 |
||
+ | virt-manager を使用している場合、仮想マシンで UEFI ファームウェアが選択されていることを確認してください。また、仮想マシンに適切なデバイスが渡されていることも確認してください。 |
||
− | 00:00.0 Host bridge [0600]: Intel Corporation Xeon E3-1200 v2/Ivy Bridge DRAM Controller [8086:0158] (rev 09) |
||
+ | |||
− | IOMMU group 1 |
||
+ | === virt-manager のパーミッション問題 === |
||
− | 00:01.0 PCI bridge [0604]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port [8086:0151] (rev 09) |
||
+ | |||
− | 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GK208 [GeForce GT 720] [10de:1288] (rev a1) |
||
+ | virt-manager でパーミッションエラーが発生する場合、以下を {{ic|/etc/libvirt/qemu.conf}} に追加してください: |
||
− | 01:00.1 Audio device [0403]: NVIDIA Corporation GK208 HDMI/DP Audio Controller [10de:0e0f] (rev a1) |
||
+ | |||
− | IOMMU group 2 |
||
+ | group="kvm" |
||
− | 00:14.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller [8086:1e31] (rev 04) |
||
+ | user="''user''" |
||
− | IOMMU group 4 |
||
+ | |||
− | [RESET] 00:1a.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 [8086:1e2d] (rev 04) |
||
+ | 上記で解決しない場合は使用しているユーザーアカウントを {{ic|kvm}} と {{ic|libvirt}} [[グループ]]に追加してください。 |
||
− | IOMMU group 5 |
||
+ | |||
− | [RESET] 00:1b.0 Audio device [0403]: Intel Corporation 7 Series/C210 Series Chipset Family High Definition Audio Controller [8086:1e20] (rev 04) |
||
+ | === VM シャットダウン後にホストがロックアップする === |
||
− | IOMMU group 10 |
||
+ | |||
− | [RESET] 00:1d.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 [8086:1e26] (rev 04) |
||
+ | Windows10 ゲストを実行している場合に、VM を長時間実行した後、ホストの複数の CPU コアがロックアップするという問題が発生することがあります ([https://bbs.archlinux.org/viewtopic.php?id=206050&p=2]を参照)。この問題を解決するには、ゲストにパススルーした GPU でメッセージシグナル割り込みを有効にしてみてください。有効化する方法のガイドは [https://forums.guru3d.com/threads/windows-line-based-vs-message-signaled-based-interrupts.378044/] にあります。 |
||
− | IOMMU group 13 |
||
+ | |||
− | 06:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1) |
||
+ | === スリープ時にゲストが実行されているとホストがロックアップする === |
||
− | 06:00.1 Audio device [0403]: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1) |
||
+ | |||
− | }} |
||
+ | VFIO を有効にした仮想マシンを起動したまま、スリープ/復帰を行おうとすると不安定になることがあり、ホストマシンをシャットダウンしようとするとロックアップする既知の問題があります。以下の libvirt フックスクリプトと systemd ユニットを使用して、ゲストを実行している間にホストがスリープ状態になるのを防止することで問題を避けることができます。フックファイルの動作には実行権限が必要です。 |
||
+ | |||
+ | {{hc|/etc/libvirt/hooks/qemu|<nowiki> |
||
+ | #!/bin/bash |
||
+ | |||
+ | OBJECT="$1" |
||
+ | OPERATION="$2" |
||
+ | SUBOPERATION="$3" |
||
+ | EXTRA_ARG="$4" |
||
+ | |||
+ | case "$OPERATION" in |
||
+ | "prepare") |
||
+ | systemctl start libvirt-nosleep@"$OBJECT" |
||
+ | ;; |
||
+ | "release") |
||
+ | systemctl stop libvirt-nosleep@"$OBJECT" |
||
+ | ;; |
||
+ | esac |
||
+ | </nowiki>}} |
||
+ | |||
+ | {{hc|/etc/systemd/system/libvirt-nosleep@.service|<nowiki> |
||
+ | [Unit] |
||
+ | Description=Preventing sleep while libvirt domain "%i" is running |
||
+ | |||
+ | [Service] |
||
+ | Type=simple |
||
+ | ExecStart=/usr/bin/systemd-inhibit --what=sleep --why="Libvirt domain \"%i\" is running" --who=%U --mode=block sleep infinity |
||
+ | </nowiki>}} |
||
+ | |||
+ | === ovmf のアップグレード後にブートできない === |
||
+ | ovmf-1:r23112.018432f0ce-1 からアップグレードしたときに起動できなくなった場合、 {{ic|/var/lib/libvirt/qemu/nvram}} にある古い *VARS.fd ファイルを削除する必要があります: |
||
+ | |||
+ | # mv /var/lib/libvirt/qemu/nvram/vmname_VARS.fd /var/lib/libvirt/qemu/nvram/vmname_VARS.fd.old |
||
+ | 詳しくは {{Bug|57825}} を参照。 |
||
− | This signals that the xHCI USB controller in 00:14.0 cannot be reset and will therefore stop the VM from shutting down properly, while the integrated sound card in 00:1b.0 and the other two controllers in 00:1a.0 and 00:1d.0 do not share this problem and can be passed without issue. |
||
== 参照 == |
== 参照 == |
||
− | * [https://bbs.archlinux.org/viewtopic.php?id=162768 |
+ | * [https://bbs.archlinux.org/viewtopic.php?id=162768 Arch Linux フォーラムの議論] | [https://archive.is/kZYMt アーカイブリンク] |
− | * [https://docs.google.com/spreadsheet/ccc?key=0Aryg5nO-kBebdFozaW9tUWdVd2VHM0lvck95TUlpMlE |
+ | * [https://docs.google.com/spreadsheet/ccc?key=0Aryg5nO-kBebdFozaW9tUWdVd2VHM0lvck95TUlpMlE ユーザーによるハードウェア互換リスト] |
− | * [ |
+ | * [https://pastebin.com/rcnUZCv7 https://www.youtube.com/watch?v=37D2bRsthfI のサンプルスクリプト] |
− | * [ |
+ | * [https://vfio.blogspot.com/ PCI パススルーの完全なチュートリアル] |
− | * [https://www.redhat.com/archives/vfio-users/ VFIO users |
+ | * [https://www.redhat.com/archives/vfio-users/ VFIO users メーリングリスト] |
− | * [ |
+ | * [ircs://chat.freenode.net/vfio-users #vfio-users on freenode] |
+ | * [https://www.youtube.com/watch?v=aLeWg11ZBn0 YouTube: Level1Linux - Ryzen による GPU パススルー] |
||
+ | * [https://www.reddit.com/r/VFIO /r/VFIO: VFIOについての subreddit] |
2023年9月2日 (土) 22:11時点における最新版
Open Virtual Machine Firmware (OVMF) は仮想マシンで UEFI を使えるようにするプロジェクトです。Linux 3.9 以上と最近のバージョンの QEMU では、グラフィックカードをパススルーすることが可能で、仮想マシンでネイティブと同じグラフィック性能を発揮することができ、グラフィック性能が要求されるタスクにおいて便利です。
デスクトップコンピュータに使用していない GPU が接続されている場合 (内蔵 GPU や古い OEM カードでもかまいません、ブランドが一致している必要はありません)、ハードウェアがサポートしていれば (#要件を参照)、あらゆる OS の仮想マシンで専用 GPU として(ほぼ)最大限の性能を活用できます。技術的な詳細は こちらのプレゼンテーション (pdf) を見てください。
目次
- 1 要件
- 2 IOMMU のセットアップ
- 3 GPU の分離
- 4 OVMF によるゲスト VM のセットアップ
- 5 パフォーマンスチューニング
- 6 特殊な構成
- 7 QEMU で libvirt を使わない
- 8 他のデバイスのパススルー
- 9 トラブルシューティング
- 9.1 Windows の仮想マシンに NVIDIA の GPU をパススルーした場合に "Error 43 : Driver failed to load"
- 9.2 CPU 例外によってクラッシュが発生する
- 9.3 Windows の仮想マシンを起動したときに "System Thread Exception Not Handled"
- 9.4 ビデオカードの HDMI 出力からの音声がおかしい
- 9.5 intel_iommu を有効にしたときにホスト側で HDMI から音声が出力されない
- 9.6 vfio_pci を有効化したあとに X が起動しない
- 9.7 Chromium が内蔵グラフィックをアクセラレーションに使わない
- 9.8 VM がひとつしかコアを使わない
- 9.9 パススルーは機能しているのに出力が表示されない
- 9.10 virt-manager のパーミッション問題
- 9.11 VM シャットダウン後にホストがロックアップする
- 9.12 スリープ時にゲストが実行されているとホストがロックアップする
- 9.13 ovmf のアップグレード後にブートできない
- 10 参照
要件
VGA パススルーでは最先端の技術を使っているため、あなたのハードウェアでは使用できない可能性があります。パススルーを行うには以下の要件が満たされていなければなりません:
- CPU がハードウェア仮想化 (KVM) と IOMMU (パススルー) をサポートしていること。
- Intel の対応 CPU リスト (Intel VT-x と Intel VT-d)
- Bulldozer 世代以降 (Zen も含む) の AMD 製 CPU は全て対応しています。
- マザーボードが IOMMU をサポートしていること。
- チップセットと BIOS の両方が対応している必要があります。対応しているかどうかすぐに判断することはできませんが、Xen wiki の対応ハードウェアリスト や Wikipedia の対応リストが存在します。
- ゲスト GPU ROM が UEFI をサポートしていること。
- このリストに載っている ROM に使用している GPU が存在し UEFI をサポートしていると書かれていれば、問題ありません。2012年以降の GPU はサポートされているはずです。Windows 8 との互換性があると売り出すには UEFI のサポートが要件だと Microsoft が決めたためです。
使用していないモニターやマウス、キーボードがあれば、それも仮想マシンに割り当てることができます (GPU はディスプレイが接続されていないと何も出力することができず Spice 接続では性能が上がりません)。何か問題が発生した場合でも、スペアの機材があればホストマシンは制御できます。
IOMMU のセットアップ
IOMMU によって PCI パススルーや障害または悪意あるデバイスからのメモリ保護機能を使うことができます。Wikipedia:Input-output memory management unit#Advantages や Memory Management (computer programming): Could you explain IOMMU in plain English? を参照してください。
IOMMU の有効化
AMD-Vi/Intel VT-d が CPU によってサポートされていること、BIOS の設定で AMD-VI/VT-d が有効化されていることを確認してください。通常は他の CPU 機能と一緒に設定が並んでいるはずです (オーバークロック関連のメニューに存在することもあります)。設定における名前は機能名 ("Vt-d" あるいは "AMD-Vi") だったり、あるいは "Virtualization technology" などの曖昧な単語だったりします。マニュアルに載っていない場合もあります。
使用している CPU に応じて適切なカーネルパラメータを設定し、 IOMMU を有効にしてください:
- Intel 製の CPU (VT-d) であれば
intel_iommu=on
を設定 - AMD 製の CPU (AMD-Vi) ではカーネルが BIOS から IOMMU のサポートを検出し、自動で有効化されます
iommu=pt
パラメータも追加してください。このパラメータによって Linux がパススルーしないデバイスに触らないようにすることができます。
再起動して、dmesg で IOMMU が有効になっていることを確認してください:
dmesg|grep -e DMAR -e IOMMU
[ 0.000000] ACPI: DMAR 0x00000000BDCB1CB0 0000B8 (v01 INTEL BDW 00000001 INTL 00000001) [ 0.000000] Intel-IOMMU: enabled [ 0.028879] dmar: IOMMU 0: reg_base_addr fed90000 ver 1:0 cap c0000020660462 ecap f0101a [ 0.028883] dmar: IOMMU 1: reg_base_addr fed91000 ver 1:0 cap d2008c20660462 ecap f010da [ 0.028950] IOAPIC id 8 under DRHD base 0xfed91000 IOMMU 1 [ 0.536212] DMAR: No ATSR found [ 0.536229] IOMMU 0 0xfed90000: using Queued invalidation [ 0.536230] IOMMU 1 0xfed91000: using Queued invalidation [ 0.536231] IOMMU: Setting RMRR: [ 0.536241] IOMMU: Setting identity map for device 0000:00:02.0 [0xbf000000 - 0xcf1fffff] [ 0.537490] IOMMU: Setting identity map for device 0000:00:14.0 [0xbdea8000 - 0xbdeb6fff] [ 0.537512] IOMMU: Setting identity map for device 0000:00:1a.0 [0xbdea8000 - 0xbdeb6fff] [ 0.537530] IOMMU: Setting identity map for device 0000:00:1d.0 [0xbdea8000 - 0xbdeb6fff] [ 0.537543] IOMMU: Prepare 0-16MiB unity mapping for LPC [ 0.537549] IOMMU: Setting identity map for device 0000:00:1f.0 [0x0 - 0xffffff] [ 2.182790] [drm] DMAR active, disabling use of stolen memory
グループが正しいことを確認
以下のスクリプトを使うことで PCI デバイスが IOMMU グループにどのようにマッピングされたか確認できます。何も出力が返ってこない場合、IOMMU のサポートが有効になっていないかハードウェアが IOMMU をサポートしていないかのどちらかです。
#!/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;
出力の例:
IOMMU Group 0 00:00.0 Host bridge [0600]: Intel Corporation 2nd Generation Core Processor Family DRAM Controller [8086:0104] (rev 09) IOMMU Group 1 00:16.0 Communication controller [0780]: Intel Corporation 6 Series/C200 Series Chipset Family MEI Controller #1 [8086:1c3a] (rev 04) IOMMU Group 2 00:19.0 Ethernet controller [0200]: Intel Corporation 82579LM Gigabit Network Connection [8086:1502] (rev 04) IOMMU Group 3 00:1a.0 USB controller [0c03]: Intel Corporation 6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2 [8086:1c2d] (rev ...
IOMMU グループは仮想マシンにパススルーすることができる一番小さい単位の物理デバイスのセットです。例えば、上記の例の場合、06:00.0 の GPU と 6:00.1 のオーディオコントローラは IOMMU グループ13に属しており、両方一緒にしかパススルーすることができません。フロントの USB コントローラは USB 拡張コントローラ (グループ10) やリアの USB コントローラ (グループ4) と分かれているグループ (グループ2) なので、他のデバイスに影響を与えないで仮想マシンにパススルーすることができます。
注意事項
独立していない CPU ベースの PCIe スロットにゲスト GPU を接続した場合
全ての PCI-E スロットは同じではありません。ほとんどのマザーボードでは PCIe スロットには CPU 由来のものと PCH 由来のものがあります。CPU によっては、プロセッサ由来の PCIe スロットは隔離することができず、その場合 PCI スロットは接続されているデバイスと一緒にグループ化されてしまいます。
IOMMU Group 1 00:01.0 PCI bridge: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port (rev 09) IOMMU Group 1 01:00.0 VGA compatible controller: NVIDIA Corporation GM107 [GeForce GTX 750] (rev a2) IOMMU Group 1 01:00.1 Audio device: NVIDIA Corporation Device 0fbc (rev a1)
上記のようにゲスト GPU しか含まれていない場合は問題ありません。他の PCIe スロットに接続した場合や CPU や PCH の配置によって、同じグループに他のデバイスが含まれる場合、そのデバイスも一緒にパススルーすることになります。仮想マシンにデバイスをパススルーしても問題ない場合は次に進んでください。そうでない場合、他の PCIe スロットに GPU を接続してみて他のデバイスと分離できないか試してみてください。もしくは ACS 上書きパッチをインストールする方法もありますが、こちらは欠点があります。詳しくは #IOMMU グループのバイパス (ACS 上書きパッチ) を参照してください。
GPU の分離
デバイスを仮想マシンに割り当てるには、ホストマシンとの干渉を避けるためにこのデバイスと同じ IOMMU グループを共有する全てのデバイスがスタブドライバまたは VFIO ドライバに置き換えられている必要があります。この処理はほとんどのデバイスでは VM が起動する直前に行われます。
しかし、GPU ドライバーは巨大で複雑なため、動的な再バインドはあまりサポートされておらず、ホストの GPU を仮想マシンにお互いのドライバーが衝突すること無く透過的にパススルーすることは通常できません。 VM が起動する前に代わりのドライバーに GPU を手動でバインドし、他のドライバーが GPU を使用できないようにすることを推奨します。
続くセクションでは、代わりのドライバーがブートプロセスの早期にバインドされるように GPU を構成する詳細な方法を記載します。これにより VM が要求するかドライバーがスイッチバックされるまでデバイスは活動を停止します。これは一旦システムが完全にオンラインになってからドライバを切り替えるよりも問題が少なく、好ましい方法と言えます。2つの方法が存在しますが、使用しているカーネルがサポートしている場合は vfio-pci を使用することが推奨されます。
Linux 4.1 から、カーネルには vfio-pci が含まれており、pci-stub と同じような機能を持ちながら、使用していないときはデバイスを D3 状態にするなどの機能が追加されています。
vfio-pci は基本的に PCI デバイスを ID で指定するため、パススルーしたいデバイスの ID を指定する必要があります。以下の IOMMU グループの場合、vfio-pci を 10de:13c2
と 10de:0fbb
にバインドします。
IOMMU Group 13 06:00.0 VGA compatible controller: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1) IOMMU Group 13 06:00.1 Audio device: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1)}}
モジュールとして vfio-pci をロード
linux カーネルには組み込みモジュールとして vfio-pci が含まれていないため、設定でロードさせる必要があります。
ベンダーとデバイス ID を vfio-pci に渡されるデフォルトパラメータに追加します:
/etc/modprobe.d/vfio.conf
options vfio-pci ids=10de:13c2,10de:0fbb
上記の設定だけでは vfio-pci が他のグラフィックドライバーよりも前にロードされるとは限りません。必ずロードされるようにするには、カーネルイメージの中で静的にバインドされるようにする必要があります。vfio_pci
, vfio
, vfio_iommu_type1
, vfio_virqfd
を mkinitcpio にこの順番で追加してください:
/etc/mkinitcpio.conf
MODULES=(... vfio_pci vfio vfio_iommu_type1 vfio_virqfd ...)
さらに、mkinitcpio.conf
の HOOKS リストに modconf フックを追加してください:
/etc/mkinitcpio.conf
HOOKS=(... modconf ...)
新しいモジュールを initramfs に追加したら、initramfs を再生成する必要があります。/etc/modprobe.d/vfio.conf
でデバイスの ID を変更した場合も、initramfs を再生成してください。パラメータは起動の初期段階で initramfs で指定される必要があります。
カーネルに vfio-pci が組み込まれている場合
vfio-pci モジュールを組み込んだカーネルを使っている場合、以下のようにカーネルパラメータでデバイス ID を指定することで GPU を分離できます:
vfio-pci.ids=10de:13c2,10de:0fbb
設定を確認
再起動して vfio-pci が正しくロードされ適切なデバイスがバインドされていることを確認:
$ dmesg | grep -i vfio
[ 0.329224] VFIO - User Level meta-driver version: 0.3 [ 0.341372] vfio_pci: add [10de:13c2[ffff:ffff]] class 0x000000/00000000 [ 0.354704] vfio_pci: add [10de:0fbb[ffff:ffff]] class 0x000000/00000000 [ 2.061326] vfio-pci 0000:06:00.0: enabling device (0100 -> 0103)
vfio.conf
の全てのデバイス (期待するデバイスであっても) が dmesg に出力される必要はありません。起動時にデバイスが出力に現れなくてもゲスト VM から問題なく使うことができます。
$ lspci -nnk -d 10de:13c2
06:00.0 VGA compatible controller: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1) Kernel driver in use: vfio-pci Kernel modules: nouveau nvidia
$ lspci -nnk -d 10de:0fbb
06:00.1 Audio device: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1) Kernel driver in use: vfio-pci Kernel modules: snd_hda_intel
OVMF によるゲスト VM のセットアップ
OVMF は QEMU 仮想マシン用のオープンソース UEFI ファームウェアです。SeaBIOS を使うことでも PCI パススルーと同じような結果を得ることはできますが、セットアップ手順が異なります。一般的にはハードウェアがサポートしているのであれば EFI を使用する方法を推奨します。
libvirt の設定
libvirt は様々な仮想化ユーティリティのラッパーであり、仮想マシンの設定とデプロイを簡単にします。KVM と QEMU の場合、フロントエンドを使用することで QEMU 用にパーミッションを設定する必要がなくなり簡単に様々なデバイスを仮想マシンに追加・削除できます。ラッパーと名乗ってはいますが、QEMU の最新機能全てをサポートしているわけではありません。QEMU の引数を追加するためにラッパースクリプトを使用する必要がある場合もあります。
qemu, libvirt, ovmf[リンク切れ: 置換パッケージ: edk2-ovmf], virt-manager をインストールしてから、OVMF ファームウェアイメージとランタイム変数テンプレートのパスを libvirt の設定に追加して、virt-install
や virt-manager
が認識できるようにしてください:
/etc/libvirt/qemu.conf
nvram = [ "/usr/share/ovmf/x64/OVMF_CODE.fd:/usr/share/ovmf/x64/OVMF_VARS.fd" ]
設定後、libvirtd.service
とログ出力コンポーネント virtlogd.socket
を起動・有効化します。
ゲスト OS のセットアップ
virt-manager
による仮想マシンの設定は画面上の指示に従うだけで完了します。ただし、以下のステップでは特別な注意を払う必要があります:
- 仮想マシンの作成ウィザードで VM の名前を付けるとき、"Customize before install" チェックボックスにチェックを入れてください。
- "Overview" セクションで、ファームウェアを "UEFI" に設定してください [1]。オプションがグレーになっている場合、
/etc/libvirt/qemu.conf
でファームウェアの場所が正しく指定されているか確認してください。修正した後libvirtd.service
を再起動してください。 - "CPUs" セクションで、CPU モデルを "host-passthrough" に変更してください。リストに存在しない場合、手動で入力してください。これで libvirt が CPU の機能を実際の CPU と同じように反映するようになって CPU が正しく認識されるようになります。変更しないと、一部のアプリケーションで CPU のモデルが不明だとエラーが発生します。
- IO のオーバーヘッドを抑えたい場合、"Add Hardware" から "VirtIO SCSI" モデルの SCSI ドライブのコントローラを追加してください。それからデフォルトの IDE ディスクを SCSI ディスクに変更して作成したコントローラーにバインドしてください。
- Windows の仮想マシンはデフォルトでは SCSI ドライブを認識しないため、こちら からドライバーが含まれている ISO をダウンロードして IDE (あるいは Windows 7 以上の場合は SATA) の CD-ROM ストレージデバイスを作成してダウンロードした ISO にリンクしてください。この設定を行わないとインストール時に Windows がディスクを認識できません。Windows をインストールするディスクを選択するときは、vioscsi 下の CD-ROM に含まれているドライバーをロードしてください。
他のインストールは通常と同じです。標準の QXL ビデオアダプタをウィンドウで実行します。現時点では、仮想デバイスのためのドライバーをインストールする必要はありません。ほとんどが後で削除されるためです。ゲスト OS のインストールが完了したら、仮想マシンをオフにしてください。最初の VM 起動時にインストールが始まらず UEFI メニューに戻ってしまう場合があります。場合によっては正しい ISO ファイルが自動的に認識されないために、起動ドライブを手動で指定する必要があります。 exit とタイプして "boot manager" に移動するとデバイス選択メニューに入ることができます。
PCI デバイスの接続
インストールが完了したら、libvirt でハードウェアの詳細情報を編集して spice チャンネルや仮想ディスプレイ、QXL ビデオアダプタ、マウスやキーボード、USB タブレットデバイスのエミュレートなどの仮想デバイスを削除できます。入力デバイスがなくなるので、仮想マシンに USB ホストデバイスをバインドする場合、ゲストに何かあったときは最低でもひとつのマウスやキーボードをホストに割り当ててください。ここで、先に分離しておいた PCI デバイスを接続することができます。"Add Hardware" をクリックしてパススルーしたい PCI Host Device を選択してください。問題がなければ、GPU に接続されたディスプレイが OVMF のスプラッシュ画面を表示して通常通りに VM が起動します。そこから VM のドライバーの設定をおこなってください。
Evdev でキーボード・マウスを接続
ゲスト用のスペアのマウスやキーボードを持っておらず、Spice のオーバーヘッドを避けたい場合、evdev を設定することでマウスとキーボードのコントロールをホストとゲストで切り替えることができます。まず、/dev/input/by-id/
からキーボードとマウスのデバイスを探してください。マウスやキーボードに複数のデバイスが関連付けられている場合、cat /dev/input/by-id/device_id
を試してみてキーを打ったりマウスを動かして入力が通ったかどうか確認してください。それからデバイスを設定に追加:
$ virsh edit [vmname]
... <qemu:commandline> <qemu:arg value='-object'/> <qemu:arg value='input-linux,id=mouse1,evdev=/dev/input/by-id/MOUSE_NAME'/> <qemu:arg value='-object'/> <qemu:arg value='input-linux,id=kbd1,evdev=/dev/input/by-id/KEYBOARD_NAME,grab_all=on,repeat=on'/> </qemu:commandline> ...
MOUSE_NAME
と KEYBOARD_NAME
は適切なデバイス id に置き換えてください。それから qemu の設定にデバイスを記述して、ユーザーとグループが入力デバイスにアクセスできるように設定:
/etc/libvirt/qemu.conf
... user = "<your_user>" group = "kvm" ... cgroup_device_acl = [ "/dev/kvm", "/dev/input/by-id/KEYBOARD_NAME", "/dev/input/by-id/MOUSE_NAME", "/dev/null", "/dev/full", "/dev/zero", "/dev/random", "/dev/urandom", "/dev/ptmx", "/dev/kvm", "/dev/kqemu", "/dev/rtc","/dev/hpet", "/dev/sev" ] ...
それから使用するユーザーが kvm
と input
グループにアクセスできるようにしてください。libvirtd.service
を再起動してください。これでゲスト OS を起動したら左と右の Control キーを両方同時に押すことでマウスとキーボードを切り替えることができます。
設定で PS/2 から Virtio の入力に切り替えることもできます:
$ virsh edit [vmname]
... <input type='mouse' bus='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x0e' function='0x0'/> </input> <input type='keyboard' bus='virtio'> <address type='pci' domain='0x0000' bus='0x00' slot='0x0f' function='0x0'/> </input> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> ...
ゲスト OS を起動してデバイスオン virtIO ドライバーをインストールしてください。
注意事項
OVMF ベースの VM で非 EFI イメージを使う
OVMF ファームウェアは EFI 以外のメディアの起動をサポートしていません。起動後に UEFI シェルが開かれてしまう場合、EFI ブートメディアに問題がある可能性があります。他の linux/windows イメージを使ってみてイメージに問題がないか確認してください。
パフォーマンスチューニング
PCI パススルーを使うのはビデオゲームや GPU を使用する作業など大抵パフォーマンスが重要な場合です。PCI パススルーによってネイティブの性能に近づきますが、仮想マシンを最大限活用するにはホストとゲスト両方で設定が必要です。
CPU ピニング
KVM ゲストではデフォルトでゲストから要求された操作を仮想プロセッサを表すスレッドとして実行します。スレッドは Linux のスケジューラによって他のスレッドと同じように管理され、nice 値や優先度にあわせて手隙の CPU コアに割り当てられます。スレッド切り替えにはオーバーヘッドが存在するため (コンテキストスイッチによってコアのキャッシュが強制的に変更されるため)、ゲストのパフォーマンスに悪い影響を与えます。CPU ピニングはこの問題を解決してプロセスのスケジューリングを上書きして VM のスレッドは特定のコアでのみ動作するようになります。例えば、ゲストのコア 0, 1, 2, 3 をホストの 4, 5, 6, 7 番目のコアに割り当てるには:
$ virsh edit [vmname]
... <vcpu placement='static'>4</vcpu> <cputune> <vcpupin vcpu='0' cpuset='4'/> <vcpupin vcpu='1' cpuset='5'/> <vcpupin vcpu='2' cpuset='6'/> <vcpupin vcpu='3' cpuset='7'/> </cputune> ...
ハイパースレッディングの場合
CPU がハードウェアによるマルチタスクをサポートしている場合 (Intel のチップではハイパースレッディングと呼ばれます)、CPU ピニングをする方法は2つ存在します。ハイパースレッディングは1つの CPU で2つのスレッドを効率的に動作させる手法であるため、クアッドコア CPU ならば8つの論理コアが使えます。物理コアの負担率が高い場合、論理コアは使われません。VM のスレッドを2つの物理コアに割り当てても、2つのコアが対応できる負担を超える作業では2つの論理コアの補助を得ることができません。4つのコアのうち2つのコアをパススルーしただけだからです。
以下はクアッドコアのマシンでハイパースレッディングが有効になっている場合の /proc/cpuinfo
の要約です:
$ grep -e "processor" -e "core id" -e "^$" /proc/cpuinfo
processor : 0 core id : 0 processor : 1 core id : 1 processor : 2 core id : 2 processor : 3 core id : 3 processor : 4 core id : 0 processor : 5 core id : 1 processor : 6 core id : 2 processor : 7 core id : 3
仮想マシンを使っているときにホスト側で負担が重い計算をしない場合 (あるいはホストを全く使わない場合)、仮想マシンのスレッドを全ての論理コアに固定化して、仮想マシンがコアを活用できるようにすると良いでしょう。
クアッドコアのマシンの場合、以下のようになります:
$ virsh edit [vmname]
... <vcpu placement='static'>4</vcpu> <cputune> <vcpupin vcpu='0' cpuset='4'/> <vcpupin vcpu='1' cpuset='5'/> <vcpupin vcpu='2' cpuset='6'/> <vcpupin vcpu='3' cpuset='7'/> </cputune> ... <cpu mode='custom' match='exact'> ... <topology sockets='1' cores='4' threads='1'/> ... </cpu> ...
ホストとゲストで同時に何か処理を行う場合、一部の物理コアとゲストのスレッドを固定して、後はホストでも使えるようにすると良いでしょう。
クアッドコアのマシンの場合、以下のようになります:
$ virsh edit [vmname]
... <vcpu placement='static'>4</vcpu> <cputune> <vcpupin vcpu='0' cpuset='2'/> <vcpupin vcpu='1' cpuset='6'/> <vcpupin vcpu='2' cpuset='3'/> <vcpupin vcpu='3' cpuset='7'/> </cputune> ... <cpu mode='custom' match='exact'> ... <topology sockets='1' cores='2' threads='2'/> ... </cpu> ...
静的ヒュージページ
大量のメモリを必要するアプリケーションでは、メモリの遅延が問題になることがあります。使用するメモリページ (メモリ割り当ての基本単位) が増えれば増えるほど、複数のメモリページにまたがる情報にアプリケーションがアクセスするようになる確立が高まります。メモリページの実際のアドレスを解決するには複数のステップを踏まないとならないため、大抵の場合 CPU は最近使用されたメモリページの情報をキャッシュすることで同一ページの使用を高速化します。しかしながらアプリケーションが大量のメモリを使うとすると問題です。例えば仮想マシンが使用する 4GB のメモリが (メモリページのデフォルトサイズである) 4kB に分割されるような場合、頻繁にキャッシュミスが発生することになりメモリの遅延を増大させてしまいます。このような問題を緩和するためにヒュージページが存在します。大きなサイズのページをアプリケーションに割り当てることで、同一ページが使用される可能性を高めます。通常は必要に応じてヒュージページを動的に管理する、透過的ヒュージページが使用されます。
しかしながら仮想マシンで PCI パススルーを使う場合は透過ヒュージページは意味がありません。IOMMU がゲストのメモリ割り当てを必要とし仮想マシンが起動するとすぐに固定化されるためです。したがってヒュージページの効果を得るには静的に割り当てる必要があります。
起動時にヒュージページを割り当てるには、カーネルコマンドラインで hugepages=x
を使って適切な量を指定します。例えば hugepages=1024
として1024ページを予約すると、ヒュージページあたりデフォルトで 2048kB のサイズが割り当てられるため、仮想マシンが使用するための 2GB 分のメモリが作成されます。
CPU がサポートしていれば手動でページサイズを設定できます。grep pdpe1gb /proc/cpuinfo
を実行することで 1 GB のヒュージページがサポートされているか確認できます。カーネルパラメータで 1 GB のヒュージページサイズを設定するには: default_hugepagesz=1G hugepagesz=1G hugepages=X transparent_hugepage=never
。
また、静的ヒュージページは要求を行ったアプリケーションだけが使用できるため、libvirt のドメイン設定に kvm が割り当てたヒュージページを活用するように設定を追加する必要があります:
$ virsh edit [vmname]
... <memoryBacking> <hugepages/> </memoryBacking> ...
CPU 周波数ガバナー
CPU ガバナーの設定によっては、仮想マシンのスレッドによって周波数が引き上がる閾値まで CPU の負担が達しないことがあります。KVM が自力で CPU の周波数を変更することはできないため、CPU の使用率が思うように上がらないとパフォーマンスが出ないという問題になる可能性があります。ゲスト側で CPU 負担が重い作業を実行している間に watch lscpu
によって報告される周波数に変化があるかどうか確認してみてください。周波数が最大値まで上がらない場合、CPU スケーリングがホスト OS によって制御されている ことが原因かもしれません。その場合、全てのコアを最大周波数に設定してみてパフォーマンスが改善しないか確認してください。最新の Intel 製チップをデフォルトの P-State ドライバーで使用している場合、cpupower コマンドは効果がないため、/proc/cpuinfo
を監視して CPU が最大周波数になっていることを確認してください。
AMD CPU でパフォーマンスを改善する
以前は AMD 環境では Nested Page Tables (NPT) を無効化することで KVM の GPU 性能を引き上げることができました。これは 非常に古いバグ が原因で、トレードオフとして CPU の性能が落ちて、がたつきが発生することがありました。
カーネル 4.14 と 4.9 から問題を解決する カーネルパッチ がマージされています。公式の linux または linux-lts カーネルを使用している場合、パッチは既に適用されています (最新版のカーネルを使っていることを確認してください)。他のカーネルを使っている場合は手動でパッチを適用する必要があります。
QEMU 3.1 から TOPOEXT cpuid フラグはデフォルトで無効になっています。AMD の CPU でハイパースレッディングを使うには手動で有効にする必要があります:
<cpu mode='host-passthrough' check='none'> <topology sockets='1' cores='4' threads='2'/> <feature policy='require' name='topoext'/> </cpu>
コミット: https://git.qemu.org/?p=qemu.git;a=commit;h=7210a02c58572b2686a3a8d610c6628f87864aed
特殊な構成
特定の構成では特別な設定が必要になります。ホストあるいは VM が正しく動作しない場合、あなたのシステムが以下のどれかにあてはまっていないか確認してください。
ゲストとホストで同じ GPU を使う
pci-stub と vfio-pci はどちらもベンダー・デバイス id の組み合わせを使って起動時にバインドするデバイスを認識するため、同じ ID の GPU が2つある場合、パススルードライバーをどちらか片方にバインドできません。スクリプトを使って driver_override
の pci バスアドレスによって割り当てる必要があります。
スクリプトを作成して vfio-pci をブート GPU 以外の全ての GPU にバインドすることができます。/usr/bin/vfio-pci-override.sh
スクリプトを作成:
#!/bin/sh for i in /sys/bus/pci/devices/*/boot_vga; do if [ $(cat "$i") -eq 0 ]; then GPU="${i%/boot_vga}" AUDIO="$(echo "$GPU" | sed -e "s/0$/1/")" echo "vfio-pci" > "$GPU/driver_override" if [ -d "$AUDIO" ]; then echo "vfio-pci" > "$AUDIO/driver_override" fi fi done modprobe -i vfio-pci
/etc/modprobe.d/vfio.conf
を以下の内容で作成:
install vfio-pci /usr/bin/vfio-pci-override.sh
/etc/mkinitcpio.conf
を編集:
MODULES からビデオドライバーを全て削除して vfio-pci
と vfio_iommu_type1
を追加してください:
MODULES=(ext4 vfat vfio-pci vfio_iommu_type1)
/etc/modprobe.d/vfio.conf
と /usr/bin/vfio-pci-override.sh
を FILES に追加してください:
FILES=(/etc/modprobe.d/vfio.conf /usr/bin/vfio-pci-override.sh)
initramfs を再生成して再起動してください:
# mkinitcpio -p linux
ブート GPU をゲストにパススルー
PCI パススルーをするときに boot_vga
とマークされた GPU は特殊なケースになります。ブートメッセージや BIOS の設定メニューなどを表示するのに BIOS がその GPU を必要とするためです。ブート GPU はパススルー時に 自由に改造できる VGA ブート ROM のコピー を作成します。システムから認識されるのは改造されたコピーになり、パススルードライバーによって不正な GPU として拒否される可能性があります。一般的には BIOS の設定でブート GPU を変更して代わりにホスト GPU を使用するか、あるいはそれが不可能な場合、マシンのホストとゲストのカードを交換することが推奨されます。
IOMMU グループのバイパス (ACS 上書きパッチ)
パススルーしたくない PCI デバイスもグループに入ってしまっている場合、Alex Williamson の ACS override パッチを使うことでデバイスを分離できます。その場合は 危険性 を承知してください。
パッチが適用されたカーネルが必要になります。linux-vfioAUR パッケージでカーネルをインストールするのが一番簡単です。
さらに、ACS override パッチはカーネルのコマンドラインオプションで有効にしなければなりません。パッチファイルは以下のドキュメントを追加します:
pcie_acs_override = [PCIE] Override missing PCIe ACS support for: downstream All downstream ports - full ACS capabilties multifunction All multifunction devices - multifunction ACS subset id:nnnn:nnnn Specfic device - full ACS capabilities Specified as vid:did (vendor/device ID) in hex
通常は pcie_acs_override=downstream
オプションで上手くいきます。
インストールと設定が終わったら、ブートローダーのカーネルパラメータを再設定して pcie_acs_override=
オプションが有効になった状態で新しいカーネルをロードするようにしてください。
QEMU で libvirt を使わない
libvirt を使って仮想マシンをセットアップするかわりに、QEMU コマンドにカスタムパラメータを付けるだけで PCI パススルーを使用するように VM を起動できます。スクリプトによる設定などで有用です。
#IOMMU のセットアップと#GPU の分離を行ってから、QEMU の記事に従って仮想環境をセットアップして、KVM を有効にして -device vfio-pci,host=07:00.0
フラグを使ってください。識別子の (07:00.0) は GPU を分離するときに使用した実際のデバイスの ID に置き換えてください。
OVMF ファームウェアを利用するために、ovmf[リンク切れ: 置換パッケージ: edk2-ovmf] パッケージをインストールして、/usr/share/ovmf/x64/OVMF_VARS.fd
から /tmp/MY_VARS.fd
など一時的なディレクトリに UEFI 変数をコピーして QEMU コマンドに以下のパラメータを追加して OVMF のパスを指定します (パラメータの順序は重要です):
-drive if=pflash,format=raw,readonly,file=/usr/share/ovmf/x64/OVMF_CODE.fd
- OVMF ファームウェアバイナリを指定、readonly オプションに注意してください。-drive if=pflash,format=raw,file=/tmp/MY_VARS.fd
- 変数のパスを指定。
QEMU の記事を読んで virtio ドライバーの使用などパフォーマンスを向上させることができる設定を調べることを推奨します。
また、-cpu host,kvm=off
パラメータを使ってホストの CPU モデル情報を VM に渡して Nvidia などメーカーのデバイスドライバーから仮想環境でないと認識させる必要があるかもしれません。
他のデバイスのパススルー
USB コントローラ
マザーボードに接続された複数の USB コントローラが複数のグループにマッピングされている場合、USB デバイスの代わりに USB コントローラをパススルーすることができます。個別の USB デバイスではなくコントローラをパススルーすることには以下の利点があります:
- 特定の操作 (スマートフォンのアップデートなど) でデバイスが切断されたり ID が変わったりしても、仮想マシンから突然認識されなくなることはありません。
- コントローラによって管理されている USB 端子を VM が直接扱うため、デバイスを接続・切断してもハイパーバイザに通知する必要がありません。
- VM を起動したときにゲストにパススルーする USB デバイスがなくなってしまっていても Libvirt はエラーを出力しません。
GPU と違って、大抵の USB コントローラのドライバーでは VM で使用するのに特殊な設定を必要としません。副作用を起こさずにホストとゲストの間で制御を受け渡すことができます。
以下のコマンドを使うことでコントローラや端子とデバイスがどのように PCI デバイスと割り当てられているか確認することができます:
$ for usb_ctrl in $(find /sys/bus/usb/devices/usb* -maxdepth 0 -type l); do pci_path="$(dirname "$(realpath "${usb_ctrl}")")"; echo "Bus $(cat "${usb_ctrl}/busnum") --> $(basename $pci_path) (IOMMU group $(basename $(realpath $pci_path/iommu_group)))"; lsusb -s "$(cat "${usb_ctrl}/busnum"):"; echo; done
Bus 1 --> 0000:00:1a.0 (IOMMU group 4) Bus 001 Device 004: ID 04f2:b217 Chicony Electronics Co., Ltd Lenovo Integrated Camera (0.3MP) Bus 001 Device 007: ID 0a5c:21e6 Broadcom Corp. BCM20702 Bluetooth 4.0 [ThinkPad] Bus 001 Device 008: ID 0781:5530 SanDisk Corp. Cruzer Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Bus 2 --> 0000:00:1d.0 (IOMMU group 9) Bus 002 Device 006: ID 0451:e012 Texas Instruments, Inc. TI-Nspire Calculator Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
上記のノートパソコンには2つの USB コントローラによる3つの USB ポートがあり、それぞれに IOMMU グループが存在します。例として Bus 001 はひとつの USB ポートを管理していますが (SanDisk の USB ペンドライブが接続されています)、内蔵ウェブカメラや bluetooth カードなど内部デバイスも管理されています。一方 Bus 002 は接続されている電卓以外は何も管理していません。3つ目のポートは空で、リスト上には表示されていませんが、実際は Bus 002 によって管理されています。
様々なデバイスを接続してみてどのコントローラがどのポートを管理しているか判断して、どのコントローラをパススルーするか決めたら、ゲスト設定の VM によって制御する PCI ホストデバイスのリストにコントローラを追加してください。他の設定は不要です。
PulseAudio で仮想マシンの音声出力をホストにパススルー
libvirt を使うことで仮想マシンの音声出力をアプリケーションとしてホストに転送することが可能です。複数の音声ストリームをホストの出力に転送でき、パススルーをサポートしていない音声出力デバイスで使うことができます。転送するには PulseAudio が必要です。
まず、#user = ""
行のコメントを削除してください。それからクォートの中にユーザー名を入力してください。これで QEMU はユーザーの PulseAudio ストリームを転送するようになります。
/etc/libvirt/qemu.conf
user = "example"
次に、libvirt の設定を変更してください。
以下の行を:
virsh edit [vmname]
<domain type='kvm'>
以下のように変更してください:
virsh edit [vmname]
<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
そして libvirt の xml ファイルの末尾に QEMU PulseAudio 環境変数を設定してください。
以下の行を:
virsh edit [vmname]
</devices> </domain>
以下のように変更してください:
virsh edit [vmname]
</devices> <qemu:commandline> <qemu:env name='QEMU_AUDIO_DRV' value='pa'/> <qemu:env name='QEMU_PA_SERVER' value='/run/user/1000/pulse/native'/> </qemu:commandline> </domain>
user ディレクトリの 1000 はあなたが使用しているユーザーの uid に置き換えてください (id
コマンドを実行することで確認できます)。先に進む前にファイルを保存して終了しないと変更が登録されません。終了後に Domain [vmname] XML configuration edited.
というメッセージが表示されれば、変更が適用されたということです。
設定したら libvirtd
サービスと pulseaudio.service
のユーザーサービスを再起動してください。
これで仮想マシンの音声出力はアプリケーションとしてホストに転送されるようになります。pavucontrol アプリケーションを使うことで出力デバイスを制御できます。Windows ゲストの場合、メッセージシグナル割り込みを使用しないとノイズが発生するので注意してください。
QEMU 3.0 オーディオの変更
QEMU 3.0 以降では、オーディオパッチの一部がマージされました (reddit リンク)。パッチのいくつかはまだ正式に上流にマージされていないため、 qemu-patchedAUR[リンク切れ: パッケージが存在しません] パッケージにはオーディオパッチが複数含まれています。
新しいコードパスを使用するにはあなたの VM のセットアップに応じてチップセットを、例えば pc-q35-3.0
または pc-i440fx-3.0
(qemu 3.0 インストール後) に変更する必要があります:
$ virsh edit [vmname]
<domain type='kvm'> ... <os> <type arch='x86_64' machine='pc-q35-3.0'>hvm</type> ... </os>
$ virsh edit [vmname]
<domain type='kvm'> ... <os> <type arch='x86_64' machine='pc-i440fx-3.0'>hvm</type> ... </os>
注意事項
リセットに対応していないデバイスのパススルー
仮想マシンのシャットダウン時、ゲストが使用していたデバイスは全てシャットダウンの準備時に OS によって deinitialize されます。この状態ではデバイスは機能しなくなり、通常通りに機能させるには電源を入れ直さなくてはなりません。Linux は独自にパワーサイクルを処理しますが、デバイスのリセット方法がわからない場合、無効状態のままになりデバイスが利用不可能になります。Libvirt と Qemu はどちらも仮想マシンを完全に停止する前に全てのホスト PCI デバイスが再接続できる状態になっていることを求めるため、デバイスがリセットできない状態になると、"Shutting down" 状態でフリーズしてホストマシンを再起動するまで仮想マシンを再起動できなくなってしまいます。そのため、カーネルによってリセットが可能な PCI デバイスのみパススルーすることを推奨します。PCI デバイスの sysfs ノードに reset
ファイルが存在するかどうかでリセット可能かどうか確認できます (例: /sys/bus/pci/devices/0000:00:1a.0/reset
)。
以下の bash コマンドを実行するとどのデバイスがリセットできてどのデバイスがリセットできないか表示されます:
for iommu_group in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d);do echo "IOMMU group $(basename "$iommu_group")"; for device in $(\ls -1 "$iommu_group"/devices/); do if [[ -e "$iommu_group"/devices/"$device"/reset ]]; then echo -n "[RESET]"; fi; echo -n $'\t';lspci -nns "$device"; done; done
IOMMU group 0 00:00.0 Host bridge [0600]: Intel Corporation Xeon E3-1200 v2/Ivy Bridge DRAM Controller [8086:0158] (rev 09) IOMMU group 1 00:01.0 PCI bridge [0604]: Intel Corporation Xeon E3-1200 v2/3rd Gen Core processor PCI Express Root Port [8086:0151] (rev 09) 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation GK208 [GeForce GT 720] [10de:1288] (rev a1) 01:00.1 Audio device [0403]: NVIDIA Corporation GK208 HDMI/DP Audio Controller [10de:0e0f] (rev a1) IOMMU group 2 00:14.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB xHCI Host Controller [8086:1e31] (rev 04) IOMMU group 4 [RESET] 00:1a.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 [8086:1e2d] (rev 04) IOMMU group 5 [RESET] 00:1b.0 Audio device [0403]: Intel Corporation 7 Series/C210 Series Chipset Family High Definition Audio Controller [8086:1e20] (rev 04) IOMMU group 10 [RESET] 00:1d.0 USB controller [0c03]: Intel Corporation 7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 [8086:1e26] (rev 04) IOMMU group 13 06:00.0 VGA compatible controller [0300]: NVIDIA Corporation GM204 [GeForce GTX 970] [10de:13c2] (rev a1) 06:00.1 Audio device [0403]: NVIDIA Corporation GM204 High Definition Audio Controller [10de:0fbb] (rev a1)
上記の場合 00:14.0 の xHCI USB コントローラはリセットができないため、仮想マシンが正しくシャットダウンできなくなります。00:1b.0 の内蔵サウンドカードと 00:1a.0 および 00:1d.0 のコントローラはリセット可能であるため問題が起こりません。
トラブルシューティング
以下で問題が見つけられない場合、QEMU#トラブルシューティングも見てください。
Windows の仮想マシンに NVIDIA の GPU をパススルーした場合に "Error 43 : Driver failed to load"
バージョン 337.88 から、Windows の Nvidia ドライバーはハイパーバイザが動作しているかどうかを確認して、動作していることを認識すると Windows のデバイスマネージャに Error 43 を吐くようになりました。QEMU 2.5.0 と libvirt 1.3.3 以上では、ハイパーバイザの vendor_id を偽装することができ、Nvidia ドライバーを騙してロードさせることができます。QEMU コマンドの cpu パラメータに hv_vendor_id=whatever
を追加するか、libvirt のドメイン設定に以下の行を追加するだけです。ID は12文字ちょうどの英数字 (例: '1234567890ab') に設定してください。
$ virsh edit [vmname]
... <features> <hyperv> ... <vendor_id state='on' value='whatever'/> ... </hyperv> ... <kvm> <hidden state='on'/> </kvm> </features> ...
古いバージョンの QEMU や libvirt を使用している場合は、ハイパーバイザの拡張を無効化する必要があり、かなり性能が落ちてしまいます。libvirt のドメイン設定ファイルに以下を記述してください:
$ virsh edit [vmname]
... <features> <hyperv> <relaxed state='on'/> <vapic state='on'/> <spinlocks state='on' retries='8191'/> </hyperv> ... </features> ... <clock offset='localtime'> <timer name='hypervclock' present='yes'/> </clock> ...
... <clock offset='localtime'> <timer name='hypervclock' present='no'/> </clock> ... <features> <kvm> <hidden state='on'/> </kvm> ... <hyperv> <relaxed state='off'/> <vapic state='off'/> <spinlocks state='off'/> </hyperv> ... </features> ...
VM を起動した後に dmesg に "BAR 3: can't reserve [mem]" エラーが表示される
上記の方法を試してもコード 43 が発生する場合、dmesg にメモリ予約エラーが記録されていないか確認してください:
vfio-pci 0000:09:00.0: BAR 3: can't reserve [mem 0xf0000000-0xf1ffffff 64bit pref]
上記のようなメッセージが出力される場合、グラフィックカードを接続している PCI ブリッジを確認してください。以下のコマンドでデバイスツリーを確認できます:
$ lspci -t
VM を起動する前に以下のコマンドを実行してください (ID は上記のコマンドで確認できた実際の ID に置き換えてください):
# echo 1 > /sys/bus/pci/devices/0000\:00\:03.1/remove # echo 1 > /sys/bus/pci/rescan
詳しくは こちらの記事 を参照。
CPU 例外によってクラッシュが発生する
QEMU#特定の Windows のゲームやアプリケーションでクラッシュやブルスクリーンが発生するを参照。
Windows の仮想マシンを起動したときに "System Thread Exception Not Handled"
QEMU#Windows の仮想マシンを起動したときに "System Thread Exception Not Handled" を参照。
ビデオカードの HDMI 出力からの音声がおかしい
ビデオカードの HDMI 端子を使用したときに、ユーザーによっては仮想マシンの音声出力が遅れたり音が割れたりすることがあります。大抵の場合、グラフィックも遅れるようになります。解決方法としてはデフォルトの割り込み方法 (Line-Based Interrupts) の代わりに MSI (Message Signaled-Based Interrupts) を有効にする方法があります。
MSI がサポートされているか・有効になっているか確認するには、以下のコマンドを root で実行してください:
# lspci -vs $device | grep 'MSI:'
`$device` はカードのアドレスに置き換えてください (例: `01:00.0`)。
出力は以下のようになります:
Capabilities: [60] MSI: Enable- Count=1/1 Maskable- 64bit+
Enable
の後ろの -
は MSI がサポートされおり VM によって使われていないことを意味します。+
であれば VM によって使われています。
有効にする手順は非常に複雑です。こちら に設定の手順と概要が載っています。
他にも lime-technology の wiki や VFIO tips and tricks の記事にヒントが載っています。
MSI Utility (FOSS Version 2) という UI ツールが64ビットの Windows 10 で動作しこの手順を簡素化します。
nVidia カードの 0 function の MSI を有効にするだけでは問題が解決しない場合 (01:00.0 VGA compatible controller: NVIDIA Corporation GM206 [GeForce GTX 960] (rev a1) (prog-if 00 [VGA controller])
)、他の function の MSI も有効にする必要があります (01:00.1 Audio device: NVIDIA Corporation Device 0fba (rev a1)
)。
intel_iommu を有効にしたときにホスト側で HDMI から音声が出力されない
intel_iommu
を有効にしたときにホストの Intel GPU の HDMI 出力デバイスが使えなくなった場合、igfx_off
(i.e. intel_iommu=on,igfx_off
) オプションを設定することで音声が出力できるようになることがあります。igfx_off
の設定について詳しくは Intel-IOMMU.txt の Graphics Problems?
を読んでください。
vfio_pci を有効化したあとに X が起動しない
ホスト GPU がセカンダリ GPU として認識されている場合、ゲスト GPU のドライバーをロードしようとしたときに X がエラーを起こします。Xorg の設定でホスト GPU の BusID を指定することで解決します。BusID は lspci や Xorg のログで確認できます。
/etc/X11/xorg.conf.d/10-intel.conf
Section "Device" Identifier "Intel GPU" Driver "modesetting" BusID "PCI:0:2:0" EndSection
詳しくは [4] を参照してください。
Chromium が内蔵グラフィックをアクセラレーションに使わない
Chromium はシステム内の GPU をできるかぎり多く検出してから使用する GPU を選択します (大抵はディスクリートの NVIDIA/AMD グラフィック)。使用する GPU は PCI デバイスによって選択されます。OpenGL レンダラが利用できるかどうかは考慮されません。結果として Chromium は内蔵 GPU を無視して、ゲスト VM が動作していてホスト環境から GPU が使えなくなっているかどうかに関係なく、vfio-pci
ドライバーに紐付けられた専用 GPU を使用しようとすることがあります。その場合 GPU が使えないためにソフトウェアレンダリングが使われることになります (CPU の負担が高まり、動画の再生が途切れがちになったりスクロールがスムーズに機能しなくなったりします)。
解決方法は Chromium 設定#特定の GPU の使用を強制するを見てください。
VM がひとつしかコアを使わない
IOMMU を有効にしてコアのカウントを 1 よりも大きくしても、VM が使用する CPU コアとスレッドがひとつしか現れないことがあります。解決するには virt-manager
で "Manually set CPU topology" を有効にして使用したい CPU ソケット・コア・スレッド数を設定してください。"Threads" は合計スレッド数ではなく各 CPU ごとのスレッド数なので注意してください。
パススルーは機能しているのに出力が表示されない
virt-manager を使用している場合、仮想マシンで UEFI ファームウェアが選択されていることを確認してください。また、仮想マシンに適切なデバイスが渡されていることも確認してください。
virt-manager のパーミッション問題
virt-manager でパーミッションエラーが発生する場合、以下を /etc/libvirt/qemu.conf
に追加してください:
group="kvm" user="user"
上記で解決しない場合は使用しているユーザーアカウントを kvm
と libvirt
グループに追加してください。
VM シャットダウン後にホストがロックアップする
Windows10 ゲストを実行している場合に、VM を長時間実行した後、ホストの複数の CPU コアがロックアップするという問題が発生することがあります ([5]を参照)。この問題を解決するには、ゲストにパススルーした GPU でメッセージシグナル割り込みを有効にしてみてください。有効化する方法のガイドは [6] にあります。
スリープ時にゲストが実行されているとホストがロックアップする
VFIO を有効にした仮想マシンを起動したまま、スリープ/復帰を行おうとすると不安定になることがあり、ホストマシンをシャットダウンしようとするとロックアップする既知の問題があります。以下の libvirt フックスクリプトと systemd ユニットを使用して、ゲストを実行している間にホストがスリープ状態になるのを防止することで問題を避けることができます。フックファイルの動作には実行権限が必要です。
/etc/libvirt/hooks/qemu
#!/bin/bash OBJECT="$1" OPERATION="$2" SUBOPERATION="$3" EXTRA_ARG="$4" case "$OPERATION" in "prepare") systemctl start libvirt-nosleep@"$OBJECT" ;; "release") systemctl stop libvirt-nosleep@"$OBJECT" ;; esac
/etc/systemd/system/libvirt-nosleep@.service
[Unit] Description=Preventing sleep while libvirt domain "%i" is running [Service] Type=simple ExecStart=/usr/bin/systemd-inhibit --what=sleep --why="Libvirt domain \"%i\" is running" --who=%U --mode=block sleep infinity
ovmf のアップグレード後にブートできない
ovmf-1:r23112.018432f0ce-1 からアップグレードしたときに起動できなくなった場合、 /var/lib/libvirt/qemu/nvram
にある古い *VARS.fd ファイルを削除する必要があります:
# mv /var/lib/libvirt/qemu/nvram/vmname_VARS.fd /var/lib/libvirt/qemu/nvram/vmname_VARS.fd.old
詳しくは FS#57825 を参照。