このキーワード
友達に教える
URLをコピー

カーネルとは?

カーネルはアプリケーションソフトウェアとコンピュータのハードウェアを結び付ける。

カーネル(: kernel)は、階層型に設計されたオペレーティングシステム (OS) の中核となる部分である。アプリケーションとハードウェアレベルでの実際のデータ処理との間の架け橋である。システムのリソースを管理し、ハードウェアソフトウェアコンポーネントのやりとりを管理する。

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

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

概要

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

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

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

カーネルの機能

カーネルの仕事はコンピュータのリソースを管理し、他のプログラムがそれらのリソースを使って動作できるようにすることである。典型的なリソースとしては以下のものがある。

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

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

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

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

プロセス管理

詳細は「プロセス管理」を参照

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

プロセスは、アプリケーションがアクセスできるメモリの範囲を定義する。カーネルのプロセス管理は、ハードウェアの持つメモリ保護機構を考慮しなければならない。

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

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

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

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

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

メモリ管理

詳細は「メモリ管理」を参照

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

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

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

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

デバイス管理

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

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

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

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

システムコール

詳細は「システムコール」を参照

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

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

カーネル設計の観点

保護(プロテクション)のサポート

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

カーネルが提供する機構または方針は、いくつかの基準で分類できる。

などである。

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

代替手法は、階層型プロテクションでケイパビリティをシミュレートするものである。この場合、保護されたオブジェクトはアプリケーションがアクセスできないアドレス空間になければならない。カーネルもそのようなメモリ空間のケイパビリティのリストを保持する。ケイパビリティによって保護されたオブジェクトにアプリケーションがアクセスしたい場合、システムコールを行い、カーネルが実際のアクセスを代行する。これにはアドレス空間の切り替えを必要とするため、オブジェクト間で複雑なやりとりが必要なシステムでは性能が低下するが、現代のOSはアクセス頻度が低いオブジェクトや性能を要求されないオブジェクトについてはこの方式を採用している。保護機構をより高い階層でシミュレートする方式も可能だが(例えば、直接サポートされていないハードウェアについてのページテーブルを操作してケイパビリティをシミュレートするなど)、性能上の問題がある。言語ベースの保護を選択するシステムでは、ハードウェアサポートがなくても問題にならない。

カーネル設計における重要な点として、セキュリティの機構と方針を実装する抽象化レベルの選択がある。カーネルのセキュリティ機構は、高度なセキュリティをサポートする上で重要である。

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

現代の主流のOSの多くは重要なセキュリティ機構が欠如しているため、アプリケーションの抽象化レベルでの適切なセキュリティ方針実装ができないことがある。一般にカーネルサポートがどうであれ、アプリケーションで任意のセキュリティ方針を実装可能だとされているが、間違いである。

ハードウェアによる保護と言語による保護

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

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

この方式には次のような長所がある。

一方、次のような短所がある。

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

プロセスの協調作動

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

入出力デバイス管理

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

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

カーネル全体の設計方針

もちろん、上述したタスク群や機能群の提供方法は設計や実装の面で様々である。

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

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

Per Brinch Hansen は機構と方針の分離のための主張を展開した。すなわち、この分離が不適切であることが既存のOSで本質的技術革新が見られないことの主要因だとし、コンピュータアーキテクチャにおける共通課題だとした。モノリシック設計は、従来の商用システムで一般的な保護技法である「カーネルモード」と「ユーザーモード」に分離するアーキテクチャ(いわゆるリングプロテクション)から生まれた。そのアーキテクチャでは、保護(プロテクション)を必要とするモジュールを可能な限りカーネルに含めようとする。このようなモノリシック設計と特権モードの関係が機構と方針の分離における重要な問題として再注目されている。実際「特権モード」のアーキテクチャ技法は保護機構とセキュリティ方針を融合させる傾向があるが、これとは大きく異なるアーキテクチャ技法であるケイパビリティベースドアドレッシングではその2つを明確に区別し、自然にマイクロカーネル設計が可能となる。

モノリシックカーネルはカーネルの全コードを同じアドレス空間(カーネル空間)で実行するが、マイクロカーネルでは多くのサービスをユーザー空間で実行しようとし、コードベースの保守性とモジュール性を向上させようとしている。多くのカーネルは明確にどちらかに分類できるわけではなく、その中間の実装とも言うべきハイブリッドカーネルになっている。さらに特殊な設計としてナノカーネルやエクソカーネルが研究されているが、広く使われるまでには至っていない。エクソカーネルの例としてXenハイパーバイザがある。

モノリシックカーネル

詳細は「モノリシックカーネル」を参照
モノリシックカーネルの概念図

