thumb|カーネルはアプリケーションソフトウェアとコンピュータのハードウェアを結び付ける。 カーネル()は、階層型に設計されたオペレーティングシステム (OS) の中核となる部分で、アプリケーションとハードウェアの架け橋である。具体的には、システムのリソースや、ハードウェアとソフトウェアの連携を管理する。そのほか、通信制御を行うことが多い。

オペレーティングシステムの基本コンポーネントとして、カーネルはメモリ、CPU、入出力を中心としたハードウェアを抽象化し、ハードウェアとソフトウェアがやり取りできるようにする。また、ユーザープログラムのための機能として、プロセスの抽象化、プロセス間通信、システムコールなどを提供する。

これらのタスクはカーネルによって方式が異なり、設計や実装も異なる。モノリシックカーネルは全てを一つの仮想アドレス空間に格納されたコードで実行して性能を向上させようとする。マイクロカーネルはサービスの大部分をユーザー空間で実行し、コードの保守性とモジュール性を向上させようとするAn overview of Monolithic and Micro Kernels, by K.J.。多くのカーネルはこの二つのカテゴリのいずれか、あるいは中間である。

概要 全てではないが、多くのオペレーティングシステム (OS) はカーネルを内包する。ハードウェアとソフトウェアの間の通信を管理するソフトウェアとしてのカーネルは、性能、メモリ効率、セキュリティ、プロセッサのアーキテクチャなどが複雑に絡んだ問題への妥協的解答である。

多くの場合、ブートローダーがカーネルを特権モードのプロセスとして起動する最上位の特権レベルは、スーパーバイザーモード、カーネルモード、CPL0、リング0など様々な呼称がある。。しかし、初期化が完了すると、カーネルはいわゆるプロセスとしては存在せず、ディスクアクセスなどの高い特権レベルを必要とする処理を必要としたときにユーザプログラムから呼び出される機能の集合体として存在することになる。カーネルの処理の流れはユーザープロセスの処理の流れの延長上にあり、システムコールによってカーネルに処理がわたり、終了するとユーザーに戻っていく。初期化時のコンテキストはそのまま消えるようにする設計もあるが、「アイドルプロセス」とか「collects」と呼ばれる、プロセッサが何もすることがないときに実行されるコードに流用される設計とすることもある。省電力のため、プロセッサが「休む」ような命令を繰り返すようなコードとすることも多い。

カーネル開発はプログラミングの中でも複雑で難しいタスクのひとつと考えられる。オペレーティングシステムの中核部であるということは、高い性能を要求される最重要なソフトウェアであり、正しく設計し実装することは難しい。カーネルはユーザプログラムの互換性や移植性を考慮する必要などから、設計が制限されることがあり、そのことがさらに開発を難しくしている。

カーネルの機能 カーネルの仕事はコンピュータのリソースを管理し、他のプログラムがそれらのリソースを使って動作できるようにすることである。典型的なリソースとしては以下のものがある。 CPU(プロセッサ)。コンピュータの中心となる部分で、プログラムの実行を分担する。カーネルは、多数のプログラムの中からプロセッサ(群)を割り当てるべきものを選択する。基本的にプロセッサは一度に1つのプロセスしか実行できない(複数実行できる場合、カーネルは複数のプロセッサとして認識する)。 メモリ。メモリにはプログラムとデータの両方が格納されるBona Fide OS Development - Bran's Kernel Development Tutorial, by Brandon FriesenCPU時間は理論上無限だが、メモリ容量とそのアクセス速度は有限であることに注意すべきである。。一般にプログラムを実行するには、プログラムとデータの両方がメモリ上になければならない。複数のプログラムがメモリへのアクセスを要求すると、実際に搭載している以上のメモリが必要とされる場合がある。カーネルは各プロセスにメモリを割り当て、全体としてメモリが不足した場合の対処を決定する。 コンピュータには何らかの入出力デバイスがある(キーボード、HDD、USBなど)。カーネルはアプリケーションから入出力要求を受け付け、適切なデバイス(あるいはデバイスの一部、たとえばファイルやウィンドウなど)に対して入出力を実行し、デバイスを使用するための便利な方法を提供する(一般に、アプリケーションがデバイスの実装の詳細を知らなくてもすむように抽象化する)デバイスドライバをカーネルの一部とみなさない考え方もあるが、たとえばリアルタイムクロックなどはカーネル自身が管理する。。

