KMDF驱动程序结构
KMDF驱动程序包含DriverEntry函数(根据KMDF标识驱动程序)、 KMF调用的一系列回调函数(以便驱动程序能够对影响其设备的事件做出响应),以及驱动程序特有的其他实用函数。
几乎每种KMDF驱动程序均必须具备下列函数。
- DriverEntry函数,表示驱动程序的主要入口点。
- EvtDriverDeviceAdd回调函数,在即插即用管理器枚举某个驱动程序的设备时调用(不适用于支持非即插即用设备的驱动程序)。
一个或多个EvtIo*回调函数,处理特定队列中具体类型的I/O请求。
驱动程序通常会创建一个或多个队列,KMDF会将驱动程序设备的IO请求放入该队列。驱动程序可以按照请求类型和调度类型配置队列。
简单设备的最小内核模式驱动程序可能只具有这些函数。KMDF包含支持默认电源管理和即插即用操作的代码,因此不操纵物理硬件的驱动程序可以省略大部分即插即用和电源管理代码。如果驱动程序可以使用默认设置,则不需要执行许多常见任务的代码,如将一个电源IRP沿设备栈向下传递。设备支持的设备特有功能越多,驱动程序提供的功能越多,同时驱动程序需要的代码也越多。
WDF_DRIVER_CONFIG
WDF应用于驱动级的回调函数结构体为WDF_DRIVER_CONFIG。其结构定义如下:
typedef struct _WDF_DRIVER_CONFIG {
//
// Size of this structure in bytes
//
ULONG Size;
//
// Event callbacks
//
PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd;
PFN_WDF_DRIVER_UNLOAD EvtDriverUnload;
//
// Combination of WDF_DRIVER_INIT_FLAGS values
//
ULONG DriverInitFlags;
//
// Pool tag to use for all allocations made by the framework on behalf of
// the client driver.
//
ULONG DriverPoolTag;
} WDF_DRIVER_CONFIG, *PWDF_DRIVER_CONFIG;
其中最重要的就是EvtDriverDeviceAdd和EvtDriverUnload函数。
- EvtDriverDeviceAdd 适用于DRIVER_ENTRY的AddDevice回调函数,用于FDO设备的创建回调。
- EvtDriverUnload适用于驱动卸载的回调。
WDF_DRIVER_CONFIG使用WDF_DRIVER_CONFIG_INIT函数初始化。
VOID
FORCEINLINE
WDF_DRIVER_CONFIG_INIT(
_Out_ PWDF_DRIVER_CONFIG Config,
_In_opt_ PFN_WDF_DRIVER_DEVICE_ADD EvtDriverDeviceAdd
)
{
RtlZeroMemory(Config, sizeof(WDF_DRIVER_CONFIG));
Config->Size = sizeof(WDF_DRIVER_CONFIG);
Config->EvtDriverDeviceAdd = EvtDriverDeviceAdd;
}
即这里只初始化EvtDriverDeviceAdd函数。
WDF_OBJECT_ATTRIBUTES
从WDF_DRIVER_CONFIG的初始化函数WDF_DRIVER_CONFIG_INIT可以看到,WDF驱动的EvtDriverUnload未使用,那么其卸载驱动时的资源清除使用什么函数来回调执行了。答案是WDF_OBJECT_ATTRIBUTES结构体的EvtCleanupCallback。
WDF_OBJECT_ATTRIBUTES的结构体定义如下:
typedef struct _WDF_OBJECT_ATTRIBUTES {
//
// Size in bytes of this structure
//
ULONG Size;
//
// Function to call when the object is deleted
//
PFN_WDF_OBJECT_CONTEXT_CLEANUP EvtCleanupCallback;
//
// Function to call when the objects memory is destroyed when the
// the last reference count goes to zero
//
PFN_WDF_OBJECT_CONTEXT_DESTROY EvtDestroyCallback;
//
// Execution level constraints for Object
//
WDF_EXECUTION_LEVEL ExecutionLevel;
//
// Synchronization level constraint for Object
//
WDF_SYNCHRONIZATION_SCOPE SynchronizationScope;
//
// Optional Parent Object
//
WDFOBJECT ParentObject;
//
// Overrides the size of the context allocated as specified by
// ContextTypeInfo->ContextSize
//
size_t ContextSizeOverride;
//
// Pointer to the type information to be associated with the object
//
PCWDF_OBJECT_CONTEXT_TYPE_INFO ContextTypeInfo;
} WDF_OBJECT_ATTRIBUTES, *PWDF_OBJECT_ATTRIBUTES;
其结构体的初始化函数为WDF_OBJECT_ATTRIBUTES_INIT
VOID
FORCEINLINE
WDF_OBJECT_ATTRIBUTES_INIT(
_Out_ PWDF_OBJECT_ATTRIBUTES Attributes
)
{
RtlZeroMemory(Attributes, sizeof(WDF_OBJECT_ATTRIBUTES));
Attributes->Size = sizeof(WDF_OBJECT_ATTRIBUTES);
Attributes->ExecutionLevel = WdfExecutionLevelInheritFromParent;
Attributes->SynchronizationScope = WdfSynchronizationScopeInheritFromParent;
}
可见,这里只是对结构体初始化,不像WDF_DRIVER_CONFIG_INIT有成员函数的初始化,故EvtCleanupCallback需要手动的初始化。故一般代码如下:
WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
attributes.EvtCleanupCallback = PlxEvtDriverContextCleanup;
WdfDriverCreate
当WDF_DRIVER_CONFIG和WDF_OBJECT_ATTRIBUTES的结构体初始化完成时,就可以调用WdfDriverCreate函数来实现WDF驱动的创建。
status = WdfDriverCreate( DriverObject,
RegistryPath,
&attributes,
&config,
WDF_NO_HANDLE);