モノリシックカーネルでは、全OSサービスはひとつのカーネル空間内に存在し、カーネルスレッド上で実行される。この手法は強力なハードウェアアクセスを提供する。UNIXの開発者ケン・トンプソンは、モノリシックカーネルの方がマイクロカーネルより実装が容易だとしている。主な欠点はシステム構成要素間の依存関係の複雑さである。例えば、デバイスドライバにバグがあっただけでシステム全体がクラッシュするし、大きなカーネルは保守が非常に困難である。

Unix系OSが伝統的に採用してきたモノリシックカーネルは、OS中核機能とデバイスドライバを全て含んでいた。デバイスドライバ、スケジューラ、メモリ管理、ファイルシステム、ネットワークのプロトコルスタックなど、多くのプログラムが必要とするがライブラリとしてユーザー空間で実行することができない機能は、全てカーネル空間に置かれた。それら全サービスへのアクセスを可能にするため、数多くのシステムコールがアプリケーションに対して提供されている。

必要とされないサブシステムを伴って最初からロードされるモノリシックカーネルは、より汎用的な意味ではあるが、特定ハードウェア向けに設計されたものよりもチューニングが可能である。LinuxFreeBSDなどの現代のモノリシックカーネルはUnix系OSであり、実行時にモジュールをロードする機能を備えており、必要に応じて容易に機能を拡張でき、同時にカーネル空間で動作するコード量をなるべく最小に抑えることができる。モノリシックカーネルには次のような長所がある。

モノリシックカーネルはシステムコールの延長で動作する部分がほとんどである。システムコールは一般にテーブル構造で保持されるインタフェースであり、ディスク操作などのカーネル内サブシステムへのアクセスを行う。プログラム内でライブラリルーチンを呼び出すと、その中で要求をチェックしてコピーし、システムコールに渡す。したがって、それほど重い呼び出しではない。Linuxカーネルはモノリシックだがかなり小さくできる。これは、ローダブル・カーネル・モジュール機能と、カスタマイズが容易なためである。実際、フロッピーディスク1枚にカーネルだけでなく多数のユーティリティを搭載し、それだけで完動するOSとすることもできる(最も有名な例として muLinux がある)。このカーネルを小型化できる能力があるため、Linuxは組み込みシステムで急速に採用が増えている(組み込みLinux)。

このようなカーネルはOSの中核機能とデバイスドライバから成り、実行時にモジュールをロードする機能を備えている。それらによって、下層のハードウェアについての豊富で強力な抽象化を提供する。それらは単純なハードウェア抽象化の小さなセットを提供し、サーバと呼ばれるアプリケーションを使ってさらなる機能を提供する。この特定の手法でハードウェア上の高度な仮想インタフェースを定義し、プロセス管理、並行性管理、メモリ管理といったスーパーバイザモードで動作するいくつかのモジュールでOSサービスを実装し、システムコールでそれらを呼び出せるようにしている。しかし、このような設計には以下のような短所や制約がある。

マイクロカーネル

詳細は「マイクロカーネル」を参照
マイクロカーネル方式では、カーネルはサーバの実行に必要な最小限の機能をカーネルに持たせ、それ以外のカーネル機能(デバイスドライバ、GUIなど)はサーバという別個のプログラムで実装する。

マイクロカーネルとは、伝統的な「カーネル」から「サーバ」群に機能を移転するOS設計方針を意味し、最小化したカーネルだけをカーネル空間に残し、サーバ群を可能な限りユーザ空間で動作させる。マイクロカーネルでは、ハードウェアの単純な抽象化と最小のプリミティブ(システムコール)で最小のOSサービスを実装する(メモリ管理マルチタスクプロセス間通信など)。他の全てのサービス(ネットワークなど)は「サーバ」としてユーザ空間に実装される。マイクロカーネルはモノリシックカーネルよりも保守が容易だが、システムコール回数やコンテキストスイッチ回数が増大するために性能が低下する傾向がある。

どうしても特権モードでなければならない部分だけがカーネル空間に置かれる。それは、IPC(プロセス間通信)、基本スケジューラ(スケジューリング・プリミティブ)、基本メモリハンドラ、基本I/Oプリミティブなどである。スケジューラ本体やメモリ管理、ファイルシステム、ネットワークスタックといった大部分はユーザ空間で動作する。マイクロカーネルは、システム機能全体がプロセッサのシステムモードで動作する1つのプログラムになっているモノリシックカーネルの設計方針への反発から生まれた。マイクロカーネルを採用したOSとしては、QNXGNU Hurd がある。マイクロカーネルは基本的に次のような長所を持つ。

2010Happy Mail