IRON MAIDEN

Linux の設計上、 CPU が割り込みに関連した実行パスを実行中は、プロセスを切り替えることは許されない。
?????割り込みハンドラって、別の割り込みハンドラに割り込まれる可能性があるじゃん。
あっ、これはプロセス切り替えじゃないからいいのか????
割り込みハンドラは例外処理に割り込み、その処理を遅延させることもありますが、例外ハンドラは割り込みハンドラに割り込むことはありません。
多分カーネルモードで発生する例外はページフォルトだけです。(いい加減ですが、あってるでしょう。)
ただ、割り込みハンドラはページフォルト・・・(プロセス切り替え)を発生させるような処理を行うことはない、ということです。

ページフォルトは更なる例外を発生させることはないので、これにより、カーネル実行パスは 2 つまでしか積まれません。
I/O デバイスが発行する割り込みはカレントプロセスのデータを参照しない。えっ???ちょっとまて〜これに割り込んで使用されるんだろうが・・・・・喝)
つまり、割り込みが発生するときにどのプロセスを実行しているか前もって知ることは出来ない。

2-1 ハードウェアでの割り込みと例外はどうなっているのか?

CPU が割り込みと例外をどう処理しているのかまったく述べていなかったことに気が付いたので、スルーするわけにもいかず、書いておきます。(気が付くんじゃなかった・・・)
現在、あなたの(私の) PC は、カーネル初期化が完了し、プロテクトモードで動いています。
ある命令を実行した後、 cs と eip のレジスタには次に実行するべき命令の論理アドレスが入っています。
これを実行する前(前の命令の実行中)割り込みか例外が発生していないか調べます。さあ大変、発生していました。

割り込み/例外に対応するベクタを求める。

idtr レジスタが指す IDT から i 番目のエントリを読み取る。

gdtr レジスタから GDT ベースアドレス取得。

GDT 内から IDT エントリのセレクタが指すセグメントディスクリプタを読み取る。これが、割り込みや例外ハンドラのあるセグメントのベースアドレスを指すはず。

適当な割り込み発信元かどうか確認。 cs レジスタの下位 2 ビットの( CPL )現行特権レベルと GDT 内のセグメントディスクリプタの( DPL )ディスクリプタ特権レベルを比較。

CPL の値が DPL の値より小さければ一般保護例外を発生。(割り込みハンドラは、割り込みを発生させたプログラムよりも低い特権レベルでは動作出来ない為。)
ソフトウェアが発生させた例外の場合、セキュリティチェックもある。

CPL と IDT 内のゲートディスクリプタを比較。

DPL の値が CPL より小さければ一般保護例外を発生。これによりユーザアプリケーションによる割り込みゲートやトラップゲートへのアクセスを防ぐ。

特権レベルが変更されているか調べる。( CPL がセグメントディスクリプタの DPL と異なるかどうか?)

異なった場合、制御回路は新しい特権レベル用に用意しているスタックを使用しなければならない。
・・・手順として、
・・・ tr レジスタを読み取り、 current プロセスの TSS セグメントにアクセス。
・・・ ss 、 esp レジスタに新しいスタックセグメントとスタックポインタの適当な値をロード。( TSS にこれらの値はある。)
・・・古い特権レベルに対応する論理アドレスを表す ss と esp の以前の値を新しいスタックに退避。

フォルトが発生した場合、例外を発生させた命令の論理アドレスを cs と eip にロード。再実行が可能になる。

スタックに eflags 、 cs 、 eip レジスタの内容を退避。

例外にハードウェアエラーコードがあれば、これをスタックに退避。

セグメントディスクリプタと IDT 内の i 番目にあるゲートディスクリプタのオフセットフィールドを cs と eip レジスタにそれぞれロード。
これが割り込みや例外ハンドラにある最初の命令の論理アドレスをあらわしているはず。

2-2 この後は?

制御回路が最後の手順を実行すると、割り込みや例外ハンドラの先頭アドレスにジャンプします。
ということは割り込み信号を処理した後に実行される命令は選択されたハンドラ内の最初の命令。ということだと思います。

問題は割り込みや例外を処理した後、対応する命令はどうなっているのか?ということですが、
iret 命令により、割り込まれたプロセスに制御を返さなければなりません。

この命令を調べると、以下を強制的に実行(重要)しています。

スタックに退避されている cs 、 eip 、 eflags レジスタの値をロード、 eip にハードウェアエラーコードが積まれている場合、 iret を実行するよりも前に取り出さないといけない。

ハンドラの CPL が cs の低位 2 ビットの値と等しいか調べる。(割り込まれたプロセスがハンドラと同じ特権レベルで動作していたかどうか?)
等しい場合、 iret は実行を終了。異なれば次の手順に進む。

スタックから ss 、 esp レジスタをロード。古い特権レベル用のスタックに戻ると同意。

ds 、 es 、 fs 、 gs セグメントレジスタを調べる。 CPL の値よりも小さい DPL のセグメントディスクリプタの内容を参照するセレクタがあった場合、そのセグメントレジスタをクリアする。
これで、カーネルルーチンが使用していた以前のセグメントレジスタ( DPL の値が 0 )を、 CPL の値が 3 で動作するユーザモードプログラムが動作することを禁止する。 これらがクリアされない場合、悪意のあるユーザプログラムもカーネル空間にアクセス出来てしまいます。
このクリアを取り払えば・・・やらないで下さい。