Linux カーネルに関する回答。他のほとんどの OS でも動作するはずです。
1) デバイス ドライバーを作成し、IRQ X を登録するとします。システムは、どのデバイスを処理する必要があるかをどこから認識しますか? たとえば、IRQ 番号 10 で request_irq() を使用できますが、マウスやキーボード、またはドライバーに記述したものにハンドラーを使用する必要があることをシステムはどのように認識しますか?
それに対する答えは1つではありません。たとえば、これがカスタム組み込みシステムの場合、ハードウェア設計者はドライバー作成者に「デバイス x を irq y にルーティングします」と伝えます。たとえば、一般的に PCI プロトコルを使用するネットワーク カードの場合など、柔軟性を高めるためです。新しいデバイスが検出されたときに、新しいデバイスに irq 番号を割り当てるためのハードウェア/ファームウェア レベルの調停があります。これは、PCI 構成レジスタの 1 つに書き込まれます。ドライバーは最初にこのデバイス レジスタを読み取り、次にその特定の irq の割り込みハンドラーを登録します。他のプロトコルにも同様のメカニズムがあります。
できることは、カーネル コードでの request_irq の呼び出しと、ドライバーがどのように irq 値を取得したかを調べることです。ドライバーの種類ごとに異なります。
したがって、この質問に対する答えは、システムは知らないということです。ハードウェア設計者またはハードウェア プロトコルは、この情報をドライバー作成者に提供します。次に、ドライバー ライターはその特定の irq のハンドラーを登録し、その irq が表示された場合の対処方法をシステムに指示します。
2) 割り込みベクトルはどのように見えますか? つまり、デバイスに IRQ 10 を使用すると、テーブル内のエラー処理用の標準ハンドラーが上書きされます (最初に使用できるハンドラーは、Silberschatz (オペレーティング システムの概念) によると 32 です)。
良い質問。それには2つの部分があります。
a) request_irq (irq,handler) を実行したとき。システムは実際には、IVT または IDT でエントリ 0 をプログラムしません。ただし、エントリ N + irq. N は、その CPU でサポートされているエラー ハンドラまたは汎用例外の数です。詳細はシステムごとに異なります。
b) 別のドライバーが使用している irq を誤って要求した場合はどうなりますか。エラーが発生し、IDT がハンドラーでプログラムされていません。
注: IDT は割り込み記述子テーブルです。
3) 誰が最初に IRQ を設定しますか? ビオス?OS?
最初にBIOS、次にOS。ただし、BIOS によって設定された IVT を再プログラムしない MS-DOS などの特定の OS があります。Windows や Linux などのより洗練された最新の OS は、特定の BIOS 機能に依存したくないため、IDT を再プログラムします。しかし、BIOS は最初にそれを行う必要があり、それから OS が登場します。
4) IRQ と割り込みベクトルのオフセットの一致を担当するのは誰ですか?
私はあなたが何を意味するのか本当にはっきりしていません。流れはこんな感じ。最初にデバイスに irq 番号が割り当てられ、次にその irq 番号を使用してデバイスのハンドラーを登録します。間違った irq 番号を使用し、デバイスで割り込みを有効にすると、システムがクラッシュします。ハンドラーが間違った irq 番号から登録されているためです。
5) IRQS を共有することが可能です。そんなことがあるものか?メインボードには、デバイスを割り込みコントローラに接続するハードウェア レーンがあります。レーンを同じ割り込みに設定するにはどうすればよいですか? レーン 2 と 3 が IRQ15 を処理することを示すテーブルが必要です。たとえば、このテーブルはどこにあり、どのように呼び出されますか?
これはとても良い質問です。余分なテーブルは、カーネルで解決される方法ではありません。むしろ、共有 irq ごとに、ハンドラーは関数ポインターのリンクされたリストに保持されます。カーネルはすべてのハンドラーをループし、ハンドラーの 1 つが割り込みを自分のものとして要求するまで、それらを次々と呼び出します。
The code looks like this:
driver1:
d1_int_handler:
if (device_interrupted()) <------------- This reads the hardware
{
do_interrupt_handling();
return MY_INTERRUPT;
}else {
return NOT_MY_INTERRUPT;
}
driver2:
Similar to driver 1
kernel:
do_irq(irq n)
{
if (shared_irq(n))
{
irq_chain = get_chain(n);
while(irq_chain)
{
if ((ret = irq_chain->handler()) == MY_INTERRUPT)
break;
irq_chain = irq_chain->next;
}
if (ret != MY_INTERRUPT)
error "None of the drivers accepted the interrupt";
}
}