割り込み処理をとりあえずまとめ

amazon:詳解Linuxカーネルにおいて、do_IRQ() な引数でポインタが指定されてるんですが、そのポインタが指すデータ型 struct pt_regs についての説明がある。


・1番目から9番目のメンバは SAVE_ALL マクロが積んだレジスタに対応します。
・10番目の orig_eax メンバは、エンコードされた IRQ 番号です。
・11番目から15番目のメンバは制御回路が自動的に積んだレジスタです。
amazon:詳解Linuxカーネルより引用

との事にて、以下に構造体の定義を。

struct pt_regs {
    long ebx;
    long ecx;
    long edx;
    long esi;
    long edi;
    long ebp;
    long eax;
    int  xds;
    int  xes;
    long orig_eax;
    long eip;
    int  xcs;
    long eflags;
    long esp;
    int  xss;
};

スタックなんで下にあるモノが先に push されたモノ、とゆー事で割り込みが発生した時点から順に処理されている事を中心に以下にまとめを。
とりあえず、entry.S なナニを中心にまとめておく事にする。又、現時点では do_IRQ を call するものを例としておく。ざっくりとした処理としては以下。

    pushl $vector-256
    SAVE_ALL
    movl %esp,%eax
    call do_IRQ
    jmp ret_from_intr

ただし、この一連の手続きが呼出される前にプロセッサ側での前処理がある、との記述がマニュアルにもあるので、そこから見ていく必要がある。IA-32 インテル®アーキテクチャ ソフトウェア・デベロッパーズ・マニュアル 上巻 6.4.1.割り込み/例外プロシージャのコール操作とリターン操作 の項にその記述はある。
ざっくりとした処理としては

  1. SS、ESP、EFLAGS、CS、EIP を順にスタックに push
  2. SS、ESP、CS、EIP 等を割り込み処理用に設定
  3. (割り込みゲートを介した呼出しならば) IF をクリア

の後に上記のコードが実行されている形になる、との事。pt_regs のフィールド並び順とも整合しているのが分かる。

次に IRQ 番号 - 256 を push して、SAVE_ALL マクロで各種レジスタの退避を行なった後にスタックポインタを引数として do_IRQ の実行に移っている。ので、do_IRQ 関数の実行が開始された時は割り込みはマスクされた状態である、と言っていいのかな。とりあえず現時点ではそーゆー事にしときます。

で、先日投入したエントリ do_IRQ 呼び出し以降の排他処理 によると割り込みは disable な状態で do_IRQ から戻ってくるハズ。ret_from_intr 以降はきちんと読めていないんですが、ざっくりした情報を以下に。

  • CONFIG_PREEMPT マクロ (カーネルオプション??) が define されている場合には resume_kernel にジャンプする場合もあるようだが、細かい処理を除くと最終的には restore_all にジャンプしている。
  • ただし、ケースによっては preempt_schedule_irq を call した後に need_resched にジャンプしている。関数やラベルの名前的に、割り込み元に戻らないカンジもするが、とりあえずスルー。
  • restore_all では RESTORE_REGS により退避した汎用レジスタを pop して戻し、IRQ 番号 - 256 が格納された部分もスルー (%esp に 4 加えている) した後に iret している。

iret の後は再びマニュアル上巻 6.4.1. 方面な記述。

  1. EIP、CS を順にスタックから pop してレジスタに戻す
  2. EFLAGS レジスタを pop してレジスタに戻す
  3. ESP、SS を順にスタックから pop してレジスタに戻す
  4. 割込まれた手続きに戻る準備完了

で、割込み元の処理を再開、という流れになっている模様。以降は同期と排他をもう少し整理できれば整理して、保留にしようと思ってた APIC について再読後、ソースを追いかけ回す予定ッス。