リソース管理に必要な重要な観点は、実行領域(アドレス空間)の定義とその領域内のリソースへのアクセスを調停する保護機構である。

また、カーネルは一般にプロセス同士の同期と通信の手段も提供しており、プロセス間通信 (IPC) と呼ぶ。

カーネルは自前でそれらの機能を実装していることもあるし、何らかのプロセスに委任していることもあるが、後者の場合はプロセス間で機能へのアクセスを可能にするIPCを提供する必要がある。

最後に、カーネルはそれら機能群へのアクセスを要求する手段をプログラムに提供しなければならない。

プロセス管理

カーネルの主な仕事はアプリケーションの実行を許可し、ハードウェア抽象化などの機能によってそれをサポートすることである。

プロセスは、アプリケーションがアクセスできるメモリの範囲を定義する。カーネルのプロセス管理は、ハードウェアの持つメモリ保護機構を考慮しなければならないNeedham, R.M., Wilkes, M. V. Domains of protection and the management of processes, Computer Journal, vol. 17, no. 2, May 1974, pp 117–120.。

カーネルはアプリケーションを実行するためアドレス空間を設定し、アプリケーションのコードを含むファイルをメモリにロードし、プログラムのためのコールスタックを設定し、そのプログラムの所定の位置に制御をわたすことで実行を開始する。

マルチタスク可能なカーネルは、ユーザーから見て実際にそのコンピュータが同時実行できるプロセス数よりも、多数のプロセスが同時並行して実行されているかのようにみせかける。一般にシステムが同時並行して実行できるプロセス数は、そのシステムの持つCPU数に等しい(同時マルチスレッディングをサポートしている場合はそのかぎりではない)。

プリエンプティブ・マルチタスクシステムでは、カーネルは各プログラムにタイムスライス(そのプログラムがCPU上で実行される連続時間)を与え、プロセスからプロセスへと高速に切り換えていくので、ユーザーから見ればそれらのプロセスが同時並行して実行されているように見えるのである。カーネルは次に実行すべきプロセスを決定し、タイムスライスの長さを決定するスケジューリングアルゴリズムを持つ。一般にプロセスには優先度が設定される。カーネルはそれらのプロセス間の通信手段も提供する。これはプロセス間通信 (IPC) と呼ばれ、パイプ、共有メモリ、メッセージ、RPC、ソフトウェア割り込みなどがある。

ほかに協調型マルチタスクもあり、各プロセスは自らカーネルに制御を戻すまで割り込まれずに実行を続けることができる。制御をカーネルに戻すことを "yielding" と呼び、プロセス間通信の際や何らかのイベントを待つ際に行われ、そのときにカーネルが別のプロセスを動作させる。古い Windows や Mac OS はこの方式だったが、コンピュータの性能向上に伴ってプリエンプティブ方式に切り換えたhttps://web.archive.org/web/20130731005237/http://www.answers.com/topic/operating-system。

オペレーティングシステムは、マルチプロセッシング(SMPやNUMA)をサポートすることもある。この場合、複数のプログラムやスレッドが複数のプロセッサ上で動作する。そのようなシステムでカーネルを動作させる場合、「再入可能(リエントラント)」あるいは「割り込み可能」になるよう大幅な改造が必要となる。これはつまり、何か処理をしている最中にほかからも要求を受け付けるということである。この改造ができれば、異なるプロセッサ上で動作するプログラムが同時にカーネルを呼び出しても大丈夫になる。カーネルは複数のプロセッサからのメモリアクセスを同期させる方法(スピンロックなど)も提供しなければならない。これはメモリ管理とプロセス管理にまたがる問題である。

