DDK:Windows NT ドライバ開発者へのヒント

文書翻訳 文書翻訳
文書番号: 186775 - 対象製品
この記事は、以前は次の ID で公開されていました: JP186775
すべて展開する | すべて折りたたむ

概要

以下は Windows NT デバイス ドライバを作成するためのヒント集です。紹介するヒントはすべての技術に適用されます。ドライバの問題解決用のチェックリストとしてご利用ください。

以下に示しました情報を効果的に利用するには、Windows NT のアーキテクチャとデバイス ドライバ開発経験に対する基礎的な知識が必要です。デバイス ドライバを開発する上での情報として、MSDN プロフェッショナルメンバシップで提供されております Windows NT デバイス ドライバキット(DDK)をご参照ください。

詳細

Windows NT デバイス ドライバを開発する時に避けなければならないことを、以下に一覧で示してあります:
  1. I/O リクエスト パケット(IRP)を保留 (IoMarkIrpPending) にしないで、ディスパッチ ルーチンから STATUS_PENDING を返してはいけない。
  2. 割り込みサービスルーチン(ISR)から KeSynchronizeExecution を呼び出してはいけない。システムがデッドロックする。
  3. DeviceObject->Flags に対して DO_BUFFERED_IO と DO_DIRECT_IO の両方を設定してはいけない。システムを混乱させ、結局、致命的なエラーを引き起こす。また、DeviceObject->Flags には、METHOD_BUFFERED、METHOD_NEITHER、METHOD_IN_DIRECT や METHOD_OUT_DIRECT を設定してはいけない。これらの値は IOCTL を定義する時にだけ使用される。
  4. ページドプールからディスパッチャ オブジェクトを割り当ててはいけない。これを行うとシステム バグチェックの原因となる。
  5. IRQL >= DISPATCH_LEVEL で動作中に、ページドプールからメモリを割り当てたり、ページドプールをアクセスしてはいけない。致命的エラーになる。
  6. IRQL >= DISPATCH_LEVEL で動作中に、ゼロではないインターバルでカーネル ディスパッチャ オブジェクトを待機してはいけない。致命的エラーになる。
  7. IRQL >= DISPATCH_LEVEL で実行している間に、直接あるいは間接的に待機するためのスレッドを呼び出すような関数を呼び出してはいけない。致命的エラーになる。
  8. 割込み要求レベル(IRQL)を、トップレベルルーチンが起動されるレベルより下げてはいけない。
  9. KeRaiseIrql を呼び出していないのに、KeLowerIrql を呼び出してはいけない。
  10. 50 マイクロ秒以上プロセッサを停止 (KeStallExecutionProcessor) してはいけない。
  11. 必要以上に長くスピンロックを保持してはいけない。よりよいシステム パフォーマンスを得るには、25 マイクロ秒以上のシステム全体のスピンロックを持たないこと。
  12. IRQL が DISPATCH_LEVEL より上で実行している間に、KeAcquireSpinLock と KeReleaseSpinLock、または KeAcquireSpinLockAtDpcLevel と KeReleaseSpinLockFromDpcLevel を呼び出してはいけない。
  13. KeAcquireSpinLock で獲得したスピンロックを、KeReleaseSpinLockFromDpcLevel によって解放してはいけない。オリジナルの IRQL が復元されなくなる。
  14. KeAcquireSpinLock と KeReleaseSpinLock や、ISR または SynchCritSection ルーチンからエグゼクティブ スピンロックを使用する他のルーチンを呼び出してはいけない。
  15. DriverEntry 以外のルーチンでデバイス オブジェクトを生成する時、DO_DEVICE_INITIALIZING フラグをクリアすることを忘れてはいけない。
  16. 異なるプロセッサ上で、同時に複数のスレッドによって、(KeInsertQueueDpc を使って) 遅延手続き呼び出し (DPC)をキューイングしてはいけない。致命的エラーを引き起こす。
  17. CutomerTimerDPC ルーチンから周期的なタイマを解放してはいけない。DPC ルーチンからは周期的ではないタイマなら解放できる。
  18. KeSetTimer または KeSetTimerEx(CustomTimerDpc)と、KeInsertQueueDpc(CustomDpc)に、同じ DPC ポインタを渡してはいけない。競合状態の原因となる。
  19. スピンロックを保持している間に IoStartNextPacket を呼び出してはいけない。システムがデッドロックする。
  20. スピンロックを保持している間に IoCompleteRequest を呼び出してはいけない。システムがデッドロックする。
  21. ドライバが完了ルーチンを設定する場合、完了ルーチンを NULL に設定しないで IoCompleteRequest を呼び出してはいけない。
  22. IoCompleteRequest を呼び出す前に、IRP の I/O ステータス ブロックの設定を忘れてはいけない。
  23. IRP をキューイングした後、または別のドライバに送信(IoCallDriver)した後に、IoMarkPending を呼び出してはいけない。ドライバが IoMarkPending を呼び出す前に IRP が完了するかもしれないし、バグチェックが発生するかもしれない。完了ルーチンを持つドライバにおいて、Irp->PendingReturned を設定する場合、完了ルーチンは IoMarkPending を呼び出さなければならない。
  24. IoCompleteRequest を呼び出した後に、その IRP を参照・更新してはいけない。
  25. IRP が完了していないことを認識するまで、そのドライバが所有していない IRP で IoCancelIrp を呼び出してはいけない。
  26. ディスパッチ ルーチンが呼び出し元に戻るまで、IRP に対する IoCancelIrp を呼び出してはいけない。
  27. 中間ドライバから下位ドライバ用の IRP を作成するために、IoMakeAssociatedIrp を呼び出してはいけない。中間ドライバで得られる IRP は関連した IRP でもよいが、既に関連した IRP に対して他の IRP を関連付けすることはできない。
  28. バッファード I/O 用に設定された IRP で IoMakeAssociatedIrp を呼び出してはいけない。
  29. デバイス I/O レジスタの仮想ポインタを無視してそれらをアクセスしてはいけない。デバイスをアクセスするための、正しいハードウェア アブストラクション レイヤ(HAL)関数を常に使用すること。
  30. DISPATCH_LEVEL から変更されるかもしれない IRP、または ISR からのデバイス オブジェクトのフィールドをアクセスしてはいけない。対称型マルチプロセッサ システムではデータ変造の原因となる。
  31. データが低レベル IRQL コードによって変更されるかもしれない場合、高レベル IRQL で実行している間に、そのデータを変更してはいけない。KeSynchronizeExecution ルーチンを使うこと。
  32. システム全体のキャンセル スピンロックを獲得する (IoAcquireCancelSpinLock) 前に、DispatchCleanup ルーチンの中で、そのドライバ自身のスピンロック (持っている場合) の 1 つを獲得しないこと。ドライバを通して統一のとれたロック取得階層構造を追うことは、潜在的なデッドロックを避けるために不可欠である。
  33. キャンセル ルーチンの中で IoAcquireCancelSpinLock を呼び出してはいけない。それに代わって常にシステム キャンセル スピンロックで呼び出される。
  34. キャンセル ルーチンから戻る前に、IoReleaseCancelSpinLock を呼び出すことを忘れてはいけない。
  35. IRQL ベースの同期を使ってはいけない。これはシングル プロセッサ システムにだけ動作する。1 つのプロセッサで IRQL を上げても、他のプロセッサでは割り込みがマスクされない。
  36. 重なったメモリ領域をアクセスする場合に RtlCopyMemory を使ってはいけない。RtlMoveMemory を使用する。
  37. 動作している CPU のページサイズが固定であると仮定しないこと。移植性を維持するために、PAGE_SIZE とヘッダファイルに定義されているページに関連する他の定数を使用すること。
  38. Boot\System 初期化フェーズでロードされるドライバの DriverEntry ルーチンから、Registry\Machine\Hardware と Registry\Machine\System 以外のレジストリキーをアクセスしてはいけない。
  39. ドライバのレジストリキー(Registry\Machine\System\CurrentControlSet\Services)の下に、ドライバをロードするために Enum キーを作成してはいけない。システムはこのキーを動的に生成する。
  40. レジストリの、バス相対 I/O ポート、メモリ領域、割り込みやダイレクトメモリアクセス(DMA)チャネル/ポートなどの、必要なハードウェアリソースを最初に要求しないで、物理デバイスを初期化しようとしてはいけない。
  41. DriverEntry ルーチンが STATUS_SUCCESS を返すまで、IoRegisterDriverReinitialization を呼び出してはいけない。
  42. IRQL PASSIVE_LEVEL で動作するページ化可能なスレッドやページ化可能なドライバルーチンから、Wait パラメタを TRUE にして KeSetEvent を呼び出してはいけない。この種の呼び出しは、そのルーチンが KeSetEvent と KeWait..Object(s) の呼び出しの間でページアウトされるようなことが起こる場合、致命的なページフォールトの原因となる。
  43. IRQL PASSIVE_LEVEL で動作するページ化可能なスレッドやページ化可能なドライバルーチンから、Wait パラメタを TRUE にして KeReleaseSemaphore を呼び出してはいけない。この種の呼び出しは、そのルーチンが KeReleaseSemaphore と KeWait..Object(s)の呼び出しの間でページアウトされるようなことが起こる場合、致命的なページフォールトの原因となる。
  44. IRQL PASSIVE_LEVEL で動作するページ化可能なスレッドやページ化可能なドライバルーチンから、Wait パラメタを TRUE にして KeReleaseMutex を呼び出してはいけない。この種の呼び出しは、そのルーチンが KeReleaseMutex と KeWait..Object(s) の呼び出しの間でページアウトされるようなことが起こる場合、致命的なページフォールトの原因となる。
  45. 発生したエラーが、システムメモリを破壊したり、最終的にシステムにバグチェックを起こさせるような重大なエラーでない限り、製品用の Windows NT ドライバからシステムをダウンさせるような、KeBugCheckEx や KeBugCheck を呼び出してはいけない。常に礼儀正しくエラー条件を取り扱うようにしなさい。
  46. どんな特別な IoTimer ルーチンでも、インタバルはシステムクロックの解像度に最終的に依存して呼び出されるので、IoTimer ルーチンが正確に 1/2 周期で呼び出されると仮定してはいけない。
  47. カーネル モード デバイス ドライバから、Win32s アプリケーション プログラミング インタフェース(API)を呼び出してはいけない。
  48. カーネル モードで動作している間、呼出したスレッドのカーネル モード スタックは動的に拡張されないので、スタックオーバーフローを引き起こすような再帰呼び出し関数を使用してはいけない。
  49. 複数の割り込みを扱う ISR の中で割り込みを識別するために、割り込みオブジェクトポインタ(PKINTERRUPT )を使ってはいけない。ISR の中で得られる割り込みオブジェクトのアドレスは、IoConnectInterrupt から得たものと常に同じものではない。現在の割込みデバイスを識別するために、IoConnectInterrupt で指定する ServiceContext の値のみを使用すべきである。
  50. CustomTimerDpc(KeCancelTimer)をクリアせずにドライバをアンロードしてはいけない。ドライバがアンロードされた後に DPC が呼び出された場合、存在しないコードを参照し、システムのバグチェックを発生する原因となる。
  51. ドライバが設定した I/O CompletionRoutine を持つすべての IRP が完了するまでドライバをアンロードしてはいけない。ドライバがアンロードされた後に IRP が下位ドライバによって完了した場合、システムは存在しないコードを実行しようとして、システムクラッシュの原因となる。
  52. ドライバがデバイス割り込みを扱う準備ができるまでデバイス割り込みを有効にしてはいけない。そのドライバが完全に初期化され、ISR と DPC でドライバ内部の構造体をシステムで安全に参照できるようになった後に有効にすべきである。
  53. スピンロックを保持したままドライバ外の処理を呼び出してはいけない。デッドロックの原因となる。
  54. IoBuildAsynchronousFsdRequest/IoAllocateIrp によってドライバで生成した IRP 用の I/O CompletionRoutine から STATUS_MORE_PROCESSING_REQUIRED を返すのを忘れてはいけない。IRP は I/O マネージャによって関連した後処理の完了を準備できなくなる。そのような IRP は、確実に (IoFreeIrp で) ドライバによって解放されなければならない。IRP を再使用しない場合、STATUS_MORE_PROCESSING_REQUIRED ステータスを返す前に、CompletionRoutine の中で解放できる。
  55. 任意のスレッドコンテキストの中で IoBuildSynchronousFsdRequest/IoBuildDeviceIoControlRequest を使って IRP を割り当ててはいけない。その IRP が解放されるまで、関連したスレッド(Irp->ThreadListEntry)に IRP が残されてしまう。
  56. ChargeQuota パラメタを TRUE に設定して IoAllocateIrp で割り当てられた IRP で、IoInitializeIrp を呼び出してはいけない。IRP が ChageQuota を TRUE に設定して割り当てられた時、I/O マネージャは、IRP の内部フラグにある IRP 用に割り当てられたメモリからプールに関する情報を保持する。そのような IRP で IoInitializeIrp を呼び出した場合、この関数によって、すべての IRP の割り当てプール情報が暗黙的にゼロにされてしまう。これは IRP を解放する際に、メモリ変造を起こすことになる。また、I/O マネージャから渡される IRP を再利用できなくなる。IRP 再利用が必要な場合、IoAllocateIrp を使用して自分で割り当てるべきである。
  57. オブジェクトが呼出しスレッドのスタックで割り当てられている場合、KeWaitForSingleObject/KeWaitForMultipleObjects で、WaitMode を UserMode に指定してはいけない。これは、待機中のオブジェクトが関数スタックで作成されている場合、スレッドスタックがページアウトされてしまうことを防ぐために、WaitMode には KernelMode を指定しなければならない。
  58. クリティカル セクションの中でコード保護なしに、ユーザ モード スレッドのコンテキストで、イベント、セマフォ、リソース、ファストミューテックス(安全でない)のような同期オブジェクトを獲得してはいけない。リソースを獲得した直後、スレッドが中断される(APC にキューイングされる)場合に、これらのリソースの獲得が、IRQL を APC_LEVEL に上げないためである。これによってデッドロックを発生し、システム セキュリティに障害を及ぼす。したがって、IRQL を APC_LEVEL に明示的に上げるか、または、KeEnterCriticalRegion を呼び出してクリティカル セクションの中で、そのようなリソースを獲得すべきである。

