デバイス拡張
ほとんどの中間および最下位ドライバーにおいて、デバイス拡張は、デバイス オブジェクトに関連付けられている最も重要なデータ構造です。 その内部構造はドライバーによって定義され、通常は次の用途に使用されます。
デバイスの状態情報の維持。
ドライバーが使用するカーネル定義オブジェクトやシステムリソース (スピンロックなど) のストレージの提供。
ドライバーが I/O 操作を実行するためにシステム空間に常駐させる必要があるデータの保持。
ほとんどのバス ドライバー、ファンクション ドライバー、およびフィルター ドライバー (最下位および中間ドライバー) は任意のスレッド コンテキスト (すべての現在のスレッド) で実行されるため、デバイス拡張は、各ドライバーがデバイスの状態と、ドライバーが必要とする他のすべてのデバイス固有のデータを維持する主要な場所です。 たとえば、CustomTimerDpc ルーチンまたは CustomDpc ルーチンを実装するドライバーは、通常、必要なカーネル定義タイマーや DPC オブジェクトのストレージをデバイス拡張で提供します。
ISR を持つすべてのドライバーは、カーネル定義の割り込みオブジェクトのセットへのポインターを格納するストレージを提供する必要があります。ほとんどのデバイス ドライバーは、このポインターをデバイス拡張に格納します。 各ドライバーは、デバイス オブジェクトの作成時に、デバイス拡張のサイズを決定します。各ドライバーはまた、デバイス拡張の内容と構造を独自に定義します。
I/O マネージャーの IoCreateDevice ルーチンおよび IoCreateDeviceSecure ルーチンは、非ページ メモリ プールからデバイス オブジェクトと拡張のメモリを割り当てます。
IRP を受け取るすべての標準ドライバー ルーチンはまた、要求された I/O 操作のターゲット デバイスを表すデバイス オブジェクトへのポインターも受け取ります。 これらのドライバー ルーチンは、このポインターによって対応するデバイス拡張にアクセスできます。 通常、DeviceObject ポインターは、最下位ドライバーの ISR への入力パラメーターを兼ねています。
次の図は、最下位ドライバーのデバイス オブジェクトに割り当てられたデバイス拡張に対して、ドライバーが一般に定義するデータのセットを示しています。 上位ドライバーは、IoConnectInterrupt によって返され、KeSynchronizeExecution および IoDisconnectInterrupt に渡される割り込みオブジェクト ポインターのストレージを提供しません。 ただし、上位ドライバーに CustomTimerDpc ルーチンが設定されている場合、この上位ドライバーによって次の図に示すタイマーおよび DPC オブジェクトのストレージが提供されます。 上位ドライバーは、エグゼクティブ スピン ロックとインターロックされた作業キューのストレージを提供することもあります。
最下位デバイス ドライバーは、割り込みオブジェクト ポインターのストレージを提供するだけでなく、ISR が異なるベクトル上の複数のデバイスの割り込みを処理する場合、または複数の ISR がある場合も、割り込みスピン ロックのストレージを提供する必要があります。 ISR の登録の詳細については、「ISR の登録」を参照してください。
通常、ドライバーはデバイス オブジェクトへのポインターをデバイス拡張に格納します (図を参照)。 ドライバーは、デバイスのリソース一覧のコピーを拡張内に保持することもできます。
上位ドライバーは、通常、次の下位ドライバーのデバイス オブジェクトへのポインターをデバイス拡張に格納します。 上位ドライバーは、IRP で次の下位ドライバーの I/O スタック位置を設定した後、次の下位ドライバーのデバイス オブジェクトへのポインターを IoCallDriver に渡す必要があります。これについては、「IRP の処理」で説明します。
また、下位ドライバーに IRP を割り当てる上位ドライバーでは、新しい IRP が必要なスタック位置の数を指定する必要があることにも注意してください。 特に、上位ドライバーが IoMakeAssociatedIrp、IoAllocateIrp、または IoInitializeIrp を呼び出す場合、これらのサポート ルーチンの引数として正しい StackSize を供給するために、次の下位ドライバーのターゲット デバイス オブジェクトにアクセスしてその StackSize 値を読み取る必要があります。
上位ドライバーは、IoAttachDeviceToDeviceStack によって返されるポインターを介して、次のレベルの下位ドライバーのデバイス オブジェクトからデータを読み取ることができますが、このようなドライバーは、次の実装ガイドラインに従う必要があります。
下位ドライバーのデバイス オブジェクトに対して、データの書き込みを試みないでください。
ただし、このガイドラインには 1 つだけ例外があります。下位のリムーバブル メディア ドライバーのデバイス オブジェクトのフラグで DO_VERIFY_VOLUME を設定およびクリアするファイル システムにはこのルールは適用されません。
下位ドライバーのデバイス拡張へのアクセスを試みないでください。理由は以下のとおりです。
2 つのドライバー間で 1 つのデバイス拡張へのアクセスを安全に同期する方法はありません。
このようなバックドア通信スキームを実装しているドライバーのペアは、個別にアップグレードできません。既存のドライバー ソースを変更せずに中間ドライバーを挿入することはできず、再コンパイルして、1 つの Windows プラットフォームから次のプラットフォームに簡単に移動することもできません。
上位ドライバーは、異なる Windows プラットフォームまたはバージョン間で、下位ドライバーとの相互運用性を維持するために、指定された IRP を再利用するか、新しい IRP を作成する必要があります。また、IoCallDriver を使用して下位レベルのドライバーに要求を伝達する必要があります。