メモリ管理

カーネルはシステムの全メモリへの無制限のアクセスが可能で、ユーザープロセスの要求に応じて安全なメモリアクセスを提供しなければならない。このための第一歩はページング方式やセグメント方式による仮想アドレッシングである。仮想記憶方式では、カーネルは物理アドレスを別のアドレス、つまり仮想アドレスに変換する。これにより、各プログラムは(カーネル以外では)仮想空間上唯一のコードに見え、プログラムが互いに他のプログラムを破壊することを防止する。

多くのシステムで、あるプログラムの仮想アドレスはメモリ上にないデータを指していることがある。仮想アドレッシングによるインダイレクション層は、本来なら主記憶 (RAM) になければならないデータをハードディスクなどの補助記憶装置に退避させることを可能にする。結果としてOSは物理的な容量以上のメモリをプログラム群に提供可能となる。RAMにないデータがあるプログラムで必要になった場合、CPUはカーネルにそれを知らせ(ページフォールト)、(必要なら)カーネルが使われていないメモリブロックの内容をディスクに退避させ、必要なデータをそのメモリブロックに復帰させる(ページ置換アルゴリズム)。すると、プログラムは要求を行った時点から処理を再開させることができる。これをデマンドページングと呼ぶ。

仮想アドレッシング方式では、仮想空間をカーネル用の部分(カーネル空間)とアプリケーション用の部分(ユーザー空間)に分けることができる。アプリケーションはカーネル用メモリにアクセスできないので、アプリケーションにバグがあったとしてもカーネルにダメージを与えることはない。この根本的な分離は多くの汎用カーネルで実際に使われているが、別の方式を採用したカーネルの研究も行われている(たとえば、Singularity)。

メモリ管理のもうひとつの機能として、カーネル内の各モジュールやデバイスドライバが使用するメモリの割り当てがある(動的メモリアロケーション)。

デバイス管理 実際に何らかの作業をするには、OSはコンピュータに接続された周辺機器にアクセスする必要があり、周辺機器はその開発元などが書いたデバイスドライバを通して制御される。デバイスドライバはOSがハードウェアデバイスとやりとりするためのプログラムであり、OSに対して何らかのハードウェアを制御・通信するための情報を提供する。ドライバはアプリケーションにとっても重要で不可欠である。ドライバの設計目標は抽象化である。ドライバの機能はOSの定めたインタフェースからデバイス固有のインタフェースに変換することである。理論上、デバイスは適当なドライバがあれば正しく動作する。デバイスドライバは、ビデオカード、サウンドカード、プリンター、スキャナー、モデム、LANカードなどに対応して存在する。一般的なデバイスドライバの抽象化レベルを次に示す。

ハードウェア側から見て 直接インタフェースする。 高度なインタフェースを使用する(ビデオBIOSなど)。 低レベルなデバイスドライバを使用する(ディスクドライバを使用するファイルシステムドライバなど) ハードウェアとともにシミュレーションを行う。すなわち、実際には全く異なる何かを行う(廃れたデバイスの代わりに最新のデバイスを使用するなど)。 ソフトウェア側から見て OSがハードウェア資源に直接アクセスできるようにする。 ドライバとして基本的な部分だけを実装。 ドライバ以外のソフトウェアとのインタフェースを実装(たとえば、TWAIN)。 何らかの高度な言語を実装(たとえばPostScript)。

たとえば、ユーザー向けに何かを画面に表示する場合、アプリケーションがカーネルに要求し、その要求がディスプレイドライバに送られ、ディスプレイドライバが実際の文字やピクセルの描画を行う。

