マイクロカーネル

マイクロカーネル（英: microkernel）とはオペレーティングシステムの設計思想、及びそのようなOSのカーネル部の名称である。OSが担う各種機能のうち、必要最小限のみをカーネル空間に残し、残りをユーザーレベルに移すことで全体の設計が簡素化でき、結果的にカスタマイズ性が向上し、性能も向上できるというOSの設計手法のことである。カーネル本体が小規模な機能に限定されるので「マイクロカーネル」と呼ばれるが、必ずしも小さなOSを構成するとは限らない。
マイクロカーネルの出現に伴い、従来型のOSを「モノリシックカーネル（一枚岩のカーネルという意）」と呼ぶようになった。マイクロカーネルの思想を更に推し進めたナノカーネルも提唱されている。

プロセス間通信

プロセス間通信 (IPC) とは、プロセス間の通信を可能にする何らかの機構であり、メッセージ送信がよく使われる。共有メモリも厳密にはプロセス間通信機構の一種だが、マイクロカーネルでIPCといえば一般にメッセージを指す。IPCにより、OSをサーバといういくつかの小さなプログラムで構築することができ、IPCを使ってサーバを他から呼び出すことができる。周辺ハードウェアのサポートもそのように実装でき、サーバにはデバイスドライバ、ネットワークのプロトコルスタック、ファイルシステム、グラフィックスなど様々なものがある。
IPCには同期式と非同期式がある。非同期IPCはネットワーク通信に似ている。送信側はメッセージを発行して処理を継続する。受信側はメッセージの到着を定期的にチェックするか、何らかの検出機構で通知される。非同期IPCではカーネルがメッセージ用のバッファとキューを管理しており、バッファオーバーフローもカーネルが扱う。また、メッセージは2回コピーされる（送信側からカーネル、およびカーネルから受信側）。同期IPCでは、送信側か受信側はもう一方がIPC可能となるまでブロックされる。バッファリングも複数回のコピーも不要だが、明示的に両者が待ち合わせる必要があるため、プログラミングに巧妙さを必要とする。多くのプログラマは非同期送信と同期受信を好む。
第一世代のマイクロカーネルは一般に同期IPCも非同期IPCもサポートしていたが、その性能は悪かった。Jochen Liedtke はその原因がIPC機構の設計と実装にあることを示した。彼はL4マイクロカーネルでIPCコストを10分の1以下にした。IPCは送信も受信もシステムコールでサポートされ、同期式のみであり、レジスタでなるべく多くのデータを渡すようにしている。さらに Liedtke は direct process switch という概念を導入し、IPCの際に送信側から受信側へ直接（不完全な）コンテキストスイッチを行うようにした。そのためL4では、メッセージの一部または全部をレジスタ群で渡す場合、レジスタ内のメッセージは全くコピーせずに転送することができる。さらにスケジューラを呼び出すオーバーヘッドを排除している。これは特に遠隔手続き呼出し (RPC) 的にサーバを呼び出す際のIPCに適している。もう1つの最適化として lazy scheduling と呼ばれるものがあり、IPC中にスケジューリングキューを走査せずに済むようするため、IPC中はスレッドをレディキューでブロックしたままにする。スケジューラが呼び出されると、そのようなスレッドを適当な待ちキューに移す。
クライアント・サーバ型システムでは多くの通信が基本的に同期式であり、非同期なプリミティブを使っていたとしても、通常はクライアントがサーバを呼び出し、応答を待つことになる。その方が実装も効率的になるため、L4以降のマイクロカーネルでは同期IPCプリミティブのみを提供するようになった。非同期IPCは補助スレッドを使って同期IPCプリミティブ上で実装できる。しかし、L4を採用した商用製品では非同期通信サポートのために非同期通知機構が必要であることが判明し、それを追加している。このシグナルのような機構はデータを転送するものではなく、カーネルによるバッファリングが不要である。
同期IPCでは通信の一方が応答可能になるまでもう一方がブロックされる。したがって無制限にIPCを使用すると容易にデッドロック状態が発生する。また、クライアントが要求を送って応答を待ち合わせないようにすると、容易にDoS攻撃のような状態になる。したがって同期IPCでは長期に渡るブロックを防ぐ手段を提供しなければならない。多くのマイクロカーネルはIPC呼び出しにタイムアウトを提供しており、ブロック時間を制限している。実際にはタイムアウト時間の設定は難しく、結果としてクライアントのタイムアウトは無制限、サーバのタイムアウトはゼロとすることが多い。結果としてタイムアウト時間を任意に設定できるようにせず、相手が応答可能でない場合にIPCを即座に失敗させるかどうかを示すフラグだけを用意する傾向になってきた。それによってタイムアウト時間としてゼロか無制限かを選択することになる。L4やMINIXの最近のバージョンもそのようになっている（QNXや以前のL4ではタイムアウト時間を任意に設定できる）。

