■システムとアプリケーションは,お互い完全に独立して動いているため,アプリケーションがハングアップしても,Windowsシステムは稼働を続けられる。
■ユーザー・モードで動作するアプリケーションと,カーネル・モードで動作するシステムの間を橋渡しすることがWindowsサブシステムの役割である。
■アプリケーションもWindowsサブシステムもユーザー・モードで動作するが,2つの間を細かく見るとカーネル・モードのLPC(ローカル・プロシージャ・コール)サービスが重要な役割を果たしている。
(2005年11月号「本当に知っている?Windows XPの基礎[アーキテクチャ編]」より)

(中島 省吾=メディアプラネット)



 今回からこの連載は「アーキテクチャ編」として,新しいテーマを解説していく。一言で「Windowsのアーキテクチャ」と言っても,その範囲は広大で実に多くの要素を含んでいる。特にNT系と9x系では,その構造は全く異なる。そこで既にスタンダードと言えるWindows XPに絞って,その中枢ともいえる「カーネル・モード」について解説しようと思う。まず第1弾は,アプリケーションのクラッシュがOSまで及ばない本当の理由である。

 よく「NT直系のWindowsは,9x系より堅牢」と言われる。その理由として「システムとアプリケーションが完全に分離されているから」というのはよく聞く話だ。もう少し詳しく言えば,アプリケーションはユーザー・モードで動作し,システムはカーネル・モードで動作する。だからアプリケーションはシステムの領域へは立ち入れないので安全だ…というのである。

△ 図をクリックすると拡大されます
図1●分離されているはずの2つのモードはどこでつながるのか
 一見もっともだが,よくよく考えるとこれは不思議な話ではないだろうか。確かにユーザー・モードのアプリケーションからカーネル・モードのシステム領域へはアクセスできない。しかし,システムとアプリケーションが完全に分離されているとしたら,アプリケーションはシステムの機能を利用できないはずである。しかし,実際にはこれが可能であり,どこかにユーザー・モードとカーネル・モードの橋渡しをする仕組みが存在するはずである(図1)。

 そこで今回は,アプリケーションのクラッシュがOSまで及ばない本当の理由と,なぜそのようなことが可能なのか,その仕組みに迫ってみたい。

ユーザー・モードとカーネル・モードの溝
 Windowsのアーキテクチャが,プロセッサと深い関係にあることは,多くの人が知るところだ。特に,「ユーザー・モード」と「カーネル・モード」と呼ばれる動作モードは,そのままIntelのプロセッサ(80386~Pentium 4)が備えている「リング3」と「リング0」の特権レベルのことである。

 動作モードを利用して,OSをアプリケーションから保護しようと考えた最初のIntelのプロセッサは「80286」だ。80286には「プロテクト・モード」と呼ぶ動作モードがあり,8086プロセッサ互換の「リアル・モード」とは異なり,メモリー空間が保護される仕組みになっている。その後の「80386」以降のプロセッサになると,特権レベルは「リング0~3」へと4つに増え,数字の大きいリングから小さい方へのアクセスが制限されるようになった。

 この4つあるリングのうち,Windowsでは「リング0」を「カーネル・モード」,「リング3」を「ユーザー・モード」と呼び,この2つのモードのみを使用する。残りのリングを利用しない理由は,他のプロセッサとの互換性を重視したからだ。今でこそWindows XPがサポートするプロセッサはIntel互換しかないが,かつてNTの時代は,米Digital Equipment(DEC)のAlphaや,米MIPS Technologiesが開発したMIPS Rシリーズといった他のメーカーのプロセッサもサポートしていた。これはその名残と言っていい。

Windowsサブシステムはユーザー・モードにある

△ 図をクリックすると拡大されます
図2●Windowsのユーザー・モードとカーネル・モード
 それではもう少し具体的に,カーネル・モードとユーザー・モードの説明をしよう。次の図2を見てもらいたい。

 この図は,Windows XPのアーキテクチャを表している。最初に注目してほしいのは,カーネル・モードの方だ。ここには「システム・サービス・ディスパッチャ」および「HAL(ハードウエア抽象化レイヤー)」と呼ばれるブロックがある。

 「システム・サービス・ディスパッチャ」はユーザー・モードとカーネル・モードの切り替えを担当するのだが,今回はこの機能を説明するわけではない。「システム・サービス・ディスパッチャ」は単にユーザー・モードのプログラムからシステムの呼び出しをされると,割り込みが発生するのでコール番号を確認して,カーネル・モードに切り替えているだけである。

 一方,HALはハードウエアとの橋渡しを行う。NTがIntel以外のプロセッサをサポートしていた時代は,このHALが,プロセッサの違いを吸収していた。

 システム・サービス・ディスパッチャの下には「I/Oマネージャ」「オブジェクト・マネージャ」などの各種マネージャが動作し,OSの「カーネル」はこれらマネージャを制御している。この「マネージャ」と呼ばれるプログラムには多くの種類があり,後々この連載の中でも詳しく解説していく。今回は,この中の「ローカル・プロシージャ・コール」というマネージャが重要な鍵を握っているので覚えておいてほしい。

 次に,ユーザー・モード側を説明しよう。こちらはアプリケーションが動作するモードである。ここで注目するのは,Windowsサブシステムと呼ばれるブロックだ。実はこのブロックには,Windows API(アプリケーション・プログラミング・インターフェース)が実装されている。詳細は後述するが,16ビットWindowsのアプリケーションやMS-DOSのアプリケーションなども,最終的にはこのWindowsサブシステムのAPIを実行する。

Windowsサブシステムが橋渡し役
 Windowsサブシステムこそが,ユーザー・モードとカーネル・モードを結びつける鍵なのである。Windowsサブシステムの主要な実体は,CSRSS.EXEと言うプログラムである。重要なのはこれが,Kernel32.dll,User32.dll,Gdi32.dllなどのDLLを管理していることだ。Kernel32.dllと聞くとピンとくるかもしれない。このDLLはいわゆる「Windows API」である。APIはアプリケーションがOSやミドルウエアの機能を利用するために使う関数の集合で,アプリケーションはこの関数を呼び出すことで,システムの機能を利用している。

 例えば,User32というDLLがあり,これはUSER関数の集合である。USER関数の仲間は,ウインドウやボタンなどのユーザー・インターフェースのコントロールを画面上に作成する。また,ボタンをマウスでクリックすると,Gdi32.dllのAPIが呼び出される。このAPIにユーザーからの要求が伝わると,その処理結果がグラフィックスのデバイス・ドライバへと渡され,ボタンが押されたようにビデオ画面が変化する。

△ 図をクリックすると拡大されます
図3●WindowsサブシステムはWindows APIを管理する
 このように,Windowsサブシステムは,アプリケーションから呼び出されるWindows APIの固まりと考えて差し支えない。アプリケーションから見れば,名前こそ「サブ」だが,Windowsサブシステムはシステムそのものと言って過言ではない(図3)。

 ところが実際には,アプリケーションが,実体としてのWindowsサブシステム内のAPIを直接呼び出せないのだ。なぜなら,アプリケーションとWindowsサブシステムは,ともにユーザー・モード上の,別個の仮想アドレス空間にあるからだ。その仮想アドレス空間はアプリケーションからは,1つのマシンとして見えるので,ここでは比喩として「仮想マシン」と呼ぶことにしよう。