カーネルは使用可能なデバイスの一覧を保持しなければならない。この一覧は、事前に知られている場合(たとえば、組み込みシステムでは利用可能なハードウェアが変われば、カーネルを書き換える)、ユーザーが設定する場合(古いPCや個人用に設計されていないシステムなど)、OSが実行時に検出する場合(プラグアンドプレイ)がある。プラグアンドプレイのシステムでは、デバイス管理は最初にさまざまなバス(PCIやUSB)上をスキャンして実装されたデバイスを検出し、対応するドライバを探す。

デバイス管理は各OS固有の部分であり、カーネルの設計によってドライバの扱い方は異なるが、一般にカーネルはドライバが物理的にデバイスにアクセスするための入出力ポートやメモリ空間を用意する必要がある。デバイスへのアクセスはコンテキストスイッチを引き起こしたり、CPUを浪費したりすることになりやすく、性能オーバヘッドの元となるため、デバイス管理の設計は重要である。

システムコール

意味のある作業を実行するには、ユーザプログラムはカーネルの提供する全サービスにアクセスできなければならない。これはカーネルによって実装が異なるが、多くは標準CライブラリやAPIが提供され、そこから対応するカーネル機能が呼び出される。

カーネル機能を呼び出す方法は主にCPUがどのような機能を提供しているかに依存する。カーネル空間とユーザー空間が分離されている場合、ユーザープロセスが直接カーネルを呼び出すことはできない。たとえば以下のような技法を採用する。

例外処理や割り込みを明示的に発生する命令(トラップ命令、ソフトウェア割り込み)を使用。多くのハードウェアで実装されている技法である。 コールゲートを使用。x86で採用されている。 特別なシステムコール命令を使用。最近のx86で実装された。 メモリ上のキューを使用。仮想空間の所定の位置にユーザープロセスが要求を投入できるキューを用意し、カーネルがそこから定期的に要求を読み取って実行する。即時性が要求されない場合で、プロセスから複数の要求を行う場合に便利である。

カーネル設計の観点 保護(プロテクション)のサポート カーネル設計において重要な観点として、障害(フォールトトレラント性)と悪意ある動作(セキュリティ)からの保護(プロテクション)サポートがある。この2つは通常明確には区別されず、明確に区別しようとするとリングプロテクションでは対応できなくなる。

カーネルが提供する機構または方針は、いくつかの基準で分類できる。 静的(コンパイル時に決定)か動的(実行時に決定)か プリエンプティブか事後検出か それらが満足する保護原理による分類(デニング quote: "isolation, resource control, decision verification (checking), and error recovery.") ハードウェアサポートによる保護か言語サポートによる保護か オープンな機構によるものか、方針と密に結合しているか などである。

階層型プロテクションは、一般に「CPUモード」でサポートされる。ハードウェアサポートによる単純で効率的な方法は、MMUにメモリアクセスのたびにその妥当性をチェックさせるもので、その機構をと呼ぶ。ただし、多くの商用コンピュータアーキテクチャではMMUがケイパビリティをサポートしていない。

代替手法は、階層型プロテクションでケイパビリティをシミュレートするものである。この場合、保護されたオブジェクトはアプリケーションがアクセスできないアドレス空間になければならない。カーネルもそのようなメモリ空間のケイパビリティのリストを保持する。ケイパビリティによって保護されたオブジェクトにアプリケーションがアクセスしたい場合、システムコールを行い、カーネルが実際のアクセスを代行する。これにはアドレス空間の切り替えを必要とするため、オブジェクト間で複雑なやりとりが必要なシステムでは性能が低下するが、現代のOSはアクセス頻度が低いオブジェクトや性能を要求されないオブジェクトについてはこの方式を採用しているStephane Eranian and David Mosberger, Virtual Memory in the IA-64 Linux Kernel, Prentice Hall PTR, 2002。保護機構をより高い階層でシミュレートする方式も可能だが(たとえば、直接サポートされていないハードウェアについてのページテーブルを操作してケイパビリティをシミュレートするなど)、性能上の問題がある。言語ベースの保護を選択するシステムでは、ハードウェアサポートがなくても問題にならないA Language-Based Approach to Security, Schneider F., Morrissett G. (Cornell University) and Harper R. (Carnegie Mellon University)。

