5.2.2 Higher-Level Driver’s Initialization
The DriverEntry routine of a higher-level NT driver should initialize itself in the following stages:
1.Allocate memory for and gather whatever configuration information it needs from the registry.
For example, a higher-level driver might search the registry for the named device objects created by already loaded device drivers that represent a particular type of device so the higher-level driver can layer itself over appropriate device drivers or the drivers layered above them.
2.Set the driver’s Dispatch, StartIo (if any), and Unload (if any) entry points in the given driver object.
3.Set up the NT objects and any other system resources, such as spin locks, that the driver will use to process I/O requests, and connect or attach its own device object(s) to the next-lower driver’s device object(s) with IoGetDeviceObjectPointer or IoAttachDevice.
4.Set up value entries in its own keys in the registry, such as the named device object(s) this driver created, so that still higher-level drivers can layer themselves over this driver.
5.If the driver successfully layered itself over one or more underlying device drivers, free the memory it allocated to hold configuration information from the registry, or possibly call IoRegisterDriverReinitialization passing a Context pointer to the configuration information, and return STATUS_SUCCESS.
Otherwise, free any objects and system resources it allocated, including the memory it used to hold configuration information, and return an appropriate NTSTATUS error.
Every writer of a higher-level NT driver should consider the following guidelines when implementing a DriverEntry routine:
·If the driver calls IoGetDeviceObjectPointer successfully, it must save the returned pointer to the next-lower driver’s device object; this pointer is a required parameter to IoCallDriver.
·A higher-level NT driver should save the file object pointer returned by IoGetDeviceObjectPointer. Such a higher-level driver must call ObDereferenceObject if the underlying driver has an Unload routine, described in Chapter 15, and is later unloaded.
·If the driver calls IoAttachDevice successfully, it must save the pointer to the next-lower driver’s device object; this pointer is a required parameter to IoCallDriver.
·To call IoAttachDevice, the driver must create a device object of its own first. If subsequent call(s) to IoAttachDevice do not succeed, the driver must call IoDeleteDevice with the device object(s) that it created.
·Because the DriverEntry routine runs in a system thread context at IRQL PASSIVE_LEVEL, any memory allocated with ExAllocatePool for use exclusively during initialization can be from paged pool, provided that the underlying device driver does not control the device that holds the system page file. Such a memory allocation must be freed with ExFreePool before DriverEntry returns control unless the driver passes a pointer to this memory in a call to IoRegisterDriverReinitialization, making the driver’s Reinitialize routine responsible for freeing the memory allocation.
·If the driver has a Reinitialize routine, its DriverEntry routine must not call IoRegisterDriverReinitialization unless it will return STATUS_SUCCESS.