共通バッファー システム DMA の使用
システム DMA コントローラーの自動初期化モードを使用するドライバーは、DMA 転送を実行できるバッファーにメモリを割り当てる必要があります。ドライバーは、通常、IRP_MN_START_DEVICE 要求を処理する DispatchPnP ルーチンから、このバッファーを取得する AllocateCommonBuffer を呼び出します。 次の図は、ドライバーがバッファーを割り当て、その仮想アドレス範囲をシステムの物理メモリにマップする方法を示しています。
前の図に示すように、ドライバーはシステム DMA にバッファーを割り当てるために次の手順を実行します。
ドライバーは AllocateCommonBuffer を呼び出し、IoGetDmaAdapter によって返されたアダプター オブジェクトへのポインターと、バッファーに対して要求された長さ (バイト単位) を渡します。 メモリを経済的に使用するには、バッファーに入力する Length 値を PAGE_SIZE 以下にするか、PAGE_SIZE の整数倍数にする必要があります。
AllocateCommonBuffer が NULL ポインターを返す場合、ドライバーは既に要求したすべてのシステム リソースを解放し、IRP_MN_START_DEVICE 要求に応答して STATUS_INSUFFICIENT_RESOURCES を返す必要があります。
それ以外の場合、AllocateCommonBuffer は、システム仮想アドレス空間に要求されたメモリ量を割り当て、そのバッファーへの 2 種類のポインターを返します。
バッファーの LogicalAddress (前の図の BufferLogicalAddress)、ドライバーは記憶域を提供する必要がありますが、それ以降は無視する必要があります。
バッファーの仮想アドレス (前の図の BufferVirtualAddress)、ドライバーも DMA 操作のバッファーを記述する MDL を構築できるように格納する必要があります。
ドライバーは、デバイス拡張機能またはその他のドライバーによって割り当てられた常駐メモリにこれらのポインターを格納する必要があります。
ドライバーは IoAllocateMdl を呼び出して、バッファーに MDL を割り当てます。 ドライバーは、AllocateCommonBuffer によって返されるバッファーの VirtualAddress と、MDL を割り当てるためのバッファーの Length を渡します。
ドライバーは、IoAllocateMdl によって返されるポインターを使用して MmBuildMdlForNonPagedPool を呼び出して、常駐バッファーの仮想アドレス範囲をシステムの物理メモリにマップします。
共通バッファーを割り当てて仮想アドレス範囲をマッピングすると、下位デバイスのドライバーは、DMA 転送を要求する IRP の処理を開始できます。 これを行うには、ドライバーは、サポート ルーチンの次の一般的なシーケンスを呼び出します。
ドライバー ライターの判断により、RtlMoveMemory は、ロックダウンされたユーザー バッファーから、デバイスへの転送のためにドライバーによって割り当てられた共通バッファーにデータをコピーします。
ドライバーが DMA 用にデバイスをプログラミングする準備が整い、システム DMA コントローラーが必要な場合は AllocateAdapterChannel
MapTransfer は、ドライバーによって割り当てられた共通バッファーを記述する MDL を使用して、転送操作用のシステム DMA コントローラーを設定
ドライバーは MapTransfer を 1 回だけ呼び出し、共通バッファーを使用するようにシステム DMA コントローラーを設定することに注意してください。 転送中、ドライバーは ReadDmaCounter を呼び出して転送するバイト数を決定し、必要に応じて RtlMoveMemory を呼び出して、ユーザー バッファーとの間でより多くのデータをコピーできます。
ドライバーが下位デバイスとの間で DMA 転送を完了した場合は FlushAdapterBuffers
要求されたデータがすべて転送され次第、またはデバイスの I/O エラーが原因でドライバーが IRP に失敗する必要がある場合は、FreeAdapterChannel
IoGetDmaAdapter によって返されるアダプター オブジェクト ポインターは、RtlMoveMemory を除くこれらの各サポート ルーチンに必要なパラメーターです。
個々のドライバーは、各ドライバーがデバイスにサービスを提供するために実装される方法に応じて、さまざまなポイントでこの一連のサポート ルーチンを呼び出します。 たとえば、あるドライバーの StartIo ルーチンが AllocateAdapterChannel への呼び出しを行い、別のドライバーがドライバーによって作成されたインターロック キューから IRP を削除するルーチンからこの呼び出しを行う場合があります。また別のドライバーが、下位 DMA デバイスがデータを転送する準備ができていることを示す際に、この呼び出しを行う場合があります。