カーネル設計における重要な点として、セキュリティの機構と方針を実装する抽象化レベルの選択がある。カーネルのセキュリティ機構は、高度なセキュリティをサポートする上で重要であるJ. Lepreau et al. The Persistent Relevance of the Local Operating System to Global Applications. Proceedings of the 7th ACM SIGOPS European workshop, 1996.J. Anderson, Computer Security Technology Planning Study, Air Force Elect. Systems Div., ESD-TR-73-51, October 1972.。

1つの方式として、ファームウェアとカーネルでフォールトトレラント性をサポートする方式があり、その上に悪意ある動作に対するセキュリティ方針を構築し(必要に応じて暗号機構を追加する)、一部の責任をコンパイラに委任する。コンパイラやアプリケーションレベルへのセキュリティ方針の責任委譲の方式を一般に「言語ベースのセキュリティ」と呼ぶ。

現代の主流のOSの多くは重要なセキュリティ機構が欠如しているため、アプリケーションの抽象化レベルでの適切なセキュリティ方針実装ができないことがあるP. A. Loscocco, S. D. Smalley, P. A. Muckelbauer, R. C. Taylor, S. J. Turner, and J. F. Farrell. The Inevitability of Failure: The Flawed Assumption of Security in Modern Computing Environments. In Proceedings of the 21st National Information Systems Security Conference, pages 303–314, Oct. 1998.。一般にカーネルサポートがどうであれ、アプリケーションで任意のセキュリティ方針を実装可能だとされているが、間違いである。

ハードウェアによる保護と言語による保護 現代の一般的コンピュータは、ハードウェアが強制した規則を使ってプログラムのデータへのアクセスを許可している。プロセッサは動作を監視し、規則に違反したプログラムを停止させる(たとえば、カーネル空間のメモリを読み書きしようとしたユーザプロセスを停止させるなど)。ケイパビリティをサポートしていないシステムでは、プロセスは相互に隔離されたアドレス空間で動作する。ユーザプロセスがカーネルを呼び出すことは、上述したシステムコールの技法を使って統制されている。

代替手法として言語ベースの保護(プロテクション)がある。言語ベースのプロテクションシステムでは、カーネルは信頼されている言語コンパイラが生成したコードのみ実行を許可する。そしてその言語は、セキュリティに違反するようなコードをプログラマが書けないように設計されている。

この方式には次のような長所がある。 アドレス空間を分離する必要がない。アドレス空間の切り替えは低速な操作であり、オーバーヘッドになっているため、現代のOSではその切り替えをなるべく減らすような最適化に多大な労力を費やしている。言語ベースのプロテクションシステムではそのような切り替えが全く不要であり、全コードを同一アドレス空間に置いても安全に運用可能である。 柔軟性がある。プログラミング言語でプロテクション機構を表現できるよう設計すれば、この方式ではそれらを実装することが可能である。言語ベースのプロテクションを実現するのにハードウェアを新たに設計する必要はない。

一方、次のような短所がある。 アプリケーションの起動に時間がかかる。アプリケーションを起動する際に正しいコンパイラで生成されたものか、あるいはソースコードやバイトコードから再コンパイルが必要でないかをチェックする必要がある。 型システムが固定される。従来のシステムでは、アプリケーションはでない操作を頻繁に実行する。言語ベースのプロテクションシステムではそのような操作は許されないので、アプリケーションを書き換える必要があり、場合によっては性能が低下することになる。

言語ベースのプロテクションを採用したシステムとしては、JXやマイクロソフトのSingularityがある。

プロセスの協調作動 エドガー・ダイクストラは論理的観点から、バイナリセマフォにおける不可分なロックとアンロック操作だけで、プロセス間の任意の協調作動を実現できることを証明したDijkstra, E. W. Cooperating Sequential Processes. Math. Dep., Technological U., Eindhoven, Sept. 1965.。しかしそのような方式は一般に安全性や効率性が欠如しており、メッセージパッシング方式の方が柔軟性が高い。他の方式もいくつかあり、現代のカーネルでは共有メモリやRPCなどのシステムをサポートしていることが多い。

