カーネル2.6.20から「KVM」(Kernel-based Virtual Machine)と呼ぶ仮想化機能が標準搭載された。KVMは,1台のマシンでLinuxと他のOS(ゲストOS)を協調稼働できるように制御する,いわゆる「VMM」(仮想マシン・モニター)と呼ばれるソフトである。カーネル内部に組み込まれており,KVMに対応した仮想化ソフト(例えばKVM版QEMU)と組み合わせて使用する。

 KVMとKVM対応仮想化ソフトを組み合わせることでPC環境を「完全仮想化(フル・バーチャライゼーション)」できる注1。完全仮想化したPCでは,LinuxとWindowsを同時に動かすことなどができる(写真1)。

写真1●KVM機能を使ってLinux上でWindows XPを稼働
写真1●KVM機能を使ってLinux上でWindows XPを稼働
KVMは完全仮想化に対応した仮想マシン・モニターである。KVM対応の仮想化ソフトを使うとWindows XPなどのOSを無改造で稼働できる。画面は,KVM対応のQEMUを使ってWindows XPをFedora Core 6上で稼働させたものだ。

 プロセッサ(CPU)の仮想化支援機構の利用を前提にすることで,KVMは他のVMMよりもシンプルに実装できている。支援機構が及ばない部分についてはソフトウエアで実装しているが,こちらはオーソドックスな仕組みを採用している。KVMは仮想化ソフトの動作を知るには最適な素材といえる。以下では,KVMの仕組みについて詳しく解説する。

VMMの実装が難しかったx86 CPU

 1台のマシン上で複数のOSを稼働させると,さまざまな“衝突”が発生する恐れがある。例えば,メモリーの同じ場所(アドレス)に同時に異なるデータを書き込む可能性がある。こうした問題が起こらないように,ゲストOSの動作を調停するのがVMMの役割である。メモリーの場合であれば,衝突が発生しそうなアドレスにデータを書き込む危険な命令が発行された瞬間に,VMMが割り込んでアドレスを書き換えるといった調停を施す。

 VMMがOSの実行中に割り込むためには,プロセッサ側に危険な命令を察知するハード的な仕組みが必要だ。危険な命令がすべて「特権命令」に分類されていれば対処は容易だ。特権命令は実行に高い権限が必要で,低い権限レベルで実行すると例外注2が発生する。そのため,ゲストOSを低い権限レベルで稼働させれば,特権命令の実行をVMMが捕捉できる。この手法を「リング・エイリアシング」と呼ぶ。

 しかしx86互換プロセッサには,非特権命令にも危険な命令が存在する。リング・エイリアシングだけではすべての調停を施せない。

 そこでこれまでの仮想化ソフトは,ゲストOSの危険な命令を,より安全な命令に動的に書き換えて実行する仕組みを併用している(これを動的バイナリ変換と呼ぶ)。

 ただし,動的バイナリ変換の仕組みは複雑だ。VMMの実装は難しくなり,コード量も膨らんでしまう。

 それに対して,KVMはわずか数千行のコードで実装されている。これは,最近のx86互換プロセッサが備える仮想化支援機構を利用するからである。「Intel VT-x」対応の米Intel社のプロセッサか,「AMD-V」対応の米Advanced Micro Devices社(AMD)のプロセッサのどちらかでないと,KVMは動作しない。

支援機構によるシンプルな実装

 「Intel VT-x」と「AMD-V」は異なる機構だが,基本的な概念は共通している。それは(1)ゲストOS稼働用のプロセッサ・モードを新規に用意したことと,(2)調停が必要な命令が実行された際に,プロセッサ状態を退避して実行モードを切り替えること,の2点である(図1)。

図1●プロセッサの仮想化支援機構の概要
図1●プロセッサの仮想化支援機構の概要
ゲストOS稼働用のプロセッサ・モードを新設した。VMMでの調整が必要な命令が実行されるとプロセッサ・モードを切り替える。
[画像のクリックで拡大表示]

 ゲストOSが稼働する場合,プロセッサは「VMX non-rootモード」(AMD-Vではゲスト・モード)で動作する。調停が必要な命令をゲストOSが発行すると,プロセッサは「VMX rootモード」に切り替える。切り替え前のプロセッサ状態や,切り替え理由などの情報は専用のメモリー領域に保存しておく。

 一方,モード切り替えによってVMMが稼働を始める。VMMは,保存された情報に基づいて必要な調停を施す。調停後は,VMMが再びVMX non-rootモードに戻す。

 仮想化支援機構に対応していないプロセッサとの最大の違いは,危険な命令であれば非特権命令であってもモード切り替えが発生する点である。これにより,動的バイナリ変換が不要になり,VMMの仕組みを単純にできる。

 KVMでは,仮想化支援機構を搭載しないプロセッサを切り捨てることで処理を単純化できた。例えば,ゲストOSでプロセッサがサポートする機能などを調べる「CPUID」命令を実行すると,KVMでは図2の手順で実行結果を差し替える注3。これは,前述した仮想化支援機構利用時の一般的なVMMの実装そのままである。

図2●Intel VT-xの場合のCPUID命令の実行
図2●Intel VT-xの場合のCPUID命令の実行
CPUID命令がKVMで処理される流れ。CPUID命令はモード切り替えを発生させる。KVMはモード切り替えの原因に応じた処理をする。プロセッサ情報を設定した後,再度モードを切り替えて仮想マシンを稼働させる。
[画像のクリックで拡大表示]

 ゲストOSに渡す情報は,仮想化ソフト(KVM対応QEMU)内のcpu_x86_init関数で,仮想マシン作成時に用意しておく。32ビット仮想マシン環境向けには,プロセッサの情報として「Family 6,Model 3,Stepping 3」などを設定している。これは,KlamathコアのPentium IIに相当する。

 実際,KVM環境でゲストOSにLinuxを稼働させて/proc/cpuinfoの情報を調べると図3のようになる。実験はCore Duoプロセッサ搭載機で実施したが,実際のCPU情報ではなく,設定した情報が表示されている。

図3●ゲストOSで参照したプロセッサ情報
図3●ゲストOSで参照したプロセッサ情報
ゲストOSではKVMが差し替えた情報が得られている。実験機のプロセッサ(Core Duo)情報とは異なっている。
[画像のクリックで拡大表示]