関連情報

MSDN : Windows NT 用デバイス ドライバデザインガイド

関連情報

この資料は米国 Microsoft Corporation から提供されている Knowledge Base の Article ID 186775 (最終更新日 2000-06-26) をもとに作成したものです。

プロパティ

文書番号: 186775 - 最終更新日: 2004年2月2日 - リビジョン: 3.0
この資料は以下の製品について記述したものです。
  • Microsoft Win32 Device Driver Kit for Windows NT 4.0
  • Microsoft Win32 Device Driver Kit for Windows NT 3.51
キーワード:?
kbdebug kbdsh kbinfo kbntos351 kbntos400 KB186775
"Microsoft Knowledge Baseに含まれている情報は、いかなる保証もない現状ベースで提供されるものです。Microsoft Corporation及びその関連会社は、市場性および特定の目的への適合性を含めて、明示的にも黙示的にも、一切の保証をいたしません。さらに、Microsoft Corporation及びその関連会社は、本文書に含まれている情報の使用及び使用結果につき、正確性、真実性等、いかなる表明・保証も行ないません。Microsoft Corporation、その関連会社及びこれらの権限ある代理人による口頭または書面による一切の情報提供またはアドバイスは、保証を意味するものではなく、かつ上記免責条項の範囲を狭めるものではありません。Microsoft Corporation、その関連会社 及びこれらの者の供給者は、直接的、間接的、偶発的、結果的損害、逸失利益、懲罰的損害、または特別損害を含む全ての損害に対して、状況のいかんを問わず一切責任を負いません。(Microsoft Corporation、その関連会社 またはこれらの者の供給者がかかる損害の発生可能性を了知している場合を含みます。) 結果的損害または偶発的損害に対する責任の免除または制限を認めていない地域においては、上記制限が適用されない場合があります。なお、本文書においては、文書の体裁上の都合により製品名の表記において商標登録表示、その他の商標表示を省略している場合がありますので、予めご了解ください。"
サポート期間が終了した「サポート技術情報」資料に関する免責事項
この資料は、マイクロソフトでサポートされていない製品について記述したものです。そのため、この資料は現状ベースで提供されており、今後更新されることはありません。

フィードバック

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com