割り込みについて


1CPU と複数の入出力装置があるシステムにおいて OS がローレベルで割り込みをどのように処理しているかの概要について整理メモ。

まず、各種デバイスのクラスは割り込みベクトル(interrupt vector)と呼ばれるメモリ領域(下位アドレスのことが多い)に配置される。
このベクトルには割り込みハンドラを引き当てるためのアドレスが格納されている。

ここでユーザプログラムが走っている時に、入出力装置からの割り込みが入ったと仮定する。
まず現在のプログラムカウンタや PSW などが CPU によってカレントスタックに積まれる。
その後、CPU はプログラムカウンタを割り込みベクトルで引き当てたアドレスに変更する。

ここまではハードウェアによってドライブされる。
以後は割り込みハンドラに入る。

全てのハンドラは、スタックにつまれた情報と割り込み前のプロセスのレジスタ内容を保存することから始まる。
保存先は通常はプロセステーブル内のエントリとなる。
その後、スタックポインタをハンドラが用いる一時スタックに変更する。

このようなレジスタ内容の保存やスタックポインタの設定処理は C のような高級言語ではかけないので、アセンブリで記述する。
割り込み原因に限らず、このルーチンは絶対に共通するので、全部の割り込みで同じコードになる。

割り込みプロセス処理終了時には C で記述された手続きを呼び出して、その割り込み処理に関する残りの処理を実施する。
この時に割り込み前のプロセスを実行可能状態(ready)にさせ、次に実行するプロセスを決めるためにスケジューラが呼ばれることが多い。
その後は再びアセンブリにもどって、次に実行するプロセスのレジスタ内容・メモリマッピングを復元してそれを実行する。

実際の処理はシステムによっていくらか異なるが、典型的な例を次に示す。

  1. CPU がスタックポインタや PSW などをスタック領域につむ
  2. ハードウェアは新たなプログラムカウンタを割り込みベクトルからロードする。
  3. アセンブリで書かれた手続きがレジスタ内容を保存する
  4. 同様にアセンブリが新たなスタックを設定する(スタックポインタ変更)
  5. C 言語で書かれた割り込みサービス手続きが実行される
  6. スケジューラが次に実行するプロセスを決定する
  7. C で記述されたサービス手続きからアセンブリに戻る
  8. アセンブリ手続きが running となったプロセスを起動する