コンピュータ基礎の基礎~仮想マシン支援機構
- 2010/08/05 18:14
- カテゴリー:備忘録
コンピュータ基礎の基礎,今日が一応の最終回という事で,仮想マシンについてとりあげます。
コンピュータのハードウェアにはCPU,メモリ,I/Oがあって,その上でソフトウェアは動いています。では,そのソフトウェアでCPUやメモリ,I/Oを記述し,ハードウェア上で仮想的に別のハードウェアを作り出して,その上で別のソフトウェアを動かすと,どんなメリットがあるでしょうか。
かつて,大型の汎用機は,新機種に置き換わるときに,お客さんが使っているソフトウェアが使えなくなることが大問題でした。今のようにパッケージソフトなどなく,お客さんが自分の都合で作ったソフトばかりなわけですから,新機種がいかに魅力的であっても,苦労して作ったソフトが走ってくれなければ困ります。
しかし,互換性の問題は,いつの時代も技術的な進歩の妨げになるものです。そこでコンピュータメーカーは,新機種上で旧機種を仮想的に作り出し,過去のソフトウェアはここで動かすことで,ユーザーの不安を取り除くことにしました。
このように,過去の資産の継承という目的で登場したのが,仮想マシンという技術です。歴史的には随分と昔からある技術ですが,最近特に注目を集めているのは,高性能化するコンピュータを有効に利用するため1台のコンピュータを仮想的に複数台にし,台数を減らしてコストを削減したり,資産継承ではなく異なるOSを走らせて各々得意とするアプリケーションを走らせるなど,もう少し積極的な目的で使われる事が増えたからです。
仮想マシンには,大きくわけて2つの方法があります。
1つは,エミュレータに代表される方式で,ホストOS型と呼ばれるものです。その名の通り,実ハードウェア上にまず1つのOSが走っており,このOSの上で仮想マシンを実現するソフトウェアを走らせます。このOSをホストOSを言いますが,仮想マシンもこのホストOSの機能を使って作られます。
もう1つは仮想マシンモニタ型というものです。ハードウェアとOSの間に,ハードウェアを仮想マシンモニタというソフトウェアを1段挟みます。仮想マシンモニタはハードウェアを仮想化するもので,ここから上位レイヤーに対して,仮想化されたハードウェアを提供します。この上で複数のOSが走るわけですが,すべて別々の仮想マシンで動いているわけです。
ホストOS方式は実装は楽ですし,仮想マシンがあたかもホストOSのアプリケーションのように見えるのでわかりやすく,またホストOSは仮想化されたハードウェアで動いているわけではないので,仮想マシンによって生まれる制約がありません。
その代わり,ホストOSの提供するサービスによって実装されている仮想マシンは,競合するリソースや演算パワーを割り振るオーバーヘッドの影響が大きく,速度的にも信頼性の点でも今一歩です。
これに対して,仮想マシンモニタ型の仮想マシンは,なにせハードウェアが直接見えず,あるのは複数の仮想マシンです。面倒なリソースの配分はこの仮想マシンモニタが行ってくれますし,それぞれの仮想マシンで動くOSはどれも対等な扱いです。それに,仮想マシンモニタがあるおかげでオーバーヘッドも小さく済みます。
とはいえ,この仮想マシンモニタもソフトウェアなわけで,出来るだけ軽く作るのが望ましいです。そのために,ハードウェアの支援,とりわけCPUに仮想マシンモニタを支援するような機構を入れ込むことが,近年のCPUでは当たり前になっています。
では,x86で仮想マシンを実現するのに,問題となっていることを見ていきます。
まず,x86には,実行レベルという概念があります。リング0からリング3までの4段階があり,実行レベルが上がれば上がるほど,アクセス出来るリソースに制約が多くなってきます。OSやBIOSは最低レベルで動いて全てにアクセス出来ないといけませんが,アプリケーションが最上位で動いてくれると,万が一ソフトが暴走してもOSに動作を妨げたり,マシン全体に影響を与えるような動きを防いでくれます。
この,レベルによってアクセス出来る範囲を変え,信頼性を高める技術をリングプロテクションと呼んでいますが,高度なOSを実装するには必須の機能の1つです。
x86の場合,OSは全てのリソースにアクセス可能なリング0で実装されてきました。リング1や2はOSの一部が使い,最上位で最も制約の多いリング3はアプリケーションが使う事になっています。もしアプリケーションがOSの動きを妨げるようなレジスタを書き換えようとしたら,例外が発生して保護するようになっているわけですね。
仮想マシンを実現する仮想マシンモニタを実装するには,OSよりも下位のリングで動かす必要がありますが,仮想マシンモニタをリング0で動かしてしまうと,OSはリング1や2で動かすことになってしまいます。
しかし,OSは全てのリソースにアクセスしようとしますから,リング1や2でリング0でなければアクセス出来ないリソースをアクセスしてしまうと,例外が発生してしまいます。
仮想マシンモニタは,この例外を受けると,その命令をエミュレートしてOSの代わりにレベル0でアクセスを代行し,結果をOSに渡してあげます。しかし,想像が付くようにこの方法はいちいち例外を監視し,命令のエミュレートを行うために,オーバーヘッドが大きくて速度が上がりません。
別の問題もあります。
x86はその名の通り,8086に端を発する歴史あるプロセッサです。互換性を維持してここまで来た驚異のプロセッサですが,これも簡単なことではなく,無理な建て増しを繰り返して,矛盾をギリギリの所で回避して成し遂げた産物です。
例えばpopfという命令ですが,なんとリングレベルによって異なる動作をする命令だったりします。ということは,仮想マシンモニタの上で動いているOSが,リング0で動いているつもりで実行したpopf命令が,実はリング1や2で別の動作をすることが起きてしまうのです。
この場合,悪いことに例外も発生してくれませんから,仮想マシンモニタはpopf命令がこないかどうか,常に監視する必要が生じるのです。これはさすがに足を引っ張りそうですね。
ここ数年で用意されたx86の仮想マシン支援機能では,この問題を効果的に解決しています。まず,リング0からリング3まのリングをもう1つ用意し,それぞれVMXrootとVMXnon-rootと呼ぶようにしました。そして仮想マシンモニタをVMXrootで動作させ,OSをVMXnon-rootで動作させるのです。
VMXnon-rootで動作するOSが,もし特権命令を実行したら,即座に処理をVMXrootに切り替え,仮想マシンモニタに制御を移します。VMXnon-rootのリング0では,リソースにアクセス出来ない代わりに,VMXrootで走っている仮想マシンモニタが動いてくれるわけですね。
こうすると,例外によって処理を代行することもなく,またpopfをいちいち監視することもなく,オーバーヘッドを大幅に削減できることがおわかり頂けると思います。
これに加えて,それぞれの独立した仮想マシンは,各々のコンテキストを保存しておかなければいけないのですが,その保存領域を専用に用意してあり,仮想マシンの切り替え時にはこれらの待避と復帰が自動で行われるようになっていて,これも大幅にオーバーヘッドを削減することに貢献しています。
さらに,I/Oについても仮想マシンの支援の仕組みが考えられています。I/OとOSを繋ぐのはデバイスドライバですが,I/Oも仮想マシンモニタで管理されると,従来のデバイスドライバは当然使えません。またI/Oのエミュレータが仮想マシンモニタから提供されるようなものですので,非常に遅くなります。
そこで,DMAのアドレスをハードウェアでリマップする機能を持たせてあります。こうすると,実際のI/Oデバイスのアドレスを直接仮想マシンに提供出来るようになるため,従来のデバイスドライバがそのまま利用出来るようになるばかりか,高速にアクセスが可能になってくれます。
ただし,仮想マシンモニタが行ってくれていた排他制御はできなくなってしまいますので,ここはハードウェアによる排他制御が可能になるよう,PCIeの仕様が拡張されているので,これを用いることになっているそうです。
さて,長々とコンピュータの基礎的な事項についてまとめを行って来ました。最終的には仮想マシンの支援機構までやってきましたが,ふと気が付くのは,従来は出来るだけハードウェアの規模を小さくして,その中で最大限の処理能力を出そうと言う目的で新しい技術が開発されてきたところが,最近では使う事の出来るトランジスタの数が膨大になり,処理能力を上げるためにどうやって回路規模を大きくするかを考えると言った,アプローチの違いがあるように感じます。
例えばキャッシュメモリをたくさん積むことや,4コア,6コアという多数のコアを実装するマルチコアプロセッサなどは,その例だと思います。見方によってはインスタントで安易な高速化の方法が利用出来るようになるほど,トランジスタがふんだんに利用出来るようになったということでしょうか。
しかし,喜んでばかりもいられません。微細化によってトランジスタの数が増えても,その微細化は消費電力の増大と発熱の問題を助長します。いつの時代も,こうしてバランスを取りながら,知恵と工夫でコンピュータの性能は上がり続けるのだと思うと,私などはワクワクしてしまいます。
今後,どういう流れになっていくのでしょうか。特にマルチプロセッサの次に来るのは,いったいどういう技術でしょうか。楽しみです。