サーバ

マイクロカーネルでのサーバはデーモンのようなものだが、一部のサーバは物理メモリ空間の一部にアクセスできる特権を与えられている。それによりデバイスドライバのサーバがハードウェアと直接やりとりできるようになっている。
汎用マイクロカーネルにおける基本的サーバとしては、ファイルシステムサーバ、デバイスドライバサーバ、ネットワークサーバ、ディスプレイサーバ、ユーザインタフェースデバイスのサーバなどがある。これらのサーバ群でUnix系のモノリシックカーネルの提供するサービスをほぼカバーしている。必須サーバは立ち上げ時に起動してサービスを開始する。サーバはユーザーアプリケーションと同様の環境で動作し、その開発もアプリケーションと似ている。カーネル開発で必要となる頻繁なビルドとリブートは不要である。
さらに、サーバで障害が発生してもシステム全体がクラッシュすることはなく、単にそのサーバを再起動すればよい。しかし、サーバで障害が発生することでシステム状態の一部が失われることがあるため、アプリケーション側もサーバ障害に対応する必要がある。例えば、TCP/IP接続を担うサーバがあるとする。このサーバを再起動すると、アプリケーションから見てコネクションが失われることになるが、これは通常のネットワークでも起き得る障害である。しかしアプリケーションが障害発生を予期していないサービスの場合、アプリケーションのコードを修正する必要がある。QNXではサーバの再起動への対応として QNX High Availability Toolkit が提供されている。
全サーバを再起動可能にするため、トランザクションやレプリケーションやチェックポインティングといったデータベース的技法を取り入れているマイクロカーネルもある。例えば ChorusOS があり、電気通信業界の高信頼アプリケーション用にそのような機能を備えている。

デバイスドライバ

Direct Memory Access (DMA) を頻繁に行うデバイスドライバは、カーネルのデータ構造を含めた物理メモリの任意の位置に書き込める必要がある。そのようなドライバは信頼されていなければならないが、必ずしもカーネル内に含まれている必要はない。実際、カーネルの一部だからといってデバイスドライバがより信頼できるというわけではない。
デバイスドライバをユーザー空間で動作させたとしても、ドライバが発生しうる障害のダメージが低減されることはないが、バグのあるドライバによってシステムの安定性が影響を受けにくくするという効果はある（悪意あるドライバの場合はその限りではない）。（デバイスではなく）ドライバのコード自体が不正なメモリアクセスを行う場合、メモリ管理ハードウェアが捉えることになる。さらにDMAを行わないデバイスでは、ユーザー空間で動作させることでドライバを信頼されないもの（特権が不要なもの）とすることができる。最近ではIOMMUを備えたコンピュータが増えており、IOMMUを使ってデバイスの物理メモリアクセスを制限できることが多い。これもユーザーモードのドライバを信頼されないものとすることができる。
ユーザーモードのドライバは実際にはマイクロカーネルより古くから存在する。1967年の Michigan Terminal System (MTS) で初めて（ファイルシステムも含めた）ユーザー空間のドライバがサポートされた。歴史的には、ドライバをカーネルに含めることはあまり問題とされなかった。周辺デバイスの数は少なく、特権が必須だったためであり、カーネルに含めることで性能問題を防いでいた。Unixもそのスタイルを踏襲し、Linuxや Windows XP 以前のWindowsも同様だった。デバイスの種類が豊富になってくると、ドライバのコード量も増大するようになり、カーネル全体に占める割合も増えていった。

性能

