バッファー付き I/O とダイレクト I/O のどちらも使用しない
ドライバーがバッファー付き I/O もダイレクト I/O も使用していない場合、I/O マネージャーは、ドライバーに送信される IRP 内の元のユーザー空間仮想アドレスを渡します。 これらのバッファーに安全にアクセスするには、ドライバーが呼び出し元のスレッドのコンテキストで実行されている必要があります。 通常、バッファーへのアクセスには、FSD などの最上位レベルのドライバーのみがこのメソッドを使用できます。
中間または最下位レベルのドライバーは、常にこの条件を満たすことはできません。 たとえば、要求スレッドが I/O 要求の完了を待機している場合、または上位レベルのドライバーが中間または最下位レベルのドライバーに階層化されている場合、要求スレッドのコンテキストで下位レベルのドライバーのルーチンが呼び出される可能性は低くなります。
I/O マネージャーは、I/O 操作がバッファー付き I/O またはダイレクト I/O のどちらも使用していないことを次のように判断します。
IRP_MJ_READ 要求と IRP_MJ_WRITE 要求の場合、DEVICE_OBJECT 構造体の Flags メンバーに DO_BUFFERED_IO も DO_DIRECT_IO も設定されていません。 詳細については「デバイス オブジェクトの初期化」を参照してください。
IRP_MJ_DEVICE_CONTROL 要求と IRP_MJ_INTERNAL_DEVICE_CONTROL 要求の場合、IOCTL コードの値には、IOCTL 値の TransferType 値として METHOD_NEITHER が含まれます。 詳細については「I/O 制御コードの定義」参照してください。
ドライバーは、バッファー付き I/O または直接 I/O のどちらも使用しない I/O 操作を指定する IRP を受け取る場合は、次の操作を行う必要があります。
ProbeForRead および ProbeForWrite サポート ルーチンを使用して、ユーザー バッファーのアドレス範囲の有効性を確認し、適切な読み取りまたは書き込みアクセスが許可されているかどうかを確認します。 ドライバーは、ドライバーがメモリにアクセスしている間、ユーザー スレッドがバッファーのアクセス権を変更できないように、ドライバーが指定した例外ハンドラー内でバッファーのアドレス範囲へのアクセスを囲む必要があります。 プローブが例外を発生させる場合、ドライバーはエラーを返す必要があります。 ドライバーは、I/O 要求を行ったスレッドのコンテキスト内でこれらのルーチンを呼び出す必要があります。そのため、このタスクを実行できるのは、上位レベルのドライバーのみです。
バッファーとメモリ操作は、次のいずれかの方法で管理します。
- バッファー付き I/O を使用するドライバーに対して I/O マネージャーが行うのと同様に、独自のダブル バッファリング操作を実行します。 詳細についてはバッファー付き I/O の使用を参照してください。
- ダイレクト I/O を使用するドライバーに対して I/O マネージャーが行うのと同様に、メモリ マネージャーのサポート ルーチンを呼び出して、独自の MDL を作成し、バッファーをロックダウンします。 詳細についてはダイレクト I/O の使用を参照してください。
- 呼び出し元のスレッドのコンテキストで、ユーザー バッファーに対して必要なすべての操作を直接実行します。 ドライバーは、ドライバーがメモリにアクセスしているときに、ユーザー スレッドがバッファーまたはバッファー内のデータのアクセス権を変更した場合に備えて、ドライバーが指定した例外ハンドラー内でバッファーへのアクセスをラップする必要があります。 詳細については、例外処理を参照してください。
実際には、ドライバーは、呼び出し元のスレッドのコンテキストでバッファー付き I/O、ダイレクト I/O、または I/O を実行するかどうかを IRP ごとに選択する必要があり、ユーザー モードのスレッド コンテキストで発生する可能性がある例外を処理する必要があります。 ドライバーは、I/O マネージャーがドライバーのこれらの操作を処理するのではなく、必要に応じて、独自のユーザー バッファー アクセス、ダブル バッファリング操作、およびメモリ マッピングを管理する必要があります。