割り込みコントローラの仕組み(APIC・GIC・MSI-X)
割り込みがどのコアへどの優先度で届くかを構造から理解できます。x86 の LAPIC/IO-APIC/x2APIC、ARM GIC、MSI-X を整理して押さえます。
- 1.割り込みコントローラはデバイスの信号を受け、宛先コアと優先度を決めて配送する。x86 は LAPIC+IO-APIC、ARM は GIC(Distributor+Redistributor+CPU interface)が担う。
- 2.MSI/MSI-X は専用の割り込み線を使わず、PCIe デバイスがメモリ書き込みとして割り込みを送る方式。配線不要で多数のベクタを持て、ベクタごとに宛先コアを分けられる。
- 3.優先度は LAPIC では TPR/PPR、GIC では Priority Mask と Running Priority で表現され、低優先度の割り込みは高優先度の処理中はマスクされて待たされる。
割り込みコントローラが解く問題
CPU の割り込み入力ピンは事実上ひとつです。一方、デバイスは何十個もあり、マルチコア機ではどのコアに割り込みを届けるかも選びたい。この「多数のデバイス → 少数のコア」をさばく仲介役が割り込みコントローラです。役割は三つに集約できます。
1. 集約(multiplex) 多数のデバイス信号をまとめて受ける
2. ルーティング どのコア(CPU)に届けるかを決める
3. 優先度・マスク 同時発生時にどれを先に通すか、何を待たせるかを決める
デバイスが信号を出してから ISR が走るまでの全体像は /os/interrupt-io/ で扱いました。本稿はその「どう届くか」を担うハードウェアの内部に踏み込みます。
x86:LAPIC と IO-APIC の二層構造
x86 の APIC(Advanced Programmable Interrupt Controller)は、役割の異なる二種類の部品に分かれています。これを混同すると配送経路が理解できません。
| 部品 | 個数 | 役割 |
|---|---|---|
| Local APIC(LAPIC) | コアごとに1つ | そのコア専用。割り込みの受領・優先度判定・タイマ・IPI送出 |
| IO-APIC | チップセット側に数個 | 外部デバイスの割り込み線を受け、宛先LAPICへルーティング |
外部デバイスの割り込みは、まず IO-APIC のピンに入ります。IO-APIC は内部にリダイレクションテーブルを持ち、ピンごとに「どのベクタ番号で」「どの LAPIC(どのコア)へ」「どのモード(固定/最低優先度)で」送るかを記録しています。設定に従って、IO-APIC は割り込みメッセージを APIC バス経由で目的の LAPIC へ送ります。
LAPIC はコアに張り付いた受領窓口です。届いた割り込みを内部のビットマップ(IRR:Interrupt Request Register)に積み、優先度判定を経て、最終的にコアの命令ストリームを中断させて ISR へ飛ばします。タイマや、別コアへ割り込みを撃ち込む IPI(Inter-Processor Interrupt) も LAPIC が出します。スケジューラのリスケジュール要求や TLB シュートダウンはこの IPI で運ばれます。
旧来の APIC は MMIO(メモリマップ I/O)でレジスタを叩き、APIC ID も 8 ビットでコア数 256 が上限でした。x2APIC モードでは LAPIC レジスタを MSR(モデル固有レジスタ)でアクセスするよう変え、APIC ID を 32 ビットに拡張します。これにより数千コア規模が扱え、IPI 送出も MMIO のシリアライズを介さず高速化します。中身のロジックは APIC と同じで、アクセス手段と ID 幅が変わったものと捉えると整理しやすいです。
ARM:GIC の三部構成
ARM の GIC(Generic Interrupt Controller、GICv3 以降)は、x86 とは部品の切り方が違います。三つのブロックの分業を押さえるのが要点です。
- Distributor(GICD):システムに一つ。全割り込みの有効化・優先度設定と、SPI(共有周辺割り込み)をどの CPU へ送るかのルーティングを統括する。
- Redistributor(GICR):コアごとに一つ。そのコア専用の PPI(プライベート周辺割り込み)と SGI(ソフト生成割り込み、x86 の IPI 相当)を管理する。
- CPU interface(システムレジスタ):GICv3 では
ICC_*系のシステムレジスタとしてコア内に統合され、割り込みの確認(acknowledge)と完了(EOI)を行う。
割り込みは種類で番号帯が分かれます。SGI はコア間通知、PPI はそのコア固有のタイマ等、SPI は共有デバイス、そして GICv3 が加えた LPI(Locality-specific Peripheral Interrupt) は MSI を受けるための番号帯です。LPI のルーティングには ITS(Interrupt Translation Service) という専用ブロックが介在し、デバイス ID とイベント ID を引数に、メモリ上のテーブルを引いて宛先コアと割り込み番号を決めます。MSI のテーブル変換をハードウェアで行うのが ITS だと捉えてください。
x86 と GIC は名前が違うだけで役割は対応します。IPI ≈ SGI、コア専用窓口の LAPIC ≈ Redistributor+CPU interface、外部割り込みの集約 IO-APIC ≈ Distributor、MSI 変換テーブル ≈ ITS。この対応を一度作ると、両アーキテクチャを別物として覚え直す必要がなくなります。
優先度とマスク:何を待たせるか
割り込みが同時に来たとき、どれを先に通し、どれを待たせるかを決めるのが優先度機構です。原理は「現在処理中の優先度より低いものはマスクして保留する」という単純なものです。
x86 LAPIC では二つのレジスタが鍵です。TPR(Task Priority Register) はソフトウェアが設定する「今これより低い割り込みは受けない」という閾値、PPR(Processor Priority Register) は TPR と「現在処理中の割り込みの優先度」の高い方として実効的に決まる値です。届いた割り込みのベクタ優先度が PPR 以下なら、IRR に積まれたまま保留され、PPR が下がる(高優先度の処理が終わる)まで配送されません。
割り込み到着
→ ベクタ優先度 > PPR ?
yes → コアへ配送、ISR実行(この間PPRは上がる)
no → IRR に保留(後でPPRが下がったら再評価)
ISR が EOI を書く → 当該優先度が下がる → 保留分を再評価
ここで EOI(End Of Interrupt) が重要です。ISR の末尾で LAPIC に EOI を書くと、その割り込みの「処理中」状態が解除され、優先度が下がって保留中の低優先度割り込みが解放されます。EOI を忘れると同レベル以下の割り込みが永久にマスクされ、システムが固まります。
GIC も思想は同じです。ICC_PMR(Priority Mask Register) が閾値、内部の Running Priority が処理中優先度に相当し、ICC_IAR(acknowledge)で受領、ICC_EOIR(EOI)で完了を通知します。なお優先度の数値規約は両者で逆向きな点に注意が必要です。GIC は数値が小さいほど高優先度(0 が最高)。一方 x86 APIC はベクタ番号が大きいほど高優先度で、優先度クラスはベクタ番号の上位 4 ビット(ベクタ ÷ 16)で決まります。直感とずれやすく、試験でも実務でも引っかかりやすい箇所です。
ここでマスクされるのは「より低い優先度の割り込み」だけです。高優先度割り込みは処理中の低優先度 ISR を**ネスト(割り込みの入れ子)**で横取りできます。ただし ISR 内で割り込みを全マスクしている区間(ハードIRQ文脈、/os/interrupt-top-bottom-half/ の上半分)では入れ子も止まるため、この区間を短く保つことが応答性に直結します。
MSI/MSI-X:配線をやめてメモリ書き込みで割り込む
従来の割り込みは物理的な信号線(ピン)を IO-APIC まで配線していました。これには無視できない弱点があります。ピン数が有限なので多数のデバイスで共有 IRQ になり、どのデバイスが割り込んだか判別する手間が増える。さらにデバイスが DMA でデータを書いた後に割り込み線を上げても、信号がデータより先にコアへ届く順序の逆転(write posting の追い越し)が起こりうる。
これを解決するのが MSI(Message Signaled Interrupt) です。発想は逆転していて、割り込みを「線の電位」ではなく「特定のアドレスへのメモリ書き込み」として送ります。
[従来] デバイス --(専用の割り込み線)--> IO-APIC --> LAPIC
[MSI ] デバイス --(指定アドレスへ data 値をメモリ書き込み)--> 割り込みとして解釈
PCIe デバイスは、設定時に OS から教わった宛先アドレス(どの LAPIC か=どのコアか、をエンコードしたアドレス)にデータ値(ベクタ番号や配送モードをエンコード)を書き込みます。この書き込みがそのまま割り込みになります。DMA 書き込みと同じ経路・同じ順序規則を通るため、データより先に割り込みが着く逆転が原理的に起きません。
MSI-X は MSI を拡張し、デバイスごとに最大 2048 個のベクタを持てるようにしたものです。さらに各ベクタが独立した宛先アドレスとデータを持つ点が決定的で、ベクタごとに別のコアへ割り込みを振り分けられます。
| 観点 | レガシーIRQ(ピン) | MSI | MSI-X |
|---|---|---|---|
| 送出手段 | 専用の割り込み線 | メモリ書き込み | メモリ書き込み |
| ベクタ数 | 共有で実質少数 | 最大32(連続割当) | 最大2048(個別割当) |
| 宛先コア | IO-APICの設定に依存 | 全ベクタで共通 | ベクタごとに個別指定可 |
| IRQ共有 | 起きやすい | 起きない | 起きない |
| 順序逆転 | 起こりうる | 起きにくい | 起きにくい |
MSI-X の「ベクタごとに宛先コアを分けられる」性質は、現代の高速 NIC や NVMe で本質的です。受信キューや I/O キューをコアごとに一本ずつ用意し、各キューの完了割り込みを担当コアの LAPIC(または GIC Redistributor)に直送すれば、コア間でキャッシュ行を奪い合わずに済みます。この局所性の効きは /os/numa-memory-locality/ の議論とそのまま重なります。
「LAPIC と IO-APIC の違い」は定番です。LAPIC はコアごと(受領・優先度・タイマ・IPI)、IO-APIC は外部割り込みのルーティング、と即答できるように。MSI が解決する問題は「IRQ 共有の解消」と「割り込み/データの順序逆転の防止」の二点。MSI-X が MSI と決定的に違うのは「ベクタごとに宛先を分けられる」点です。EOI を書かないと低優先度割り込みが永久にマスクされる、も押さえどころ。
まとめ
- 割り込みコントローラは「多数のデバイス → 少数のコア」を、集約・ルーティング・優先度判定で仲介する。
- x86:LAPIC(コアごとの受領窓口・IPI・タイマ)+ IO-APIC(外部割り込みのルーティング)。x2APIC は MSR アクセスと 32 ビット ID 化で大規模機に対応。
- ARM GIC:Distributor(統括)+ Redistributor(コア専用)+ CPU interface(受領・EOI)、MSI 変換は ITS が担う。役割は x86 と一対一で対応する。
- 優先度:閾値(TPR/PMR)より低い割り込みはマスクされ保留、EOI で解放される。数値規約は逆向きで、GIC は小さいほど高優先度、x86 APIC はベクタ番号が大きいほど高優先度。
- MSI/MSI-X:割り込みをメモリ書き込みとして送る方式。配線不要で多数ベクタを持て、MSI-X はベクタごとに宛先コアを分けられ局所性を最大化する。
OS Article
割り込みコントローラの仕組み(APIC・GIC・MSI-X)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
割り込み
比較で見る軸
難易度: advanced / カテゴリ: OS / タグ数: 6
導入後に効く点
MSI/MSI-X は専用の割り込み線を使わず、PCIe デバイスがメモリ書き込みとして割り込みを送る方式。配線不要で多数のベクタを持て、ベクタごとに宛先コアを分けられる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- OS
- タグ数
- 6
判断チェックリスト
- 自社の用途が「割り込み / APIC」に近いか確認する。
- 強みである「割り込みコントローラはデバイスの信号を受け、宛先コアと優先度を決めて配送する。x86 は LAPIC+IO-APIC、ARM は GIC(Distributor+Redistributor+CPU interface)が担う。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。