前回は、システム仮想マシンを実現するための条件、その古典的な実装方法を紹介しました。また、それらのアプローチをx86システムに適用する場合、どのような障壁があるかについて説明しました。
今回は、従来のx86プロセッサにおける仮想化の問題点を解決するために追加された“ 仮想化支援機能” がどのようなものであるかを紹介します。
仮想化支援機能の概要
x86プロセッサの仮想マシンソフトウェアの実装が困難だった中、プロセッサを供給するインテルおよびAMDは、プロセッサ自体に仮想化支援機能を追加しました。それが、インテル製のプロセッサに搭載されたIntel VT-x、およびAMD製のプロセッサに搭載されたSVMです。
リング0で動作するOSをも支配するVMM専用モード
前回解説したtrap-and-emulateによるシステム仮想マシンを実装するためには、仮想マシンモニタ(VMM)が、ゲストOSのカーネルによる都合の悪い処理を全てトラップできる必要があります。
しかし、これまでx86プロセッサのために設計・開発されたオペレーティングシステムは、プロセッサの特権レベルであるリング0を占有するように作られてきました。
このため、ゲストOSをリング0から他のリングに移し実行する“ ソフトウェアVMM” が作られました。プロセッサの開発元であるインテルおよびAMDは、根本的な解決策として、プロセッサに「リング0で動作するオペレーティングシステムのカーネルをも支配できる」新たなモードを追加したのです。
これにより、ゲストOSをこれまでと同じリング0で実行していても、仮想マシンモニタがゲストOSの動作を制御できるようになりました。このため、ソフトウェアVMMが行っていた” ゲストOSのカーネルをリング1に移して実行させる処理” 自体が不要となりました。また、ソフトウェアを動作させるリングレベルに変更が生じないため、リング0とリング1で異なった動作をするような命令に対する配慮もいりません。
図1 仮想化支援機能を利用した仮想マシンの実装
すべてのセンシティブ命令のトラップが可能に
Intel VTやAMD-Vでは、従来のリングプロテクションではトラップできなかったセンシティブ命令も、全てトラップできるようになっています。このため、従来のx86プロセッサ用ソフトウェアVMMが行っていた、バイナリ・トランスレーションなどの回避処理が不要になりました。このためtrap-and-emulateによる仮想マシンモニタの実装が比較的容易となっています。
Goldbergらが論じた「仮想化可能なアーキテクチャ」へ
これらの仮想化支援機能は、既存のx86プロセッサの機能をそのまま継承しつつ、Goldbergらによる” 仮想マシンモニタのあるべき姿” を実現できるよう、プロセッサ自体に仮想マシン実行用モードを追加したものである、ととらえることができます。
x86プロセッサで初めてリングプロテクションの機能が実装されたのは、1985年にリリースされたIntel 80386でした。Intel 80386以後、x86プロセッサで動作するオペレーティングシステムは、リング0~3の4段階の保護を前提として設計・開発されてきました。x86プロセッサのリングプロテクションが実装されてから20年近くが経っていましたが、仮想化支援機能の登場によって、久々に特権にかかわる機構にメスが入ったことになります。
仮想化支援機能Intel VT-xの内部構造
仮想化支援機能については、2007年前後に大きく話題となり、Webサイトの技術記事や雑誌類でも頻繁に取り上げられていました。このため、概要についてすでにご存じの方も多いかと思いますが、改めて内容を確認しておきたいと思います。
x86プロセッサの仮想化支援機能としては、Intel VTとAMD-Vの2種類がありますが、これらは各社のプロセッサに搭載された仮想化機能の” 総称” です。今回スポットを当てている“ 仮想マシン実行モードの実装” の代表例として、インテル製x86プロセッサ向けのIntel VT-xと呼ばれる拡張機能があります。その他にもItanium向けの同等機能であるIntel VT-iなどもありますが、ここではIntel VT-xを基に解説します。
Intel VT-xの基本的な考え方
Intel VT-xは、プロセッサの動作モードを「仮想マシンソフトウェアの動作面」( VMX root mode)と「仮想マシンの動作面」( VMX non-root mode)の2面に分ける機能です。仮想マシン上の論理プロセッサがセンシティブ命令を実行する場合、もしくはトラップすべき状況にになった場合には、ハードウェアレベルでもうひとつの面に制御を移すことにより、仮想マシンの実装をサポートしています。
Intel VT-xでは、VMX rootからVMX non-rootに切り替える場合には、現在のプロセッサの状態をシステムメモリ上に保存し、またシステムメモリ上のデータから論理プロセッサの状態を復元します。逆に、VMX non-rootからVMX rootに切り替える場合には、論理プロセッサの状態をシステムメモリ上に保存し、元のプロセッサの状態をシステムメモリ上のデータから復元する仕組みにより、モード切り替えを実現します。
図2 Intel VT-xにおけるVMX root/VMX non-rootのモード切り替え
Intel VT-xは、VMX non-rootの論理プロセッサの振る舞い・状態を保存する領域やVMX rootのプロセッサの状態を待避する領域などをセットにしたVMCSと呼ばれるデータ構造、そしてVMX root/non-rootのモード切り替えや切り替え準備に使われる新命令群により構成されます。
VMCS ―― VMX root/VMX non-rootの状態や構成を保存するデータ構造
Intel VT-xの要となるデータ構造が、Virtual Machine Control Data Structure(VMCS)です。
VMCSは、仮想マシンソフトウェアがシステムメモリ上に作成します。このデータ構造の中には、仮想マシンソフトウェアにより、論理プロセッサの状態と振る舞い方、実プロセッサ―論理プロセッサ間の切り替え時のオプションパラメータが設定されます。
また、論理プロセッサがどのような理由で停止したのか等の情報が保存されるフィールドもあり、仮想マシンソフトウェアが、その結果に基づき仮想マシンの状態を判断しながら、必要な処理が行えるようになっています。
表1 VMCSの構造
論理グループ 説明
ゲストステート領域 論理プロセッサ(仮想マシン)の状態を保存する。
ホストステート領域 実プロセッサ(VMM)の状態を保存する。
VM実行制御フィールド 論理プロセッサ内の振る舞い方、および論理プロセッサ内から脱出(VM Exit)する条件など、を指定する。
VM Exit制御フィールド 論理プロセッサを実行終了する際の動作を制御する。
VM Entry制御フィールド 論理プロセッサを実行開始する際の動作を制御する。
VM Exit情報フィールド 論理プロセッサの実行が終了した際、その理由についてプロセッサが理由を設定する。
ゲストステート領域とホストステート領域
ゲストステート領域およびホストステート領域には、VMX root/VMX non-root間の切り替え時に、実プロセッサと論理プロセッサの状態が保存されます。保存されるものとしては、コントロールレジスタ(CRx) 、デバッグレジスタ(DR7) 、セグメントレジスタの値などが含まれます。
実際には、この領域に、全てのレジスタの状態が保存されるわけではありません。汎用レジスタ(EAX~EDX)など、これらの領域に保存されないレジスタも存在します。そのようなレジスタは、仮想マシンソフトウェアが個別に状態を保存・復元しなければなりません。
VM 実行制御フィールド
VM実行制御フィールドは、そのVMCSで示される論理プロセッサがどのような振る舞いをすべきかを設定します。
本フィールドには、論理プロセッサで、どのようなイベント(センシティブ命令やI/Oアクセス)が生じたらVMX rootに切り替えるか、などを指定するためのフィールドが含まれます。これにより、仮想マシンソフトウェアが、ゲスト側でどのような命令が実行されたらホスト側に切り替えるか、外部からの割り込みやNMIが発生した場合にホスト側に切り替えさせるか、一定時間が経過したらホスト側に切り替えさせるプリエンプションタイマーを利用するか、などを設定できます。
VM Exit/VM Entry制御フィールド
これらのフィールドは、論理プロセッサへ(から)切り替える際の挙動を指定します。また、論理プロセッサに仮想的な外部割り込みや例外を挿入する場合には、論理プロセッサへ挿入すべき割り込みの情報を、仮想マシンソフトウェアがVM Entry情報フィールドへ設定します。
VM Exit情報フィールド
VM Exit情報フィールドは、VMX non-rootからVMX rootへの切り替え(VM Exit)が発生した際に、プロセッサにより更新されるフィールドです。この情報フィールドには、どのような理由によりVM Exitが発生したか等の情報が記録されます。
仮想マシンソフトウェアは、VM Exit情報フィールドを参照して論理プロセッサが停止した理由を把握し、仮想マシンモニタとしての処理を行います。大抵の場合はVM Exit情報フィールドの情報でだいたいの情報が揃うのですが、VM Exitの原因によっては、論理プロセッサが実行中の命令のアドレスを示すIPレジスタの値からVM Exitの原因となった命令を特定し、内容を判断して処理しなければならない場合もあります。
Intel VT-xで追加された命令群
Intel VT-xで追加された命令は、5個のVMXオペレーション命令(VMX Operation Instructions)、および5個のVMCS管理命令(VMCS Management Instructions)、計10個です。前者はIntel VT-xで利用可能となるVMX root/VMX non-rootを切り替えるためのもの、後者は論理プロセッサの実行に必要となるVMCSを管理するための命令です。
VMXオペレーション命令
VMXオペレーション命令は、VMXモードの開始・終了、論理プロセッサの実行を開始する命令で構成されます。また、論理プロセッサ内からホスト側の機能を呼び出す“ ハイパーコール” を実現するための命令が用意されています。
表2 VMXオペレーション命令
VMXON Intel VT-xを有効化
VMXOFF Intel VT-xを無効化
VMLAUNCH 論理プロセッサ(仮想マシン)を実行開始
VMRESUME 中断中の論理プロセッサ(仮想マシン)を実行再開
VMCALL VMX rootモードのハイパーコール呼び出し
VMCS管理命令
VMCS管理命令は、論理プロセッサの構成や状態を定義するVMCSを読み書きする命令で構成されます。VMCSとして利用されるメモリ空間は、プロセッサにより読み書き保護され、ソフトウェアが直接アクセスできません。このため、仮想マシンソフトウェアがVMCSの内容を読み書きする際は、これらの命令を使用します。また、切り替え先の論理プロセッサの情報がシステムメモリ上のどこにあるか、プロセッサに指示するためのロード命令などが存在します。
表3 VMCS管理命令
VMCLEAR VMCS領域を初期化する
VMREAD VMCS内のデータを読み出してメモリに格納する
VMWRITE VMCSにメモリ上のデータを格納する
VMPTRLD VMCSのポインタをプロセッサにロードしアクティベートする
VMPTRST 現在プロセッサに設定されているVMCSのポインタを読み出す
AMD SVMとIntel VT-xの違い
ここまで、仮想化支援機能の例としてインテルのx86プロセッサに実装されているIntel VT-xを紹介しましたが、AMDのプロセッサの実装についても簡単に見ておきましょう。
AMD-Vにも、Intel VT-xと同等の機能があり、これはSVM(Secure Virtual Machine)と呼ばれています。最近はSVMという言葉を見る機会は減り、AMD-Vという表記で触れられていることが多いのですが、AMDが提供する開発者向けマニュアル、オープンソースの仮想マシンソフトウェアのソースコード、メッセージなどには依然SVMという表記が残っています。x86プロセッサ向けの仮想マシンに関してSVMというキーワードを見かけたら、“ AMD-Vのうち、特に仮想マシン実行モードのことを指している” と考えると良いでしょう。
SVMはIntel VT-xに非常によく似ていますが、命令やデータ構造のレベルでは全く互換性がありません。では、SVMとIntel VT-xのデータ構造や命令体系がどのように違うのでしょうか。
図3 SVMにおけるHost mode/Guest mode間の切り替え
SVMの有効化
Intel VT-xの場合、機能を有効化/無効化するためのオプションとしてVMXON/VMXOFF命令がありました。しかし、SVMにはこれらに対応する命令はありません。SVMを有効化/無効化する場合は、MSR(Machine Specific Register)と呼ばれる特殊なレジスタ上のビットであるSecure Virtual Machine Enable(SVME)フラグをオン/オフします。またSVMでは、ホストの状態を保存するシステムメモリ(host-state save area)の物理アドレスを専用のMSRに設定しておく必要があります。
VMCB(Virtual Machine Control Block)
SVMでは、VMCB(Virtual Machine Control Block)と呼ばれる領域を使います。VMCBはIntel VT-xのVMCSに相当するものですが、主な相違点について下記にまとめます。
VMCSとはデータ構造が異なる
VMCSと同じく仮想マシンの状態を保存ための領域(state save area)があるが、VMCB内にホスト側の状態を保存する領域は存在しない
SVMで追加された命令群
SVMで追加されている命令は8個(MOV命令を含めると9個)です。厳密に対応するわけではありませんが、SVMの命令群とIntel VT-xの命令群の対応も含め表4に記述しました。
表4 SVMで追加された命令群
AMD-V命令 説明 対応するIntel VT-x命令
VMRUN Guest Mode(仮想マシン)を実行する VMLAUNCH、VMRESUME
VMLOAD Guest Modeの一部のプロセッサ状態をVMCBから復元する -
VMSAVE Guest Modeの一部のプロセッサ状態をVMCBに保存する -
VMMCALL Guest Modeからホスト側を呼び出す(ハイパーコール) VMCALL
STGI グローバル割り込みフラグの設定 -
CLGI グローバル割り込みフラグのクリア -
INVLPGA Tagged TLBキャッシュのクリア -
SKINIT Security Kernelの起動(TPMによる実行コードの検証が可能) -
MOV CRレジスタの操作 -
Intel VT-xには見当たらない、SVMの特徴的な命令としてTPM(Trusted Platform Module)と連携して仮想マシンのセキュリティを確保できるSKINIT命令、プロセッサ外からの割り込みを抑制・再開するSTGI,/CLGI命令などが挙げられます。
ソフトウェアVMMのほうが仮想化支援機能より速い!?
一見、便利な仮想化支援機能ですが、これらの機能が搭載された当初は、ホスト―ゲスト間の切り替えに非常に多くのCPUサイクルを必要としていました。このため、仮想マシンソフトウェアの実装が以前より容易になったと言っても「ハードウェアの機能を使うとVMwareなどのソフトウェアVMMよりも遅くなる」といった問題がありました。
NetBurst~MeromのVM Entry/VM Exitパフォーマンス比較
具体的なインテル製プロセッサのベンチマークを見てみましょう。VMwareの論文によると、NetBurstアーキテクチャを採用したPentium4プロセッサとCore 2 Duoプロセッサでの比較で、VMX root/VMX non-rootの切り替え(VM Entry、VM Exit)に必要なサイクル数は半分近くまで低減されました。
図4 仮想化支援機能が必要とするCPUサイクル数の比較
参考元
Keith Adams, Ole Agesen "A Comparison of Software and Hardware Techniques for x86 Virtualization" VMware, 2010
Nehalemコアでの性能改善
さらに、Meromコア(Core 2 Duo世代)とNehalemコア(Xeon 5500, Core i7世代)の比較でVMX root/VMX non-root間の切り替えに必要なサイクル数は60%近くの削減がなされており、当初の実装から比較すると、オーバーヘッドは大変少なくなっています。
図5 Nehalemによる仮想化支援機能の性能改善状況
参考元
2010年3月 インテル マイクロアーキテクチャー(Nehalem)概要
独自のバイナリトランスレーション技術を持っていたVMwareは……
このように、プロセッサに搭載された仮想化支援機能は、当初は性能があまり思わしくなかったため、VMwareはこれらの技術をすぐには採用しませんでした。同社は、独自のバイナリトランスレーション技術を持ち、ソフトウェアレベルでより高速に仮想マシンを実行できたからです。
VMwareは、プロセッサの仮想化支援機能が改良されるまでは自社のバイナリトランスレーション技術を利用し続け、プロセッサの性能改善が図られてからIntel VTやAMD-Vを利用するようになりました。具体例として、64ビットのゲストOSをサポートしたESX4.0以降では仮想化支援機能を搭載したプロセッサが必須となっています。
次回予告
今回は、x86プロセッサの仮想化支援機能(Intel VT、AMD-V)のはじまりとその概要、そして、現在に至るまでの流れについて紹介しました。次回は、オープンソースの仮想マシンソフトウェアであるLinux KVMが、これらプロセッサに搭載された仮想化支援機能をどのように利用しているか、具体的に追っていきたいと思います。お楽しみに。