回答:
カーネルは、起動時に、各行の割り込みハンドラーを指す割り込みベクターテーブル(x86では割り込み記述子テーブルまたはIDT と呼ばれます)を初期化します。
80286より前は、IDTは常に固定アドレスに保存されていました。80286以降、IDTはLIDT
命令を使用してロードされます。
割り込みベクターテーブルは、割り込み行ごとに1つのハンドラーを指します。そうは言っても、カーネルは、たとえば、他のいくつかの割り込みルーチンを実行する割り込みハンドラーを提供するか、一部またはすべての割り込みをカバーする単一のハンドラーを提供するかを選択できます。Linuxは、どの割り込みラインが呼び出されたかを判断し、呼び出す適切なダウンストリームハンドラーを見つける汎用割り込みハンドラーを提供することにより、これらのことを行います。
はい、ジャンプするコードのアドレスを含む定義済みの場所があります:割り込みベクター。プロセッサに応じて、これは物理メモリの特定の場所(8088)、仮想メモリの特定の場所、プロセッサレジスタ、レジスタによって示されるメモリの場所(ARM、386)などです。
詳細はプロセッサによって異なりますが、プロセッサで割り込みを処理するための主な共通要素は次のとおりです。
他の2つの回答(執筆時点)では、割り込みとIDTについて説明しています。これは正しいですが、最新のIntel風のCPUでは、カーネルを呼び出す方法は3つ以上あります。
方法#1:割り込み。
これは上で説明されています。割り込み記述子テーブル/割り込みベクトルにエントリを設定し、ソフトウェア割り込みを実行してカーネルに入ります。
この方法の主な利点は、典型的なカーネルがとにかく割り込みを処理できる必要があり、それが古風なハードウェアで動作することです。
方法#2:ゲートを呼び出します。
コールゲートは、特別な種類のセグメントセレクタです。呼び出しのターゲットは、グローバルまたはローカルセグメント記述子テーブル(それぞれGDTおよびLDT)にロードする必要があります。次に、コールゲートをセグメントとして使用してファーコール命令を実行すると(コールのオフセットは無視されます)、これにより、より多くの特権コードを呼び出すことができます。コールゲートは非常に柔軟です。IA-32アーキテクチャには4つの特権レベルがあり、コールゲートを使用して任意のレベルを呼び出すことができます。
Linuxがコールゲートを使用したことはないと思いますが、Windows 95は使用しました。Win95カーネルサービス(krnl386.exe
およびkernel.dll
)は、実際にはユーザーモード(リング3)で実行されました。最高の特権レベル(リング0)は、プロセスの切り替えのみを実行するドライバーとマイクロカーネルにのみ使用されました。ドライバーへの呼び出しは、コールゲートを使用して行われました。これにより、従来の16ビットコード(その多くがありました!)が、いつものように、標準のfar呼び出しを使用してWin95ドライバーを使用できるようになりました。
グローバル記述子テーブルの不適切な保護は、いくつかのWindows 95の悪用の原因であり、メモリを上書きすることで独自のコールゲートをインストールすることができました。
方法#3:SYSCALL / SYSRETおよびSYSENTER / SYSEXIT
これらは、AMDとIntelが独自に発明した2組の命令ですが、基本的に同じことを行います。SYSCALL / SYSRETが最初に登場し、AMDのみでした。SYSENTER/ SYSEXITはIntelでしたが、AMDは現在実装しています。そこで、SYSENTER / SYSEXITについて説明します。
コールゲートとは異なり、SYSENTERはリング0への転送にのみ使用でき、1つの場所にのみ転送できます。ただし、呼び出しや割り込みとは異なり、スタックに触れないため、レイテンシが非常に低いという利点があります。
転送場所は、3つのモデル固有のレジスタを使用して設定されます。1つはセグメント情報用で、もう1つはカーネルコードの命令ポインタとスタックポインタ用です。スタックには何も「プッシュ」されないため、ユーザーモードコードは、レジスタにリターン命令ポインターとスタックポインターを渡すことで、カーネルにどこに戻るかを指示します。カーネルはスタックポインターを復元し、SYSEXIT命令は命令ポインターを復元します。