第 9 章 実行に当たっての問題
11.6 Kernel PlugIn の仕組み
11.6.5 Kernel PlugIn での割り込み処理
セクション [11.6.5.2] の説明のとおり、Kernel PlugIn ドライバの使用を有効にした場合、Kernel PlugIn ドライ バで割り込みを処理します。
Kernel PlugIn の割り込みを有効にした場合、WinDriver がハードウェアの割り込みを受信した際には、
Kernel PlugIn ド ラ イ バ の 高 い IRQL ハ ン ド ラ (KP_IntAtIrql() (レ ガ シ ー 割 り 込 み) ま た は
KP_IntAtIrqlMSI() (MSI / MSI-X)) を呼びます。高い IRQL ハンドラが TRUE を返す場合、高い IRQL ハンドラが処理を終え、TRUE を返した後に、Kernel PlugIn の割り込み遅延ハンドラ (KP_IntAtDpc() (レ ガシー割り込み) または KP_IntAtDpcMSI() (MSI / MSI-X)) を呼びます。DPC 関数の戻り値は、ユー ザーモードの割り込み処理ルーチンを実行する回数です。たとえば、KP_PCI のサンプルでは、Kernel
PlugIn で実行中の割り込みハンドラは割り込みを 5 回カウントし、5 回毎にユーザーモードに通知します。
従って、WD_IntWait() は、ユーザーモードでは受け取った割り込みの 5 回に 1 回しか通知しません。高 い IRQL (KP_IntAtIrql() または KP_IntAtIrqlMSI()) は 5 回の割り込み毎に TRUE を返し、
DPC ハンドラ (KP_IntAtDpc() または KP_IntAtDpcMSI()) を有効にし、DPC 関数は高い IRQL ハン
ドラからの実際の DPC 呼び出しの回数を返します。つまりユーザーモードの割り込み処理は 5 回の割り込 み毎に 1 回しか実行されません。
11.6.5.1 ユーザーモードの割り込み処理 (Kernel PlugIn なし)
Kernel PlugIn 割り込み処理が無効の場合、割り込みを受信する度に WD_IntWait() を返し、WinDriver
がカーネルで割り込み処理を終了すると、ユーザーモードの割り込み処理ルーチンを起動します (主に、
WDC_IntEnable() またはより低レベルの InterruptEnable() または WD_IntEnable() への呼 び出しで渡される割り込み転送コマンドの実行) – 図 11.2 を参照。
図 11.2: Kernel PlugIn なしでの割り込みの処理 11.6.5.2 カーネルでの割り込み処理 (Kernel PlugIn あり)
Kernel PlugIn で割り込みを処理するには、ユーザーモード アプリケーションが Kernel PlugIn ドライバへの
ハンドルをオープンし、そして fUseKP パラメータに TRUE を設定して、WDC_IntEnable() を呼びます。
ドライバ コード
WD_IntWait()
WinDriver カーネル
割り込み 信号 ユーザー モード
カーネル モード
WD_IntWait()
ハードウェア
図 11.3: Kernel PlugIn ありでの割り込み処理
WDC_xxx API を 使 用 し な い 場 合 、 ア プ リ ケ ー シ ョ ン は 、Kernel PlugIn ド ラ イ バ へ の ハ ン ド ル を WD_IntEnable() 関数またはラッパー InterruptEnable() 関数へ渡します (WD_IntEnable() と WD_IntWait() を 呼 び ま す)。Kernel PlugIn 割 り 込 み 処 理 を 有 効 に し ま す (関 数 へ 渡 さ れ る WD_INTERRUPT 構造体の hKernelPlugIn フィールド内に Kernel PlugIn ハンドルを渡します)。
WDC_IntEnable() / InterruptEnable() / WD_IntEnable() を呼び出して Kernel PlugIn で割り 込みを有効にする際、Kernel PlugIn の KP_IntEnable() コールバック関数を有効にします。この関数 で、Kernel PlugIn 割り込み処理へ渡される割り込みコンテキストを設定できます。また同様に、ハードウェア で実際に割り込みを有効にするためにデバイスへの書き込みや、デバイスの割り込みを正確に有効にする ために必要なコードを実装できます。
Kernel PlugIn 割り込みハンドラが有効な場合、有効になった割り込みの種類を基に、関連する高い IRQL
ハンドラ (KP_IntAtIrql() (レガシー割り込み) または KP_IntAtIrqlMSI() (MSI / MSI-X)) が割り 込みのたびに呼び出されます。高い IRQL ハンドラのコードを高い割り込みレベルで実行します。このコー ドの実行中はシステムが停止します (そのため、コンテキスト スイッチや、優先度の低い割り込みが処理され ません)。
高い IRQL で実行中のコードは、次の制約があります。
ページしないメモリに対してのみアクセス可能です。
次の関数だけを呼び出し可能です (または、これらの関数を呼び出したラッパー関数)。
WDC_xxx() のアドレスまたは設定空間 read / write 関数
WDC_MultiTransfer() 、 ま た は 低 レ ベ ル の WD_Transfer() 、 WD_MultiTransfer() または WD_DebugAdd() 関数
ドライバ コード WD_IntEnable()
. .
WinDriver カーネル
KP_IntAtIrql()
{
優先度の 高いコード }
KP_IntAtDpc() {
優先度の 低いコード }
WinDriver Kernel PlugIn
割り込み 信号 ユーザー モード
カーネル モード
ハードウェア
高い割り込み要求レベルから呼び出される OS 固有のカーネル関数 (WDK 関数など)。(これ らの関数を使用すると、その他の OS とのコード互換性が損なわれる場合があるのでご注意く ださい。)
malloc()、free() または上記の関数以外の WDC_xxx または WD_xxx API 関数は呼びま せん。
前述の制限のため、高い IRQL ハンドラ (KP_IntAtIrql() または KP_IntAtIrqlMSI()) のコードは できだけ小さくします (レベル センシティブ割り込みの検知 (消去) など)。割り込み処理で実行するその他の コードを DPC 関数 (KP_IntAtDpc() または KP_IntAtDpcMSI()) で実装します。DPC 関数は、遅延 割り込みレベルで実行され、高い IRQL ハンドラと同じような制限はありません。その DPC 関数と一致する 高い IRQL 関数が戻り値を返した後に (TRUE を返した場合)、DPC 関数を呼びます。
ユ ー ザ ー モ ー ド で 割 り 込 み 処 理 を 行 う こ と も で き ま す 。DPC 関 数 (KP_IntAtDpc() ま た は KP_IntAtDpcMSI()) の戻り値が、カーネルモードでの割り込み処理が終了した後に、ユーザーモードの 割り込み処理ルーチンを呼ぶ回数となります。