1. |
Do not return status_pending through the scheduling routine without marking I/O Request Packet (IRP) suspension (iomarkirppending. |
2. |
Do not call kesynchronizeexecution through the interrupt service routine (ISR. It causes a system deadlock. |
3. |
Do not set deviceobject-> flags to do_buffered_io or do_direct_io. It will disrupt the system and eventually lead to fatal errors. In addition, do not set method_buffered, method_neither, method_in_direct, or method_out_direct in deviceobject-> flags, because these values are only used when IOCTL is defined. |
4. |
Do not assign scheduling program objects through the page buffer pool. If this is done, it will occasionally lead to system fault detection (bugcheck ). |
5. |
When running on IRQL> = dispatch_level, do not allocate memory through the page buffer pool or access the memory in the page buffer pool. This is a fatal error. |
6. |
Do not wait for the non-zero interval of the core scheduler object on IRQL> = dispatch_level. This is a fatal error. |
7. |
When executing on IRQL> = dispatch_level, do not call any function that causes the calling thread to wait directly or indirectly. This is a fatal error. |
8. |
Do not reduce the interrupt request level (IRQL) to a level lower than that called by your top-level routine. |
9. |
If keraiseirql () has not been called, do not call kelowerirql (). |
10. |
Do not stop the processor for more than 50 microseconds. |
11. |
Do not keep the spin lock locked for more time than you need. To improve the overall performance of the system, do not lock effective rotation locks in any system range for more than 25 microseconds. |
12. |
When IRQL is greater than dispatch_level, do not call keacquirespinlock and kereleasespinlock, or keacquirespinlockatdpclevel and kereleasespinlockfromdpclevel. |
13. |
Do not call kereleasespinlockfromdpclevel to release the rotation lock obtained by keacquirespinlock, because this will make the original IRQL unrecoverable. |
14. |
Do not call keacquirespinlock and kereleasespinlock in ISR or synchcritsection routines or any other routine that uses the executable rotation lock. |
15. |
When you create a device object in a routine instead of in DriverEntry, do not forget to clear the do_device_initializing tag. |
16. |
Do not add the delayed Procedure Call (DPC) object to the queue (using keinsertqueuedpc) in multiple threads of different processors at the same time ). This can cause fatal errors. |
17. |
Do not release the cycle timer through the cutomertimerdpc routine. You can release a non-cyclic timer through the DPC routine. |
18. |
Do not pass the same DPC pointer to the kesettimer, or the kesettimerex (customtimerdpc) and keinsertqueuedpc (customdpc), because this will lead to competition. |
19. |
Do not call iostartnextpacket when rotating the lock. This will cause a system deadlock. |
20. |
Do not call iocompleterequest when rotating the lock. This will cause a system deadlock. |
21. |
If your driver has set the completion routine, do not call iocompleterequest without setting the completion routine to null. |
22. |
Before calling iocompleterequest, do not forget to set the I/O status zone in the IRP. |
23. |
Do not call iomarkpending after you add an IRP to a queue or send it to another driver (iocalldriver. Before the driver calls iomarkpending, the IRP may have been completed, and fault detection may occur. For drivers that contain completion routines, if IRP-> pendingreturned is set, the completion routine must call iomarkpending. |
24. |
Do not access a certain IRP after calling iocompleterequest. |
25. |
Do not call iocancelirp for IRPs that do not belong to your driver unless you know that the IRP is not complete. |
26. |
Before your scheduling routine returns to the caller, do not call iocancelirp for the IRP being processed by your scheduling routine. |
27. |
Do not call iomakeassociatedirp from an intermediate driver to create IRP for a lower driver. The IRP obtained in the intermediate driver may be the associated IRP, but you cannot associate other IRPs with the associated IRP. |
28. |
Do not call iomakeassociatedirp for the IRPs set with buffer I/O. |
29. |
Do not simply unreference the virtual pointer pointing to the device I/O register and access these pointers. Always use the correct Hardware Abstraction Layer (HAL) function to access the device. |
30. |
If the IRP or device object may be modified at the dispatch level, do not access it through ISR. In a symmetric multi-processor system, this can cause data corruption. |
31. |
When running advanced IRQL, do not modify the data if the data may be written by the low-level irol code. The kesynchronizeexecution routine should be used. |
32. |
Do not obtain the driver's own rotation lock (if any) in your dispatchcleanup routine before obtaining the ioacquirecancelspinlock of the system range ). To avoid possible deadlocks, you must follow the consistent lock acquisition hierarchy in the driver. |
33. |
Do not call ioacquirecancelspinlock In the cancel routine because the system-level cancel rotation lock is obtained when the routine is called. |
34. |
Do not forget to call ioreleasecancelspinlock before returning from the cancel routine. |
35. |
Do not use IRQL-based synchronization because it is only valid for single-processor systems. Increasing IRQL on a single processor will not mask interruptions on other processors. |
36. |
Do not use rtlcopymemory for overlapping memory address ranges. Rtlmovememory should be used. |
37. |
Do not assume that the page size is a constant, even for a given CPU. To maintain portability, use page_size and other page-related constants defined in the header file. |
38. |
Do not access any registry items except registry/machine/hardware and registry/machine/system from the DriverEntry routine of the driver loaded during boot/system initialization. |
39. |
Do not create an Enum entry in the Registry/machine/system/CurrentControlSet/services of the driver to load the driver. The system dynamically creates this item. |
40. |
If you do not apply for required bus-related I/O Ports, memory ranges, interruptions, or direct memory access (DMA) channels/ports, and other hardware resources in the registry, do not initialize a physical device. |
41. |
Do not call ioregisterdriverreinitialization in your DriverEntry routine unless the reinitialization routine returns STATUS_SUCCESS. |
42. |
When IRQL is passive_level, do not call the kesetevent when the wait parameter is set to true in the page-scheduled thread or driver routine. If your routine is scheduled out of the page between the call of kesetevent and kewait.. Object (s), such calls will cause a fatal page error. |
43. |
Kereleasesemaphore cannot be called under the same conditions as the preceding example. |
44. |
Kereleasemutex cannot be called under the same conditions as the preceding example. |
45. |
Do not use the retail Windows NT driver to call kebugcheckex or kebugcheck to stop the system running, unless you encounter an important error that damages the system memory and eventually leads to system failure detection. Always cleverly handle error conditions. |
46. |
Do not assume that the iotimer routine will be accurately called at the one-second boundary, because the call interval of any specific iotimer routine depends on the system clock. |
47. |
Do not call the Win32 application programming interface (API) from the device driver in the core mode ). |
48. |
Do not use recursive functions that will cause stack overflow, because the core mode of the calling thread does not support dynamic growth of stacks. |
49. |
In ISR routines that process multiple interrupts, do not use the interrupt Object Pointer (pkinterrupt) to identify the interrupt, because the interrupt object address you get in ISR is not always the same as the address you get through ioconnectinterrupt. To identify the device that is currently interrupted, use only the servicecontext value specified in ioconnectinterrupt. |
50. |
If customtimerdpc (kecanceltimer) is not cleared, do not uninstall the driver. If the DPC is started after the driver is uninstalled, it may call non-existent code and cause the system to go to fault detection. |
51. |
If the I/O completionroutine of a driver is set in IRP, you must wait until all these IRPs are completed before you can uninstall the driver. If IRP is completed by a lower-level driver after the driver is uninstalled, the system tries to execute non-existent code and causes the system to crash. |
52. |
The device interruption must be enabled only when the driver is ready to handle a device interruption. It should be enabled only after the driver initialization is completed. When ISR and DPC are executed, the system can securely access several private members of the device object. |
53. |
When rotating the lock, do not call code other than the driver, because this will cause a deadlock. |
54. |
If your driver creates an IRP through iobuildasynchronousfsdrequest/ioallocateir, do not return any status other than status_more_processing_required for this IRP from your I/O completionroutine, this IRP is not prepared for the post-processing work of the completed I/O manager. Such IRP should be explicitly released by the driver (iofreeirp ). If you do not intend to reuse IRP, you can release it in completionroutine before returning status_more_processing_required. |
55. |
Do not use iobuildsynchronousfsdrequest/iobuilddeviceiocontrolrequest in any thread context to allocate IRP, because the IRP is still associated with the thread (IRP-> threadlistentry) until it is released. |
56. |
If you have used ioallocateirp to assign an IRP when the chargequota parameter is set to true, do not call ioinitializeirp for this IRP. If an IRP is assigned when chargequota is set to true, the I/O manager saves the information about the buffer pool used when it allocates memory for the IRP in the internal tag of the IRP. If ioinitializeirp is called for such IRPs, the allocation pool information will be lost when the function blindly clears the entire IRPs. When you release the IRP, the memory will be damaged. At the same time, do not reuse IRP from the IO manager. To reuse IRP, you should use ioallocateirp to allocate your own IRP. |
57. |
If an object is assigned to the stack of the call thread, do not specify waitmode as usermode in kewaitforsingleobject/kewaitformultipleobjects. The result is that if the waiting object is created in the function stack, you must specify waitmode as kernelmode to prevent the thread from being scheduled by the page. |
58. |
When the code in the key section is not protected, do not obtain resources such as eresources and fastmutex (unsafe) in the context of the user mode thread. Because obtaining these resources does not increase IRQL to apc_level, if the thread is suspended after obtaining the resources (implemented by adding APC to the queue), it may lead to a deadlock, and reduce system security. Therefore, IRQL should be explicitly raised to apc_level, or keentercriticalregion should be called to enter key segments, and then these resources can be obtained. |