UMDF 1.x ドライバーでのデータ バッファーへのアクセス

警告

UMDF 2 は UMDF の最新バージョンであり、UMDF 1 に取って代わるものです。 すべての新しい UMDF ドライバーは、UMDF 2 を使用して記述する必要があります。 UMDF 1 には新機能が追加されておらず、Windows 10 の新しいバージョンでは UMDF 1 のサポートが制限されています。 ユニバーサル Windows ドライバーでは、UMDF 2 を使用する必要があります。

詳しくは、UMDFの概要をご覧ください。

UMDF 2 のデータ バッファーへのアクセスの詳細については、「WDF ドライバーでのデータ バッファーへのアクセス」を参照してください。

ドライバーが読み取り、書き込み、またはデバイス I/O 制御要求を受信すると、要求オブジェクトには、入力バッファーまたは出力バッファー、またはその両方が含まれます。 (いくつかのデバイス I/O 制御要求では、2 つの入力、2 つの出力、または 2 つの入出力バッファーが提供されます)。

入力バッファーには、ドライバーに必要な情報が含まれています。 書き込み要求の場合、通常この情報は、関数ドライバーがデバイスに送信する必要があるデータです。 デバイス I/O 制御要求の場合、入力バッファーには、ドライバーが実行する必要がある操作の種類を示す情報が含まれている場合があります。

出力バッファーは、ドライバーから情報を受け取ります。 読み取り要求の場合、通常この情報は、関数ドライバーがデバイスから受信するデータです。 デバイス I/O 制御要求の場合、出力バッファーは、要求の I/O 制御コードが指定した状態またはその他の情報を受け取る場合があります。

ドライバーが要求のデータ バッファーにアクセスするために使用する手法は、ドライバーがデバイスのデータ バッファーにアクセスする方法によって異なります。 UMDF では、次のバッファー アクセス方法がサポートされています。

3 つ目のアクセス方法 (バッファー I/O でもダイレクト I/O でもないと呼ばれます) は、UMDF ベースのドライバーでは使用できませんが、UMDF では、一部の I/O 要求を「どちらでもない」方法から UMDF バージョンがサポートする方法に変換できます。

ほとんどの場合、UMDF ベースのドライバーは、UMDF とドライバーがバッファー I/O またはダイレクト I/O のどちらを使用していても、同じ UMDF オブジェクト メソッドを呼び出してデータ バッファーにアクセスします。 多くの場合、ダイレクト I/O はバッファー I/O よりも優れたパフォーマンスを提供します。

このトピックの次のセクションでは以下を説明します。

優先バッファー アクセス メソッドの指定

UMDF バージョン 1.9 以降では、バッファー I/O アクセス メソッドとダイレクト I/O アクセス メソッドの両方がサポートされています。 ドライバーは、IWDFDeviceInitialize2::SetIoTypePreference を呼び出してデバイス オブジェクトを作成する前に、 IWDFDeviceInitialize2::SetIoTypePreference を呼び出すことによって、デバイスのすべての読み取り、書き込み、およびデバイス I/O 制御要求に使用するアクセス メソッドを指定できます。 たとえばドライバーは、いずれかのデバイスの読み取りおよび書き込み要求のバッファー I/O メソッドのみの優先を指定する場合、UMDF ドライバー ホスト プロセスは、そのデバイスのドライバーに読み取りおよび書き込み要求を配信するときに、バッファー I/O メソッドを使用します。 ドライバーがダイレクト I/O の優先を指定する場合、UMDF はダイレクト I/O を使用できます (ただし、使用しない場合があります)。 UMDF が直接 I/O を使用する場合の詳細については、「UMDF が I/O 要求のバッファー アクセス方法を選択する方法」を参照してください。

ドライバーがサポートするデバイスごとに、ドライバーはデバイスの、バッファー I/O、ダイレクト I/O、またはバッファーまたはダイレクト I/O のいずれかの優先設定を指定できます。 ドライバーは、読み取り要求と書き込み要求に対して 1 つのアクセス メソッドを指定し、デバイス I/O 制御要求に対して別のアクセス メソッド指定できます。 ドライバーがアクセス メソッドの優先を指定しない場合、UMDF はバッファー メソッドを使用します。