入出力デバイス管理 入出力デバイスを並行して協調作動する他のプロセス群から一様に扱えるようにするというカーネルの考え方は、Per Brinch Hansen が提唱し実装したのが最初である(似たような考え方は1967年にも示唆されていた)。Hansen はその説明で、「共通の」プロセス群を「内部プロセス」、入出力デバイスを「外部プロセス」と呼んでいる。

物理メモリと同様、アプリケーションがコントローラのポートやレジスタに直接アクセスすることを許可すると、コントローラが不正作動したり、システムがクラッシュすることになる。それに加えて、デバイスの複雑さに応じて対応するプログラムは非常に複雑化することがあり、しかも複数の異なるコントローラを使うことがある。そのため、デバイスを管理するためのより抽象化されたインタフェースを提供することが重要である。この抽象化を提供するのは一般にデバイスドライバや Hardware Abstraction Layer (HAL) である。アプリケーションは必要なら頻繁にデバイスへのアクセスを要求する。カーネルはシステムに接続されたデバイスの一覧を何らかの方法で保持しなければならない。これはBIOSや各種システムバスの機能(PCI/PCIeやUSB)を使ってなされる。あるアプリケーションがあるデバイス操作を要求すると(たとえばディスプレイに文字を表示する)、カーネルは対応するドライバ(たとえばビデオドライバ)に要求を送らなければならない。するとそのドライバがデバイスに対して必要な処理を行う。マイクロカーネルの場合、この際にプロセス間通信 (IPC) が使われる。

カーネル全体の設計方針 もちろん、上述したタスク群や機能群の提供方法は設計や実装の面でさまざまである。

「機構と方針の分離」の原則は、マイクロカーネルとモノリシックカーネルの哲学の間でかなり大きな相違がある。ここで、「機構」はさまざまな「方針」の実装を可能とするものであり、「方針」は特定の「操作のモード」である。たとえば「機構」面では、ユーザーがログインしようとしたとき認証サーバを呼び出してアクセスを認めるべきか否かを決定するということが考えられる。一方「方針」面では、認証サーバがパスワードを要求し、データベース内の暗号化されたパスワードと照合するかもしれない。機構が汎用的であれば、機構と方針が同一モジュールに統合されている場合よりも方針の変更(たとえば、パスワードの代わりにセキュリティトークンを使うなど)がより容易になる。

最小のマイクロカーネルでは非常に基本的な方針のみが含まれ、その機構はカーネル上で動作させるもの(OSの残りの部分やアプリケーション群)自身がどのような方針(メモリ管理、高度なプロセススケジューリング、ファイルシステム管理など)を採用するか決定することを可能にする。一方モノリシックカーネルは方針の大部分をカーネル内に含む傾向があり、結果としてその上の部分の自由度は制限される。

Per Brinch Hansen は機構と方針の分離のための主張を展開した。すなわち、この分離が不適切であることが既存のOSで本質的技術革新が見られないことの主要因だとし、コンピュータアーキテクチャにおける共通課題だとしたJürgen Nehmer The Immortality of Operating Systems, or: Is Research in Operating Systems still Justified? Lecture Notes In Computer Science; Vol. 563. Proceedings of the International Workshop on Operating Systems of the 90s and Beyond. pp. 77–83 (1991) quote: "The past 25 years have shown that research on operating system architecture had a minor effect on existing main stream systems." quote: "Although the complexity of computer applications increases yearly, the underlying hardware architecture for applications has remained unchanged for decades."。モノリシック設計は、従来の商用システムで一般的な保護技法である「カーネルモード」と「ユーザーモード」に分離するアーキテクチャ(いわゆるリングプロテクション)から生まれた quote: "Conventional architectures support a single privileged mode of