web-dev-qa-db-ja.com

Linuxでは割り込みはどのように処理されますか?

Interrupthardware signal assertionはプロセッサピンで発生しました。しかし、Linux OSがそれをどのように処理するかを知りたいのです。
割り込みが発生したときに何が起こるのですか?

35
Sen

以下は、低レベル処理の高レベルのビューです。私は単純な典型的なアーキテクチャについて説明していますが、実際のアーキテクチャは、この詳細レベルでは重要ではない方法で、より複雑になったり、異なったりする可能性があります。

interrupt が発生すると、プロセッサは割り込みがマスクされているかどうかを調べます。マスクされている場合は、マスクが解除されるまで何も起こりません。割り込みのマスクが解除されたときに保留中の割り込みがある場合、プロセッサはそれを選択します。

次に、プロセッサはメモリ内の特定のアドレスに分岐することにより、割り込みを実行します。そのアドレスのコードは 割り込みハンドラ と呼ばれます。プロセッサがそこで分岐すると、割り込みをマスクし(割り込みハンドラが排他的に制御されるため)、一部のレジスタ(通常は他のレジスタ)の内容を保存します。

割り込みハンドラは、通常、データを送受信するために割り込みをトリガーしたペリフェラルと通信することによって、実行する必要があることを実行します。タイマーによって割り込みが発生した場合、ハンドラーはOSスケジューラーをトリガーして、別のスレッドに切り替えることがあります。ハンドラーが実行を終了すると、保存されたレジスターを復元し、割り込みのマスクを解除する特別な割り込みからの復帰命令を実行します。

割り込みハンドラは他の割り込みの実行を妨げているため、すばやく実行する必要があります。 Linuxカーネルでは、割り込み処理は2つの部分に分かれています。

  • 「上半分」は割り込みハンドラです。最小限必要なことを行い、通常はハードウェアと通信し、カーネルメモリのどこかにフラグを設定します。
  • 「下半分」は、プロセスメモリへのデータのコピー、カーネルデータ構造の更新など、その他の必要な処理を実行します。割り込みが有効になっている状態で実行されるため、時間がかかり、システムの他の部分をブロックすることさえあります。

このトピックでいつものように、詳細については Linux Device Drivers を参照してください。 10章 は割り込みに関するものです。

Gillesはすでに 説明 割り込みの一般的なケースです。以下は、特にIntelアーキテクチャ上のLinux 2.6に適用されます(これの一部もIntelの仕様に基づいています)。

割り込みは、プロセッサによって実行される命令のシーケンスを変更するイベントです。
2種類の割り込みがあります。

  • CPUが命令の処理中に生成する同期割り込み(例外)
  • 他のハードウェアデバイスによって発行された非同期割り込み(Interrupt)

例外はプログラミングエラー(feDivide errorPage FaultOverflow)カーネルで処理する必要があります。彼はプログラムにシグナルを送り、エラーからの回復を試みます。

次の2つの例外が分類されます。

  • 異常な状態を検出している間にCPUによって生成されたプロセッサ検出例外; 3つのグループに分けられます:障害は一般に修正できます、トラップは実行を報告します、中止重大なエラーです。
  • プログラマーによって要求されたプログラムされた例外、トラップのように処理されます。

割り込みは、I/Oデバイス(キーボード、ネットワークアダプターなど)、インターバルタイマー、および(マルチプロセッサシステムでは)他のCPUから発行できます。割り込みが発生すると、CPUは現在の命令を停止し、新しく到着した割り込みを実行する必要があります。彼は、割り込みが処理された後に(おそらく)再開するために、古い割り込みプロセス状態を保存する必要があります。

割り込みの処理は重要なタスクです。

  • 割り込みはいつでも発生する可能性があり、カーネルはできるだけ早くそれを邪魔にならないようにします
  • 割り込みは別の割り込みによって割り込まれることができます
  • カーネルにはまったく中断してはならない領域があります

2つの異なる割り込みレベルが定義されています。

  • I/Oデバイスによって発行されたマスク可能な割り込み;マスクまたは非マスクの2つの状態があります。マスクされていない割り込みのみが処理されます。
  • マスクできない割り込み;重大な誤動作(ハードウェア障害など)。常にCPUによって処理されます。

すべてのハードウェアデバイスには、独自の割り込み要求(IRQ)ラインがあります。 IRQには0から始まる番号が付けられています。すべてのIRQラインは、プログラマブル割り込みコントローラー(PIC)に接続されています。 PICはIRQをリッスンし、それらをCPUに割り当てます。特定のIRQラインを無効にすることもできます。
最新のマルチプロセッシングLinuxシステムには、通常、新しいAdvanced PIC(APIC)が含まれており、CPU間でIRQ要求を均等に分散します。

割り込みまたは例外とその処理の間の中間ステップは、割り込み記述子テーブル(IDT)です。このテーブルは、各割り込みまたは例外ベクトル(数値)を指定されたハンドラーに関連付けます(つまり、Divide errorは関数divide_error()によって処理されます)。

