Declaring functions in KMDF and WDM Drivers
The Windows Driver Kit for Windows Vista with Service Pack 1 (SP1) and Windows Server 2008 introduces a new way to declare your event callback functions for KMDF drivers and dispatch routines for WDM drivers. This new type of declaration uses function role types. Function role types are predefined typedef declarations that identify the distinct roles that are defined for event callback functions in the underlying KMDF driver model or dispatch routines in the underlying WDM driver model. The function role type declarations replace traditional declarations for these functions.
Note The function role type declarations are simply declarations that use the standard C and C++ typedef specifier. The typedef declarations provide a way to introduce a common naming convention and a way to encapsulate details about the function role type implementation.
The static analysis tools, Static Driver Verifier and PREfast for Drivers, require that each event callback function in a KMDF driver and each dispatch routine in a WDM driver be declared by specifying the corresponding role type. The function role types identify the function’s intended purpose. PREfast for Drivers uses the function role types to more accurately detect syntax and coding errors, such as the incorrect use of certain functions, or driver-specific errors, such as saving a pointer to a string or structure argument instead of copying an argument in a DriverEntry routine. Static Driver Verifier uses these function role types to determine whether the driver correctly interacts with the Windows operating system kernel. Static Driver Verifier explores all detectable paths in the driver source code and executes them symbolically. The static analysis tools can help find bugs that are not detected by using other conventional methods to test drivers.
Up to now, the DriverEntry routine for a WDM or KMDF driver would typically be declared in the following manner:
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
The DriverEntry routine now has an associated function role type called DRIVER_INITIALIZE. The routine can be declared simply as:
DRIVER_INITIALIZE DriverEntry;
That’s it. There is no need to declare the function prototype with its list of the parameters, return values and parameter types. All that work is done by the DRIVER_INITIALIZE typedef, which is defined in Wdm.h.
typedef
NTSTATUS
DRIVER_INITIALIZE (
__in struct _DRIVER_OBJECT *DriverObject,
__in PUNICODE_STRING RegistryPath
);
Not only is it easy to declare the function by using the function role type, but by using this declaration, you also gain the benefit of the annotations that have been added to the typedef. In this case, you might notice that the DRIVER_INITIALIZE correctly uses the __in parameter annotation, which means that PREfast for Drivers will check to make sure that the parameters are initialized before the function is called. As discussed in the blog post “Resources to help you annotate code for static analysis ” these driver annotations help improve the accuracy of the results produced by the static analysis tools. If you look at the older style declaration for the DriverEntry function (shown in the first example), the prototype uses the symbolic, but nevertheless meaningless, IN annotation. That is, the IN annotation is ignored by the compiler and by PREfast. That annotation might be helpful to someone reading the code, but that’s about it. Using the DRIVER_INITIALIZE role type in the function declaration has some tangible benefits, but the annotations aren’t particularly complex or compelling. To see the power of using these function role type declarations, take a look at a KMDF example. You declare a driver's EvtIoWrite event callback function by using the function role type EVT_WDF_IO_QUEUE_IO_WRITE. This function role type is declared in a typedef in Wdfio.h.
typedef
__drv_maxIRQL(DISPATCH_LEVEL)
VOID
(EVT_WDF_IO_QUEUE_IO_WRITE) (
__in
WDFQUEUE Queue,
__in
WDFREQUEST Request,
__in
size_t Length
);
Now it gets more interesting. In addition to the annotations that direct PREfast for Drivers to validate the input parameters (__in), the EVT_WDF_IO_QUEUE_IO_WRITE function role type uses the driver-specific annotation for IRQL checking. The annotation __drv_maxIRQL(DISPATCH_LEVEL) specifies that the callback must be called only when IRQL <= DISPATCH_LEVEL. This means that PREfast will issue a warning if this function is ever called when the IRQL is greater than DISPATCH_LEVEL. However, this is just the beginning. The __drv_maxIRQL(DISPATCH_LEVEL) annotation just covers the base case, the maximum IRQL at which the callback can execute. In a KMDF driver, the same callback function might execute at different IRQLs at different times. A KMDF driver can configure the ExecutionLevel member of the device or driver's WDF_OBJECT_ATTRIBUTES structure. For example, the EvtIoWrite event callback could be called at PASSIVE_LEVEL one time, and then called at DISPATCH_LEVEL a subsequent time. Unfortunately, it is not easy to capture this complexity in an annotation. The good news is that Static Driver Verifier can model the framework object’s IRQL constraints and behavior and can verify a driver against a set of usage rules for that function role type. The really cool part about all of this is that you only have to declare EvtIoWrite by using the function role type. You not only benefit from the annotations that have been added to the function typedef declaration, you also benefit from any future improvements and refinements to the annotations and in the construction of the usage rules. Simply declare EvtIoWrite as follows:
EVT_WDF_IO_QUEUE_IO_WRITE EvtIoWrite;
To learn more about how you should declare your WDM and KMDF driver-supplied functions, use the function reference documentation in the WDK. To see some examples of function role type declarations, take a look at the KMDF and WDM driver samples and header files in the WDKroot\version\src\ directory of the WDK. For information about how to obtain the latest WDK, see How to Get the Windows Driver Kit (WDK) and the Windows Logo Kit (WLK).
Call to action!
· Declare your driver-supplied functions by using the function role types. The function role type declarations replace traditional declarations for these functions.
· Use the static analysis tools early in your driver development cycle to catch and fix problems before you ship your driver.
Resources
· Using Function Role Type Declarations
· Declaring Functions Using Function Role Types for KMDF Drivers
· Static Driver Verifier KMDF Annotations
· Declaring Functions Using Function Role Types for WDM Drivers
Dave Hagen [MSFT], WDK Technical Writer
http://blogs.msdn.com/wdkdocs
This posting is provided "AS IS" with no warranties, and confers no rights.