エンジニアなら知っておきたい仮想マシンのしくみ

第6回 プロセッサの仮想化をソースから知る[その1]

この記事を読むのに必要な時間:およそ 8 分

前回は,x86プロセッサの仮想化支援機能(Intel VT,AMD-V)について,その仕組みを紹介しました。

今回は,オープンソースの仮想マシンソフトウェアであるLinux KVMのソースコードを読み,仮想マシンソフトウェアがどのようにIntel VTやAMD-Vを利用してプロセッサを仮想化しているか,具体的に追っていきたいと思います。

Linux KVMのソースコード構成

Linux KVMは,Linux向けのカーネルモジュールとして,Linuxカーネルにマージされています。最新の開発版について興味があれば,Linux KVMの開発サイトから入手することをお勧めします。今回はLinux 2.6.38.2のソースツリーに含まれるLinux KVMのソースコードを基に解説します。

Linux KVMのソースコード ディレクトリ

Linux KVMのカーネルモジュールは,Linuxカーネルのソースコードツリーのうち,以下のディレクトリに収録されています。

virt/kvm/ ――アーキテクチャ非依存コード
Linux KVMの実装部分のうち,APIなど,ユーザモードから見える部分については,このディレクトリ以下に収録されています。たとえば,/dev/kvmデバイスのインターフェース実装などが含まれます。
arch/*/kvm/ ――各アーキテクチャ向けコード

仮想マシン機能を実現するために,x86などの各アーキテクチャによって実装が異なるハードウェア固有部分は,こちらのディレクトリ以下に,各アーキテクチャごとに収録されています。たとえばx86プロセッサ向けのコードはarch/x86/kvm/に見つかります。

Linux KVMはおもにx86で利用できますが,実際にはその他のアーキテクチャにも対応しています。現時点でLinux KVMがポートされているアーキテクチャについて整理すると,下記のとおりとなっています。

  • x86(x86アーキテクチャ 32ビット, 64ビット)
  • ia64(IA-64アーキテクチャ)
  • s390(S/390アーキテクチャ)
  • ppc(Power PCアーキテクチャ)

x86プロセッサ向け仮想化支援機能の抽象化

x86プロセッサに限って,ハードウェア固有部分には,さらにもうひとつのレイヤが存在します。これまで紹介してきたように,Linux KVMはIntel VT,およびAMD-Vの両方に対応しています。しかし両者には実装上の互換性がないため,別々に対応しなければなりません。

このため,Intel VT搭載機向けのコード,AMD-V搭載機向けのコードは別々のソースファイルに分離されています。そして,コンパイル時には,それぞれのソースファイルからkvm-intel.koおよびkvm-amd.koと2つカーネルモジュールが作られます。Linux KVMのロード時には,Linux KVM本体(kvm.ko)に加え,プロセッサの種別からkvm-intel.koもしくはkvm-amd.koのどちらかが併せてロードされる仕組みとなっています。

もっとも,Intel VTとAMD-Vの間で互換性がないといっても,これらのコードの目的はどちらも⁠x86プロセッサの仮想化⁠です。このため,実際には⁠どちらにも通用するコード⁠が存在し,この部分が切り出されたのがx86.cです。各仮想化支援機能は,x86.cはvmx.cやsvm.cのアダプタとしての役割を持っています。もし,将来,x86プロセッサ向けの新しいプロセッサ仮想化手法が登場した暁には,このインターフェースを踏襲する形で,ソースファイルの追加によっての対応も可能でしょう。

表1 おもなx86プロセッサの仮想化支援対応コード

ソースコード説明
x86.cx86アーキテクチャサポート(Intel VT/AMD-V対応)
vmx.cIntel VTサポート
svm.cAMD-Vサポート

Linux KVMからのIntel VTの利用

では,Linux KVMカーネルモジュールが具体的にどのような処理を行っているのか,vmx.cの内容を読んでいきましょう。

VMCSの生成

Intel VT-xでは,論理プロセッサを実行するためにVMCSが必要です。Linux KVMは,仮想マシンに対してvcpu(仮想CPU)が作成されたタイミングで,システムメモリ上にVMCS領域を生成します。仮想マシンが2つの vcpuを持つ場合,vcpuごとに1つ,合計2つのVMCSが生成されます。プロセス,仮想マシン,プロセッサの数を図で表すと図1のような関係になります。

図1 Linux KVMにおけるインスタンス,VMCSの数量関係

図1 Linux KVMにおけるインスタンス,VMCSの数量関係

VMCSは,システムメモリ上のページから割り当てて使います。ページとは,プロセッサが管理するメモリ空間の単位で,x86プロセッサの場合は4KBである場合が殆どです。Linux KVMは,Linuxカーネル本体のメモリ管理ルーチンよりシステムメモリの割り当てを受け,VMCSとして内容を初期化します。

arch/x86/kvm/vmx.c

1569 static struct vmcs *alloc_vmcs_cpu(int cpu)
1570 {
1571         int node = cpu_to_node(cpu);
1572         struct page *pages;
1573         struct vmcs *vmcs;
1574
1575         pages = alloc_pages_exact_node(node, GFP_KERNEL, vmcs_config.order);
1576         if (!pages)
1577                 return NULL;
1578         vmcs = page_address(pages);
1579         memset(vmcs, 0, vmcs_config.size);
1580         vmcs->revision_id = vmcs_config.revision_id; /* vmcs revision id */
1581         return vmcs;
1582 }

さらに,作成されたVMCSは必要に応じてレジスタの初期値などが設定されます。また,ファイルとして保存されていた仮想マシンを復元する場合,マイグレーション機能により別の環境から移ってきた仮想マシンの場合は,その論理プロセッサの状態を復元する必要もあるでしょう。

著者プロフィール

長谷川猛(はせがわたけし)

(株)SRAで7年間のシステム構築&提案を経験したのち,Fusion-ioのセールスエンジニアを経て,フリーランスエンジニアとして活動中。『LDAP Super Expert』(技術評論社)に寄稿したほか,『Xen 徹底入門』(翔泳社)および『萌え萌えうにっくす!UNIX ネットワーク管理ガイド』(毎日コミュニケーションズ)の共著者のひとりである。

スノーボード,ごまラーメン,飼い犬のミニチュアシュナウザー「ラピス君」が大好き。

コメント

コメントの記入