ハードウェア仮想化支援 ─ VT-x/EPTと二段アドレス変換
VMがほぼネイティブ速度で動くのはなぜか。VT-xのroot/non-root分離とEPTの二段アドレス変換を原理から押さえれば、VM Exitやポステッド割り込みの最適化の意味が腑に落ちます。
- 1.VT-x/AMD-VはCPUにVMX rootとnon-rootの2つの動作状態を追加し、ゲストはリング0〜3をそのまま使いつつ特権操作だけをVMMへ落とす。これでリング圧縮や命令の動的書き換えが不要になる。
- 2.EPT/NPTはゲスト物理→ホスト物理の二段目の変換をハードウェアで行い、ゲストのページテーブル(GVA→GPA)に介入せずGVA→GPA→HPAを完結させる。代償としてTLBミス時のページウォークが二次元化してコストが増える。
- 3.VM Exitは数百〜千サイクル級の重い遷移なので、ポステッド割り込みやSR-IOVでExit回数とI/O経路を削り、割り込み配送とデバイスアクセスをゲストへ直結させる。
なぜ仮想化にハードウェア支援が要るのか
仮想化の目標は、ゲストOSに「自分が物理マシンを独占している」と錯覚させることです。問題はx86の設計にあります。OSは本来リング0で動き、特権命令(割り込み制御、ページテーブル基底レジスタの書き換え等)を実行します。しかし仮想マシン上ではVMM(ハイパーバイザ)がリング0を握るため、ゲストOSは下位リングへ追い出されます。
ここで古典的な要件が立ちはだかります。仮想化がトラップ&エミュレートで成立するには、すべての特権命令が非特権モードで実行されたとき例外(トラップ)を起こす必要があります。ところがx86には、非特権モードでも例外を出さずこっそり値を読めてしまう命令(センシティブだがトラップしない命令)が複数あり、ゲストは自分が降格された事実を検知できてしまいます。
ハードウェア支援が登場する前は、リング圧縮(ゲストカーネルをリング0でなくリング1へ押し込む)や、問題命令を実行時に書き換えるバイナリ変換、準仮想化(ゲストカーネルを改変してVMMへ明示的に依頼させる)で凌いでいました。いずれも複雑で、CPUの設計どおりにゲストを動かせない点が根本の限界でした。
VT-x/AMD-V ─ root と non-root という新しい軸
Intel VT-xとAMD-Vは、リングとは直交する新しい動作状態をCPUに追加してこの問題を解きます。それがVMX rootモード(VMMが走る)とVMX non-rootモード(ゲストが走る)です。
| 観点 | VMX root(VMM側) | VMX non-root(ゲスト側) |
|---|---|---|
| 誰が動くか | ハイパーバイザ | ゲストOSとアプリ |
| リング | リング0〜3を通常どおり使用 | リング0〜3をそのまま使用 |
| 特権命令 | そのまま実行 | 設定した契機でVM Exitし制御を奪われる |
| 状態の保管 | VMCS/VMCBを管理 | VMCS/VMCBから状態を復元して実行 |
肝心なのは、non-rootモードのゲストがリング0をそのまま使える点です。ゲストカーネルは降格されないので、リング圧縮も命令の書き換えも不要になります。代わりに、VMMが「どの操作で介入したいか」を事前に設定しておき、その契機に達するとCPUが自動でroot側へ制御を戻します。この遷移がVM Exit、逆方向がVM Entryです。
ゲストとVMMの状態(レジスタ群、制御レジスタ、Exitの理由など)は、IntelではVMCS(VM Control Structure)、AMDではVMCBというメモリ上の構造体に保持されます。VM EntryでゲストのコンテキストがロードされCPUがnon-rootへ入り、VM Exitでゲスト状態が退避されVMMへ戻ります。リングを切り替えるのではなく実行モードの軸を1本増やしたことが、VT-x/AMD-Vの本質です。
二段アドレス変換 ─ EPT/NPTが解く問題
CPUの観点だけ仮想化しても、メモリが残ります。ゲストOSは自分のページテーブルでゲスト仮想アドレス(GVA)をゲスト物理アドレス(GPA)へ変換しているつもりですが、GPAは本物の物理アドレスではありません。GPAをホスト物理アドレス(HPA)へ写すもう一段の変換が要ります。
ハードウェア支援がない時代はシャドウページテーブルで対処していました。VMMがGVA→HPAを直接表す影の表を作り、ゲストがページテーブルを書き換えるたびに同期します。正しく動きますが、ゲストのページテーブル更新ごとにVM Exitが多発し、保守も複雑でした。
これを解くのがEPT(Intel: Extended Page Tables)/NPT(AMD: Nested Page Tables)です。CPUに二段目の変換表を持たせ、ゲストの一段目(GVA→GPA)には一切介入せず、ハードウェアがGPA→HPAを補って変換を完結させます。
二段アドレス変換(GVA -> GPA -> HPA)
一段目: ゲストのページテーブル GVA -> GPA (ゲストOSが管理)
二段目: EPT/NPT(VMMが管理) GPA -> HPA (CPUが自動で適用)
ゲストはGPAまでしか知らない。CPUがEPTでHPAへ写す。
-> ゲストのページテーブル書き換えでVM Exitが起きなくなる
シャドウ方式に比べ、ゲストのメモリ管理が原理どおりに動き、Exit回数が激減します。一方で代償もあります。
TLBミス時のページウォークが「二次元」になります。一段目のページテーブルは4階層(x86-64)で、各階層のエントリはGPAで示されるため、そのGPAを引くたびに二段目のEPTを丸ごと辿る必要があります。最悪では「一段目4回 × 各回のEPT walk 4回」に最終アクセスを加えたおおむね24回前後のメモリ参照になり得ます。だからこそTLBとキャッシュ階層の効きが、仮想化環境では一段と重要になります。
このコストを和らげるため、ラージページ(2MB/1GB)でページウォークの段数を減らす、TLBエントリにVPID/ASIDという識別子を付けてVM Entryごとのフラッシュを避ける、といった最適化が併用されます。
VM Exit ─ 仮想化の主たるオーバーヘッド
VM Exitは、ゲスト状態の退避・VMM状態のロード・Exit理由の解析を伴う重い遷移で、一回あたり数百〜千サイクル級のコストがかかります。性能チューニングの要諦は「Exitの回数をいかに減らすか」に尽きます。
VM Exitを誘発する代表例
CPUID / 一部の制御レジスタ書き換え
I/Oポートアクセス(設定により)
外部割り込みの受信
EPT違反(ゲストが未マップのGPAへアクセス)
ハイパーコール(ゲストからVMMへの明示要求)
EPTがシャドウページテーブルを置き換えたのも、割り込みやI/Oの直結化が進んだのも、すべて「Exitを減らす」という一本の動機に貫かれています。どの契機でExitするかはVMCS/VMCBの制御ビットで細かく設定でき、VMMは介入が必要な操作だけを選んで捕捉します。
ポステッド割り込みとSR-IOV ─ デバイスを直結する
仮想化で最後まで重いのが割り込みとI/Oです。素朴な実装では、デバイスの割り込みは必ずVMMが受け(VM Exit)、宛先ゲストを判定して仮想割り込みを注入し直します。割り込みが多いほどExitが積み上がります。
ポステッド割り込み(Posted Interrupt)は、この経路を短絡します。割り込みコントローラ(APIC仮想化)と連携し、対象ゲストが実行中ならVM Exitなしで直接割り込みを届けます。VMMはデータパスから外れ、配送のためだけの遷移が消えます。
I/O側を解くのがSR-IOV(Single Root I/O Virtualization)です。1枚の物理デバイス(PF: Physical Function)が、独立したレジスタとキューを持つ複数の仮想機能(VF: Virtual Function)をハードウェアで提供します。各VFを個別のゲストへ**そのまま割り当て(パススルー)**れば、ゲストはVMMを介さずデバイスを直接叩けます。
ゲストにデバイスを直結させると、デバイスのDMAがゲスト物理アドレス(GPA)で行われます。これを安全にする要がIOMMU(Intel VT-d / AMD-Vi)です。デバイスからのDMAアドレスをホスト物理アドレスへ変換し、許可された範囲外へのアクセスを遮断します。いわばEPTのデバイス版で、メモリ側のGPA→HPAと対になってDMA側のアドレス変換と保護を担います。SR-IOVの直結は、このIOMMUあってこそ成立します。
これらはPCI Expressのトポロジと密接で、VFの提供やパススルーはPCIeの機能(BARやコンフィグ空間)の上に構築されます。
「VT-x/AMD-Vはリングと直交するroot/non-rootを追加し、ゲストはリング0をそのまま使える(リング圧縮・バイナリ変換が不要)」「EPT/NPTがGPA→HPAの二段目を担い、ゲストのページテーブルに介入しない代償としてページウォークが二次元化する」「VM Exitが主なオーバーヘッドで、ポステッド割り込み・SR-IOV・IOMMUでExitと経路を削る」の3点が核心です。シャドウページテーブルとEPTの違い(Exit頻度とウォークコストのトレードオフ)を説明できると強いです。
まとめ
- VT-x/AMD-Vはリングと直交するroot/non-rootモードを追加し、ゲストにリング0を使わせたまま特権操作だけをVM Exitで捕捉する。これでリング圧縮もバイナリ変換も不要になった。
- EPT/NPTはGPA→HPAの二段目をハードウェアで処理し、ゲストの一段目(GVA→GPA)に介入しない。代償としてTLBミス時のページウォークが二次元化し、メモリ参照回数が大きく増える。
- 性能の主敵はVM Exitで、ポステッド割り込み(割り込み配送の直結)とSR-IOV(VFのパススルー)、それを支えるIOMMUがExitとI/O経路を削る。
CPUのモード遷移という観点ではCPUの命令パイプラインやCISC/RISCの設計思想と地続きで、メモリ側はキャッシュ・TLB階層の理解がそのまま仮想化性能の理解につながります。
CPU/メモリ/ディスク Article
ハードウェア仮想化支援 ─ VT-x/EPTと二段アドレス変換を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
仮想化
比較で見る軸
難易度: advanced / カテゴリ: CPU/メモリ/ディスク / タグ数: 6
導入後に効く点
EPT/NPTはゲスト物理→ホスト物理の二段目の変換をハードウェアで行い、ゲストのページテーブル(GVA→GPA)に介入せずGVA→GPA→HPAを完結させる。代償としてTLBミス時のページウォークが二次元化してコストが増える。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- CPU/メモリ/ディスク
- タグ数
- 6
判断チェックリスト
- 自社の用途が「仮想化 / VT-x」に近いか確認する。
- 強みである「VT-x/AMD-VはCPUにVMX rootとnon-rootの2つの動作状態を追加し、ゲストはリング0〜3をそのまま使いつつ特権操作だけをVMMへ落とす。これでリング圧縮や命令の動的書き換えが不要になる。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。