多くの主流のプロセッサにおいて、サービスを得るのにかかるコストはモノリシックカーネルよりもマイクロカーネルの方が本質的に高い。モノリシックなシステムでは、サービスを得るのに1回のシステムコールを使用し、その際に2回の「モード切り換え」（プロセッサのリングまたはCPUモードの変更）を必要とする。マイクロカーネルを採用したシステムでは、サービスを得るにはサーバにIPCメッセージを送り、別のIPCメッセージで結果を得る必要がある。このときドライバがプロセスとして実装されていればコンテキストスイッチが必要であり、プロシージャとして実装されていれば関数呼び出しが必要である。さらに実際にデータをサーバに渡して結果のデータを戻してもらうには、データをコピーするオーバヘッドが余分にかかる。モノリシックカーネルでは、クライアント（ユーザー空間）の持つバッファにあるデータに直接アクセス可能である。
したがってマイクロカーネルシステムには性能問題が潜在している。実際、MachやChorusOSといった第一世代のマイクロカーネルを採用したシステムの性能は低かった。しかし Jochen Liedtke はMachの性能問題は設計と実装がまずかったためであることを示し、特にMachがページキャッシュを使いすぎていることを指摘した。Liedtke は自身のL4マイクロカーネルを注意深く設計・実装することで、特に極小原則に従えばIPCコストをMachの10分の1以下にできることを証明した。L4のIPC性能は様々なアーキテクチャ上で最速を誇った。
そういった結果により、第一世代のマイクロカーネルの性能の低さは第二世代のL4などのマイクロカーネルには当てはまらないことを示したが、マイクロカーネルをベースにしたシステムが高性能を発揮できることを証明したわけではなかった。それでもモノリシックなLinuxサーバをL4上に移植したものは、通常のLinuxに対して数パーセントのオーバーヘッドを示しただけだった。しかし、単一サーバシステムはマイクロカーネルの利点を生かしているとは言い難く、OSの機能を複数のサーバに分離したときの性能が重要だとされた。
複数サーバの商用システムはいくつか存在しており、例えばリアルタイムオペレーティングシステムのQNXやIntegrityがある。そういったシステムとモノリシックなシステムとの包括的性能比較は公表されたことがない。さらに言えばそれら商用システムでは性能が最重要課題ではないようで、割り込み応答時間の保証や頑健性のための単純さが強調されている。複数サーバの高性能OSを構築する試みとしてIBMの Sawmill Linux というプロジェクトがあった。しかし、このプロジェクトは完了することなく中止された。
同じころ、ギガビット・イーサネットのような高速デバイスのデバイスドライバをユーザーレベルで実装したものが、カーネル内のデバイスドライバと同等の性能を発揮することが示されている。これは複数サーバの高性能システムが構築可能であることを示唆している。

セキュリティ

マイクロカーネルはセキュリティ面で優れているとよく言われてきた。セキュリティの観点では、マイクロカーネルの極小原則は、全てのコードについて必要とされる機能を提供するのに必要な権限だけを持つべきであるという最小権限の原則の直接的帰結である。極小性は、システムのトラステッド・コンピューティング・ベース (TCB) を極小に保つべきであることを要求する。カーネル（ハードウェアの特権モードで実行されるコード）は常にTCBの一部であり、セキュリティ指向設計ではそれを極小化するのが自然である。
結果として、マイクロカーネル設計は高度なセキュリティを要求される用途で採用されており、例えばKeyKOS、EROS、軍用システムなどがある。実際、コモンクライテリア (CC) の最高保証レベル（評価保証レベル (EAL) 7）では、対象の評価が「単純」であること、複雑なシステムの真の信頼性を確立するのに実際的不可能性を確認できることを明示的に要求している。

第三世代

近年のマイクロカーネル研究開発は、カーネルAPIの形式仕様とそのAPIのセキュリティ属性の形式的証明に集中している。第一の例として、EROSでの隔離機構の数学的証明があり、EROS API を単純化したモデルに基づいている。より最近の例として、L4のバージョンの一種である seL4 のプロテクションモデルについて自動検証された包括的な証明がなされている。
それにより「第三世代マイクロカーネル」と呼ばれるものが生まれている。これはセキュリティ指向のAPI、ケイパビリティによるリソースアクセス制御、最重要概念としての仮想化、カーネル資源管理への革新的アプローチ、形式的分析に適した設計、などを特徴としつつ、性能向上を目標としたものである。例として、Coyotos、seL4、Nova、Fiasco.OCなどがある。
seL4の場合、実装についての完全な形式的検証がなされており、形式仕様と実装が一致していることが数学的に証明されている。それにより、APIについて証明された属性が実際のカーネルでも保持されていることが保証でき、CC EAL7 をも越える保証の程度となっている。