デバイス I/O 制御要求の場合、I/O 制御コード (IOCTL) はバッファー アクセス メソッドを指定します。 (IOCTL でアクセス方法を指定する方法の詳細については、「I/O 制御コードの定義」を参照してください。) ただし、UMDF が使用するアクセス メソッドが、IOCTL で指定されているアクセス メソッドと一致しない場合があります。

バッファー取得モードの指定

UMDF バージョン 1.9 より前のバージョンでは、UMDF は I/O 要求を受け取るとすぐに (UMDF ドライバー ホスト プロセスにバッファーをコピーすることによって) I/O 要求のバッファーを常にドライバーで使用できるようにします。 このバッファー取得モードは、即時取得と呼ばれます。 エラーが発生した場合、UMDF はエラー状態の値を使用して I/O 要求を完了し、ドライバーに I/O 要求を配信しません。

UMDF バージョン 1.9 以降では、即時取得モードと遅延取得モードの両方がサポートされています。 遅延取得モードでは、ドライバーがバッファーへのアクセスを試みるまで、ドライバー ホスト プロセスへの I/O 要求のバッファーのコピーを延期します。 エラーが発生した場合、バッファー アクセス関数はドライバーにエラー状態の値を返します。

ドライバーは、各デバイスの IWDFDeviceInitialize2::SetIoTypePreference を呼び出すときにバッファー取得モードを指定できます。 次のルールを使用します。

  • ドライバーがダイレクト I/O アクセス メソッドを指定する場合は、遅延取得モードも指定する必要があります。 ダイレクト I/O は遅延取得でのみ機能します。

  • UMDF バージョン 1.9 以降で実行するように記述されたすべてのドライバーは、ドライバーがバッファーまたはダイレクト I/O アクセス メソッドのどちらをを選択するかに関係なく、すべての I/O 要求に遅延取得モードを指定する必要があります。 遅延取得は、ドライバーが使用しないバッファーにアクセスしないため、パフォーマンスが向上します。

ドライバーでバッファー取得モードが指定されていない場合、UMDF は即時取得を使用します。

ドライバー スタック内のすべての UMDF ベースのドライバーは、同じ取得モードを使用する必要があります。 一部のドライバーが即時取得を指定し、一部が遅延取得を指定した場合、UMDF は即時取得を使用します。

UMDF が I/O 要求のバッファー アクセス メソッドを選択する方法