カーネルはIDTを介して、発生した割り込みまたは例外の処理方法を正確に把握しています。


では、割り込みが発生するとカーネルは何をするのでしょうか?

  • CPUは、各命令の後に(A)PICからのIRQがあるかどうかをチェックします
  • その場合、IDTに問い合わせて、受信したベクトルを関数にマッピングします。
  • 許可されたソースによって割り込みが発行されたかどうかを確認します
  • 中断されたプロセスのレジスタを保存します
  • 割り込みを処理するために対応する関数を呼び出します
  • 中断されたプロセスの最近保存されたレジスタをロードし、再開を試みます
22
wag

まず、割り込み処理に関与するのは、周辺ハードウェアデバイス、割り込みコントローラー、CPU、オペレーティングシステムカーネル、ドライバーです。周辺機器のハードウェアデバイスは、割り込みの生成を担当します。オペレーティングシステムのカーネルに注意を向けたい場合、割り込み要求ラインをアサートします。これらの信号は、割り込み信号の収集を担当する割り込みコントローラーによって多重化されます。また、割り込み信号がCPUに渡される順序の決定も行います。割り込みコントローラーは、特定の割り込み要求ライン(IRQL)を一時的に無効にして、再度有効にすることができます(IRQLマスキング)。割り込みコントローラは、収集した割り込み要求を順次CPUに渡します。各命令の実行が完了した後、CPUは、割り込みコントローラからの待機中の割り込み要求があるかどうかをチェックします。 CPUが待機中の要求があり、内部CPU制御レジスタに割り込みイネーブルフラグが設定されていることを検出すると、CPUは割り込み処理を開始します。ご覧のように、CPUの割り込みフラグの操作と割り込みコントローラーとの通信により、Linuxカーネルは割り込みの受け入れを制御できます。たとえば、Linuxは特定のデバイスからの割り込みの受け入れを無効にしたり、割り込みの受け入れをまったく無効にしたりできます。

プロセッサが割り込み要求を受信するとどうなりますか?まず、CPUは割り込みフラグをリセットすることにより、自動的に割り込みを無効にします。割り込み処理が完了すると、再度有効になります。同時に、CPUは、中断されたコードの実行を再開できるように、CPUをユーザーモードからカーネルモードに切り替えるために必要な最小限の作業を行います。 CPUは、制御が渡されるコードのアドレスを見つけるために、Linuxカーネルで満たされた特別なCPU制御構造を調べます。このアドレスは、Linuxカーネルの一部である割り込みハンドラーの最初の命令のアドレスです。

割り込み処理の最初のステップとして、カーネルは受け取った割り込みのベクトルを識別して、システムで発生したイベントの種類を識別します。割り込みベクトルは、Linuxがそれを処理するために実行するアクションを定義します。 2番目のステップとして、Linuxは残りのCPUレジスター(CPUによって自動的に保存されなかったもの)を保存し、中断されたプログラムで使用できる可能性があります。これにより、Linuxは割り込みを受けたプログラムに関係なく割り込みを透過的に処理できるため、非常に重要なアクションです。 3番目のステップとして、Linuxは、カーネル環境を設定し、それに必要なCPU状態を設定することにより、カーネルモードへの切り替えを実行します。そして最後に、ベクトル依存の割り込みハンドラが呼び出されます。 (Arch\x86\kernel\entry_32.SのBUILD_INTERRUPT3マクロを見て、x86アーキテクチャ関連の例の追加の詳細を取得できます)周辺機器の場合、これはdo_IRQ()ルーチンです。 (Arch\x86\kernel\irq.cを見てください)

ベクトル依存の割り込みハンドラーは通常、irq_enter()およびirq_exit()の呼び出しによってラップされます。これらの関数のペアで囲まれたコード領域は、他のそのような領域に対してアトミックであり、cli/stiのペアに対してもアトミックです。 Irq_enter()およびirq_exit()は、割り込み処理に関連するいくつかの統計もキャプチャします。最後に、カーネルはvector_irqテーブルを調べて、受信した割り込みのベクトルに割り当てられているirq番号を見つけ、handle_irq()(Arch\x86\kernel\irq_32.cから)を呼び出します。

この時点で、カーネルはirq記述子の一部としてデバイスドライバーによってインストールされたデバイス依存の割り込みハンドラールーチンを探して呼び出すため、Linuxでの割り込み処理の共通部分は終了します。そのようなハンドラーがドライバーによってインストールされなかった場合、カーネルは単に割り込みコントローラーで割り込みを確認し、一般的な割り込みハンドラーを終了します。

割り込み処理の終了後、カーネルは以前に中断されたプログラムの状態を復元し、このプログラムの実行を再開します。

8
ZarathustrA

理論的な側面から、ほとんどすべてが説明されています。しかし、カーネル割り込み処理コードフレームワークに関する説明を探している場合は、次のリンクを参照してください。 カーネル割り込み処理内のコードウォーク

そして、あなたがまだ割り込みと割り込みハンドラーに関する理論を探しているなら、私はこれを読むことをお勧めします: 割り込みと割り込みハンドラーを理解する

3
trukna