DMA でのダイレクト I/O の使用
次の図は、I/O マネージャーがダイレクト I/O を使用する DMA 転送操作の IRP_MJ_READ 要求を設定する方法を示しています。
前の図は、ドライバーが IRP の MdlAddress を使用して読み取り要求のデータを転送する方法を示しています。 図のドライバーは、パケット ベースのシステムまたはバスマスター DMA を使用し、DO_DIRECT_IO を持つデバイス オブジェクトのフラグを ORed します。
ユーザー空間の仮想アドレスのある範囲は、現在のスレッドのバッファーを表し、そのバッファーの内容は実際には物理的に離れているページ数に格納される場合があります (前の図の濃い網かけ)。 I/O マネージャーは、このバッファーを記述する MDL を作成します。 MDL は、メモリ マネージャーによって定義される不透明なデータ構造であり、特定の仮想アドレス範囲を 1 つ以上のページ ベースの物理アドレス範囲にマップします。 詳細については、「MDL の使用」を参照してください。
I/O マネージャーは、現在のスレッドの読み取り要求を処理します。この要求に対して、スレッドはバッファーを表すユーザー空間の仮想アドレスの範囲を渡します。
I/O マネージャーまたはファイル システム ドライバー (FSD) は、ユーザーが指定したアクセシビリティ バッファーをチェックし、以前に作成した MDL で MmProbeAndLockPages を呼び出します。 MmProbeAndLockPages は、MDL 内の対応する物理アドレス範囲にも入力します。
前の図に示すように、仮想範囲の MDL には、複数の対応するページ ベースの物理アドレス エントリを含めることができます。また、バッファーの仮想範囲は、MDL によって記述された最初のページと最後のページの先頭からバイト オフセットで開始および終了する場合があります。
I/O マネージャーは、転送操作を要求する IRP の MDL (MdlAddress) へのポインターを提供します。 ドライバーが IRP を完了した後、I/O マネージャーまたはファイル システムが MmUnlockPages を呼び出すまで、MDL で説明されている物理ページはロックダウンされたままで、バッファーに割り当てられます。 ただし、このような MDL 内の仮想アドレスは、デバイス ドライバーまたはデバイス ドライバーの上に階層化される可能性がある中間ドライバーに IRP が送信される前であっても、非表示 (および無効) になる可能性があります。
ドライバーがパケット ベースのシステムまたはバス マスター DMA を使用する場合、その AdapterControl ルーチンは、IRP の MdlAddress ポインターを使用して MmGetMdlVirtualAddress を呼び出して、MDL のページ ベースのエントリのベース仮想アドレスを取得します。
次に、AdapterControl ルーチンは、MmGetMdlVirtualAddress によって返されるベース アドレスを使用して MapTransfer を呼び出して、デバイスから物理メモリに直接データを読み取ります。 (詳細については、「アダプター オブジェクトと DMA」を参照してください。)
ドライバーは常にバッファーの長さをチェックする必要があります。 I/O マネージャーは、長さ 0 のバッファーの MDL を作成しないことに注意してください。