ドライバーが IWDFDeviceInitialize2::SetIoTypePreference を呼び出すときにドライバーが指定するアクセス メソッドは、UMDF で使用されるアクセス メソッドではない可能性があります。 UMDF では次の規則を使用して、使用するアクセス方法を決定します。

  • ドライバー スタック内のすべての UMDF ベースのドライバーは、デバイスのバッファーにアクセスするために同じメソッドを使用する必要があります。 一部のドライバーがデバイスに対してバッファー I/O またはダイレクト I/O のいずれかを優先し、他のドライバーがデバイスのバッファー I/O のみを優先すると、UMDFが判断した場合、UMDF はすべてのドライバーにバッファー I/O を使用します。 1 つ以上のスタックのドライバーがバッファー I/O のみを優先し、他のドライバーがダイレクト I/O のみを優先する場合、UMDF はシステム イベント ログにイベントを記録し、ドライバー スタックを開始しません。

    ドライバーは、IWDFDevice2::GetDeviceStackIoTypePreference を呼び出して、UMDF がデバイスの読み取り/書き込み要求と I/O 制御要求に割り当てたバッファー アクセス メソッドを決定できます。

  • 場合によっては、ドライバーは IWDFDeviceInitialize2::SetIoTypePreference を呼び出すときにダイレクト I/O の優先設定を指定しますが、最適なパフォーマンスのために、UMDF は 1 つ以上のデバイスの要求にバッファー I/O を使用します。 たとえば、UMDF は、直接アクセスするバッファーをマップするよりも、データをドライバーのバッファーに高速にコピーできる場合、バッファー I/O を小さなバッファーに使用します。

    必要に応じてN、フレームワークがダイレクト I/O を使用する最小バッファー サイズを決定するためにフレームワークが使用する、REG_DWORD型指定の DirectTransferThreshold レジストリ値を設定できます。 フレームワークは最適なパフォーマンスを提供する値を使用するため、通常、このレジストリ値を指定する必要はありません。 DirectTransferThreshold 値は、デバイスのハードウェア キーの下にあるデバイスの Device Parameters\WUDF サブキーの下にあります。

    フレームワークでは、次の規則を使用して、DirectTransferThreshold で指定した値に基づいてしきい値を決定します。 指定された数値は 4096 のPAGE_SIZE を想定しており、Itanium ベースのシステムを除いて有効です。

    • DirectTransferThreshold を 8192 (または 2 * PAGE_SIZE) 以下の値に設定すると、フレームワークはしきい値を 8192 に設定します。 フレームワークでは、8192 バイト未満のバッファーにはバッファー I/O、8192 バイト以上のバッファーにはダイレクト I/O が使用されます。

    • DirectTransferThreshold を 8192 より大きい値に設定すると、フレームワークは PAGE_SIZE の次の正確な倍数に切り上げます。 ここでも、フレームワークでは、しきい値より小さいバッファーにはバッファー I/O を使用し、しきい値以上のバッファーにはダイレクト I/O を使用します。

  • UMDF は、メモリ ページの境界で開始および終了するバッファー領域にのみ、ダイレクト I/O を使用します。 バッファーの先頭または末尾がページ境界上にない場合、UMDF はバッファーのその部分にバッファー I/O を使用します。 つまり、UMDF では、複数の I/O 要求で構成される大規模なデータ転送に、バッファー I/O とダイレクト I/O の両方を使用ことがあります。

  • デバイス I/O 制御要求の場合、UMDF は、I/O 制御コード (IOCTL) がダイレクト I/O を指定し、すべてのデバイスの UMDF ベースのドライバーが IWDFDeviceInitialize2::SetIoTypePreference を呼び出してダイレクト アクセス メソッドを指定した場合にのみ、ダイレクト I/O を使用します。

ドライバーは、バッファー アクセス メソッドに関係なく、データ バッファーにアクセスするために同じ要求オブジェクト メソッドのセットを使用します。 そのため、ほとんどのドライバーは通常、UMDF が I/O 要求にバッファー I/O またはダイレクト I/O のどちらを使用しているか認識する必要はありません。

ドライバーが I/O 要求のアクセス方法を取得する方法

場合によっては、アクセス方法がわかっている場合に、デバイスとドライバーのパフォーマンスを向上させることができます。 このような場合、ドライバーは IWDFIoRequest2::GetEffectiveIoType を呼び出して、I/O 要求のバッファー アクセス メソッドを取得できます。

たとえば、通常はダイレクト I/O を使用する高スループット デバイスを考えてみましょう。 ダイレクト I/O を使用しているため、ドライバーは、検証後にアプリケーションがパラメーターを変更しないように、パラメーターを検証する前に、アプリケーション指定のパラメーターをローカル ドライバー メモリにコピーする必要があります。

ドライバーは、バッファー I/O を使用するバッファーを受け取る場合があり、バッファー I/O バッファーが既にコピーされているため、アプリケーションはデータを変更できず、ドライバーは検証前にパラメーターをコピーする必要はありません。 そのため、ドライバーは、検証する前にパラメーターをコピーする必要があるかどうかを判断するために、各要求のバッファー アクセス メソッドをチェックする必要があります。

UMDF ドライバーでのバッファー I/O の使用

ドライバーがバッファー I/O を使用している場合、UMDF の動作は要求の種類によって異なります。 読み取り要求と書き込み要求の場合、ドライバー ホスト プロセスは、ドライバーがアクセスできる 1 つの中間バッファーを作成します。

書き込み要求の場合、ドライバー ホスト プロセスは、ドライバー スタックを呼び出す前に、呼び出し元のアプリケーションの入力バッファーから入力情報を転送します。 ドライバーは通常、中間バッファーから入力情報を読み取り、デバイスに書き込みます。

読み取り要求の場合、ドライバーは通常、デバイスから情報を読み取り、中間バッファーに格納します。 ドライバー ホスト プロセスは、中間バッファーからアプリケーションの出力バッファーに出力データをコピーします。

