15.1.1 Releasing Driver-Allocated Resources
An Unload routine is responsible for freeing all the system objects and resources the driver is using before the driver itself is unloaded.
In other words, the Unload routine must call the following support routines:
·IoDisconnectInterrupt if the driver has registered an ISR with IoConnectInterrupt
·IoDeleteSymbolicLink if the DriverEntry or Reinitialize routine called IoCreateSymbolicLink, and IoDeassignArcName if the driver called IoAssignArcName
·ExFreePool if the DriverEntry or any other driver routine called ExAllocatePool and the memory has not yet been released
·MmUnmapIoSpace if the DriverEntry routine called MmMapIoSpace
·MmFreeNonCachedMemory if the DriverEntry routine called MmAllocateNonCachedMemory
·MmFreeContiguousMemory if the DriverEntry routine called MmAllocateContiguousMemory
·HalFreeCommonBuffer if the DriverEntry routine called HalAllocateCommonBuffer
·IoAssignResources or IoReportResourceUsage if the DriverEntry routine called one of these support routines or HalAssignSlotResources to claim hardware resources in the configuration registry for itself and/or for its physical devices individually
Consider the following a general design guideline for Unload routines
Every Unload routine must ensure that no other driver routine is currently using or might shortly be using any driver-allocated resource before the Unload routine frees that resource.
For example, an Unload routine must call IoStopTimer if the driver's IoTimer routine is currently enabled for a particular device object. It must ensure that no thread is waiting on any of the driver's dispatcher objects and/or that its timer object(s) are not queued for calls to its CustomTimerDpc routine(s) before it frees the storage for its dispatcher objects. It must call KeRemoveQueueDpc if it has a CustomDpc routine that the ISR might have queued, and so on.
Any device driver must call IoDisconnectInterrupt with the interrupt object(s) pointer if it called IoConnectInterrupt in its DriverEntry routine. Its Unload routine must call IoDisconnectInterrupt before it deletes the storage for this pointer.
Any higher-level driver that called IoGetDeviceObjectPointer in its DriverEntry or Reinitialize routine must call ObDereferenceObject with the pointer to the file object associated with the lower driver's device object. Its Unload routine must call ObDereferenceObject before it deletes the storage for this pointer.
Any higher-level driver that called IoAttachDevice in its DriverEntry or Reinitialize routine must call IoDetachDevice with the pointer to the lower driver's device object. Its Unload routine must call IoDetachDevice before it deletes the storage for this pointer.
If the driver allocated nonpaged pool as storage for any Kernel-defined object(s) it uses, the Unload routine must explicitly call ExFreePool to free the storage and the object(s).
If the driver called PsCreateSystemThread, the Unload routine also must cause the driver-created thread to be run so that the thread itself can call PsTerminateSystemThread before the driver is unloaded from the system. A driver-created system thread cannot be released by calling ZwClose with the ThreadHandle returned by PsCreateSystemThread.
For more information about symbolic links, about claiming resources in the registry, about releasing registry resources, and about allocating memory, see also Chapter 16. For specific information about any particular support routine, see the Kernel-Mode Driver Reference.