割り込み - kentakozuka/yetos GitHub Wiki
mermaid
sequenceDiagram
participant input as Input
participant cpu as CPU
participant ram as RAM
participant os as OS
os->>cpu: Request to allocate IDT
cpu->>ram: Allocate IDT
input->>cpu: Send interrupt event
cpu->>os: Run function
os->>cpu: Return interrupt function
- 事前準備
- イベント発生時に実行する割り込みハンドラを準備
- 割り込みハンドラをIDT(割り込み記述子テーブル)に登録
- イベント発生時
- ハードウェア(場合によってはソフトウェア)がイベントをCPUに通知
- CPUは現在の処理を中断し、イベントの種類に応じて登録された割り込みハンドラに処理を移す
- 割り込みハンドラの処理が終わると、中断していた処理を再開
割り込み処理が終わった時点でCPUに対して、処理の終了を伝える必要がある。
0xfee00000
から fxfee00400
までの1024バイトの範囲にはメインメモリには配置されておらず、CPUのレジスタが置かれている。ここに書き込むことで割り込み処理の終了をCPUに伝える処理が実行される。
void NotifyEndOfInterrupt() {
volatile auto end_of_interrupt = reinterpret_cast<uint32_t *>(0xfee000b0);
*end_of_interrupt = 0;
}
-
volatile
修飾子をつけることでC++の最適化の対象から外す。これをつけないとコンパイラは*end_of_interrupt = 0;
によって書き込んだ値が他の場所で利用されないため、メモリ書き込み命令を省く可能性がある
usb::xhci::Controller *xhc;
__attribute__((interrupt)) void IntHandlerXHCI(InterruptFrame *frame) {
main_queue->Push(Message{Message::kInterruptXHCI});
NotifyEndOfInterrupt();
}
-
__attribute__((interrupt))
で割り込みハンドラだということをコンパイラに伝える
- 割り込みを種類別に 割り込みベクタ(割り込み要因番号)を割り振って管理する
- 固定で番号が振られているものと独自に番号を決めてよいものがある
- x86-64では 0-255のいずれかになる。
- Interrupt Descriptor
- 割り込みについての詳細情報が入っている
リトルエンディアンなので、右から読む
フィールド | 説明 |
---|---|
offset_low, offset_middle, offset_high | 割り込みハンドラのアドレスを設定する。3つ合わせて64ビットアドレスを指定する。 |
segment_selector | 割り込みハンドラを実行する際のコードセグメント(実行可能コードが置いてあるメモリ区画). |
attr | 割り込み記述子の属性を設定する。typeは記述子の種別(14 or 15)。 |
descriptor_privilege | Descriptor Privilege Level(DPL)。割り込みハンドラの実行権限(0-3)。 |
interrupt_stack_table | IST。はみかん本では常に0。 |
present | 記述子の有効フラグ。 |
- IDT: Interrupt Descriptor Table
- 割り込みベクタと割り込みハンドラを対応付けるテーブル
- 割り込み記述子を256個並べた配列
- メインメモリ上に配置する
- 割り込みハンドラをIDTに登録することで、実際に割り込みが発生した際にハンドラが呼び出される
- Message Signaled Interruptの略。
- 特定のメモリアドレス(Message Address)に対して32bitの値(Message Data)をを書き込む
- メモリアドレスと値のフォーマットはCPU側の仕様で規定されている
x86-64の場合は以下
- 割り込みを扱う為には、割り込みハンドラ、割り込み記述子、割り込み発生源の設定が必要
- 割り込みハンドラは
__attribute__((interrupt))
をつけ、処理の最後に End of Interruptレジスタへの値の書き込みをする - 割り込み記述子はメインメモリ上に作成したIDTの1つの要素で、割り込みハンドラのアドレスや各種属性を設定する
- IDTは最大256個の配列。それぞれ0-255の割り込みベクタに対応する
- IDTの先頭アドレス、及び大きさをlidt命令によりCPUに登録する
- xHCIではMSI(MSI-X)方式で割り込みを発生させるため、Message Address 及び Message Dataの設定をする