ただし、デバイス I/O 制御要求の場合、ドライバー ホスト プロセスは、ドライバーがアクセスできる 2 つの個別のバッファーを作成します。 これは WDM ドライバーと KMDF ドライバーの動作とは異なり、ドライバーが単一の中間バッファーにアクセスするバッファー内の I/O バッファーを使用して送信される読み取り、書き込み、およびデバイスの I/O 制御要求です。 この場合、出力バッファーには最初は何も含まれていないため、ドライバーはそこから読み取るべきではありません。 さらに、ドライバーが入力バッファーに書き込むデータは破棄され、呼び出し元のアプリケーションには返されません。

バッファー I/O を選択するタイミングに関するガイドラインについては、WDF_DEVICE_IO_TYPE を参照してください。

UMDF バージョン 1.9 以降では、要求バッファーの即時取得または遅延取得をサポートできます。 詳細については、WDF_DEVICE_IO_BUFFER_RETRIEVAL を参照してください。

即時バッファー取得モードを使用するドライバーは、バッファーにアクセスするために IWDFIoRequest::GetInputMemoryIWDFIoRequest::GetOutputMemory を使用する必要があります。

遅延バッファー取得モードを使用するドライバーは、IWDFIoRequest2::RetrieveInputBufferIWDFIoRequest2::RetrieveInputMemoryIWDFIoRequest2::RetrieveOutputBuffer、または IWDFIoRequest2::RetrieveOutputMemory を呼び出すことによってバッファーにアクセスできます。

UMDF ドライバーでのダイレクト I/O の使用

ドライバーがダイレクト I/O を使用している場合、ドライバー ホスト プロセスは、I/O 要求の発信元 (通常はユーザーモード アプリケーション) が指定したバッファー領域のアクセシビリティを検証し、バッファー領域を物理メモリにロックし、バッファー領域への直接アクセスをドライバーに提供します。

ダイレクト I/O を選択するタイミングに関するガイドラインについては、WDF_DEVICE_IO_TYPE を参照してください。

ドライバーは、IWDFIoRequest2::RetrieveInputBufferIWDFIoRequest2::RetrieveInputMemoryIWDFIoRequest2::RetrieveOutputBuffer、または IWDFIoRequest2::RetrieveOutputMemory を呼び出すことによってバッファーにアクセスできます。

UMDF ドライバーでの、バッファー I/O でもダイレクト I/O でもないものの使用

バッファー I/O メソッドでもダイレクト I/O メソッドでもないと呼ばれるバッファー アクセス メソッド (「どちらでもないメソッド」とも呼ばれます) を使用すると、ドライバーはアプリケーションの要求バッファー ポインターに直接アクセスできます。 UMDF ベースのドライバーでは、このアクセス方法を使用できません。

ただし、一部のデバイス I/O 制御コード (IOCTL) の定義では、要求で「どちらでもない」メソッドを使用することを指定します。 必要に応じて、UMDF は、このようなデバイス I/O 制御要求のバッファー アクセス方法をバッファー I/O またはダイレクト I/O に変換できます。 次の手順に従います。

  1. ドライバーの INF ファイルの INF DDInstall セクションUmdfMethodNeitherAction ディレクティブを含めます。 このディレクティブの値を設定して、UMDF が「どちらでもない」アクセス メソッドを使用するデバイス I/O 制御要求をドライバーに渡す必要があることを示すことができます。 (それ以外の場合、UMDF はエラー状態値でこれらの I/O 要求を完了します)。

  2. バッファー I/O またはダイレクト I/O に対して UMDF が提供するオブジェクト メソッドを使用して、I/O 要求のバッファーにアクセスします。

UMDF がアクセス メソッドをバッファー I/O またはダイレクト I/O に変換できることが確実である場合にのみ、「どちらでもない」メソッドを使用する IOCTL 要求のサポートを有効にする必要があります。 たとえば、「I/O コントロール コードのバッファーの説明」で説明されているバッファー仕様規則に従っていない、カスタマイズされた要求を IOCTL で指定した場合、UMDF はバッファーを変換できません。