3. KMDF 驱动入口与初始化:DriverEntry、WDF_DRIVER_CONFIG 与 EvtDriverDeviceAdd

KMDF 驱动的初始化流程是驱动加载与设备管理的起点。本章深入剖析 DriverEntry 函数的职责、WDF_DRIVER_CONFIG 结构的配置方法、EvtDriverDeviceAdd 回调的触发时机,以及完整的设备初始化流程。理解这些核心机制,是后续中断处理与 DMA 性能调优的基础。

核心要点: KMDF 驱动初始化遵循“驱动对象创建 → 配置结构填充 → 设备添加回调 → 设备对象初始化”的固定流水线。任何环节的配置错误都会导致驱动加载失败或设备无法识别。

3.1 DriverEntry 函数:驱动的入口点

DriverEntry 是 KMDF 驱动的第一个执行函数,由操作系统在驱动加载时调用。它的主要职责是创建一个 WDF 驱动对象,并注册必要的回调函数。

函数原型与参数

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT  DriverObject,
    _In_ PUNICODE_STRING RegistryPath
);
参数 类型 说明
DriverObject PDRIVER_OBJECT WDM 驱动对象指针,KMDF 框架会将其与 WDF 驱动对象关联
RegistryPath PUNICODE_STRING 驱动在注册表中的服务路径,用于读取配置信息

标准实现步骤

  1. 调用 WdfDriverCreate:创建 WDF 驱动对象,传入 WDF_DRIVER_CONFIG 结构。
  2. 检查返回值:确保 WdfDriverCreate 返回 STATUS_SUCCESS。
  3. 可选:读取注册表:通过 RegistryPath 获取驱动自定义配置。
  4. 返回状态:成功返回 STATUS_SUCCESS,失败返回相应错误码。
最佳实践: DriverEntry 应保持轻量,仅完成框架初始化。复杂的硬件初始化应推迟到 EvtDriverDeviceAdd 回调中执行。
DriverEntry 执行流程 系统调用 DriverEntry 填充 WDF_DRIVER_CONFIG 调用 WdfDriverCreate 返回 STATUS_SUCCESS

3.2 WDF_DRIVER_CONFIG 结构:驱动的配置蓝图

WDF_DRIVER_CONFIG 结构是 KMDF 驱动初始化的核心配置载体,它定义了驱动的基本属性和回调函数入口。

结构定义与关键字段

typedef struct _WDF_DRIVER_CONFIG {
    ULONG   Size;                              // 结构大小,必须初始化为 sizeof(WDF_DRIVER_CONFIG)
    PFN_WDF_DRIVER_DEVICE_ADD  EvtDriverDeviceAdd;  // 设备添加回调(必需)
    PFN_WDF_DRIVER_UNLOAD     EvtDriverUnload;      // 驱动卸载回调(可选)
    ULONG   DriverInitFlags;                   // 驱动初始化标志
    ULONG   DriverPoolTag;                     // 驱动内存池标签
} WDF_DRIVER_CONFIG, *PWDF_DRIVER_CONFIG;
字段 必需/可选 说明
Size 必需 必须设置为 sizeof(WDF_DRIVER_CONFIG),用于版本兼容性检查
EvtDriverDeviceAdd 必需 当 PnP 管理器检测到设备时调用的回调函数
EvtDriverUnload 可选 驱动卸载时的清理回调,释放全局资源
DriverInitFlags 可选 控制驱动行为,如 WDF_DRIVER_INIT_FLAG_NO_DISPATCH
DriverPoolTag 可选 用于调试的内存池标签,建议使用 4 字符标识

初始化宏

KMDF 提供了便捷的初始化宏 WDF_DRIVER_CONFIG_INIT,自动填充 Size 字段并设置 EvtDriverDeviceAdd:

WDF_DRIVER_CONFIG config;
WDF_DRIVER_CONFIG_INIT(&config, MyEvtDriverDeviceAdd);
// 可选:设置卸载回调
config.EvtDriverUnload = MyEvtDriverUnload;
config.DriverPoolTag = 'DMA1';
常见错误: 忘记调用 WDF_DRIVER_CONFIG_INIT 或手动设置 Size 字段,会导致 WdfDriverCreate 返回 STATUS_INVALID_PARAMETER。始终使用初始化宏。

3.3 EvtDriverDeviceAdd 回调:设备发现的响应者

EvtDriverDeviceAdd 是 KMDF 驱动中最重要的回调函数之一。当 PnP 管理器枚举到驱动支持的设备时,框架会调用此回调,驱动在此函数中完成设备对象的创建和初始化。

函数原型

NTSTATUS
MyEvtDriverDeviceAdd(
    _In_    WDFDRIVER       Driver,
    _Inout_ PWDFDEVICE_INIT DeviceInit
);
参数 说明
Driver 由 WdfDriverCreate 创建的 WDF 驱动对象句柄
DeviceInit 指向 WDFDEVICE_INIT 结构的指针,用于配置设备属性

标准实现步骤

  1. 配置设备属性:通过 WdfDeviceInitAssignName、WdfDeviceInitSetDeviceType 等函数设置设备名称、类型、特性。
  2. 创建设备对象:调用 WdfDeviceCreate,传入 DeviceInit 和 WDF_OBJECT_ATTRIBUTES。
  3. 创建 I/O 队列:为设备创建默认或自定义的 I/O 队列,注册请求处理回调。
  4. 初始化中断与 DMA:配置中断对象和 DMA 适配器(后续章节详述)。
  5. 返回状态:成功返回 STATUS_SUCCESS。
性能提示: EvtDriverDeviceAdd 在 PASSIVE_LEVEL 执行,适合进行内存分配和初始化。避免在此函数中执行耗时操作,以免阻塞 PnP 枚举过程。
EvtDriverDeviceAdd 回调流程 PnP 枚举到设备 框架调用 EvtDriverDeviceAdd 配置设备属性 调用 WdfDeviceCreate 创建 I/O 队列 初始化中断/DMA 返回 STATUS_SUCCESS

3.4 设备初始化流程:从 DriverEntry 到设备就绪

KMDF 设备的完整初始化流程跨越多个阶段,从驱动加载到设备可被应用程序访问。以下表格总结了关键阶段及其执行顺序:

阶段 执行函数/回调 IRQL 主要操作
1. 驱动加载 DriverEntry PASSIVE_LEVEL 创建 WDF 驱动对象,注册回调
2. 设备枚举 PnP 管理器 PASSIVE_LEVEL 检测设备,调用 EvtDriverDeviceAdd
3. 设备创建 EvtDriverDeviceAdd PASSIVE_LEVEL 配置属性,创建 WDF 设备对象
4. 设备初始化 EvtDevicePrepareHardware PASSIVE_LEVEL 分配硬件资源,映射内存空间
5. 中断初始化 EvtDeviceD0Entry DIRQL 连接中断,启用 DMA 引擎
6. 设备就绪 — PASSIVE_LEVEL 设备可接收 I/O 请求
调试建议: 在 DriverEntry 和 EvtDriverDeviceAdd 入口处添加 DbgPrint 或 TraceEvents,便于跟踪初始化流程。使用 WinDbg 的 !wdfdriverinfo 命令可查看驱动对象状态。

3.5 完整代码示例:最小 KMDF 驱动初始化

以下代码展示了一个完整的 KMDF 驱动入口与设备初始化实现,包含错误处理和资源清理:

#include <ntddk.h>
#include <wdf.h>

DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD MyEvtDriverDeviceAdd;

NTSTATUS
DriverEntry(
    _In_ PDRIVER_OBJECT  DriverObject,
    _In_ PUNICODE_STRING RegistryPath
)
{
    NTSTATUS status;
    WDF_DRIVER_CONFIG config;

    // 1. 初始化配置结构
    WDF_DRIVER_CONFIG_INIT(&config, MyEvtDriverDeviceAdd);
    config.DriverPoolTag = 'DMA1';

    // 2. 创建 WDF 驱动对象
    status = WdfDriverCreate(
        DriverObject,
        RegistryPath,
        WDF_NO_OBJECT_ATTRIBUTES,
        &config,
        WDF_NO_HANDLE
    );

    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfDriverCreate failed: 0x%X\n", status);
        return status;
    }

    DbgPrint("KMDF Driver loaded successfully\n");
    return STATUS_SUCCESS;
}

NTSTATUS
MyEvtDriverDeviceAdd(
    _In_    WDFDRIVER       Driver,
    _Inout_ PWDFDEVICE_INIT DeviceInit
)
{
    NTSTATUS status;
    WDFDEVICE device;
    WDF_OBJECT_ATTRIBUTES attributes;
    WDF_IO_QUEUE_CONFIG queueConfig;

    UNREFERENCED_PARAMETER(Driver);

    // 1. 设置设备属性
    WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_UNKNOWN);

    // 2. 创建设备对象
    WDF_OBJECT_ATTRIBUTES_INIT(&attributes);
    status = WdfDeviceCreate(&DeviceInit, &attributes, &device);
    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfDeviceCreate failed: 0x%X\n", status);
        return status;
    }

    // 3. 创建默认 I/O 队列
    WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&queueConfig, WdfIoQueueDispatchSequential);
    status = WdfIoQueueCreate(device, &queueConfig, WDF_NO_OBJECT_ATTRIBUTES, WDF_NO_HANDLE);
    if (!NT_SUCCESS(status)) {
        DbgPrint("WdfIoQueueCreate failed: 0x%X\n", status);
        return status;
    }

    DbgPrint("Device created successfully\n");
    return STATUS_SUCCESS;
}
关键检查点:
  • 确保 WDF_DRIVER_CONFIG_INIT 在 WdfDriverCreate 之前调用。
  • EvtDriverDeviceAdd 中必须调用 WdfDeviceCreate,否则设备无法被系统识别。
  • 所有资源分配失败时,必须返回错误码,框架会自动清理已分配的资源。

3.6 初始化性能优化要点

驱动初始化阶段的性能直接影响系统启动速度和设备枚举效率。以下是针对 KMDF 初始化的优化建议:

  • 延迟初始化:将非关键的硬件初始化推迟到 EvtDevicePrepareHardware 或 EvtDeviceD0Entry 中执行,减少 DriverEntry 和 EvtDriverDeviceAdd 的耗时。
  • 内存预分配:在 EvtDriverDeviceAdd 中预分配设备上下文所需的内存,避免运行时动态分配带来的性能抖动。
  • 避免阻塞调用:初始化期间不要等待用户模式组件或长时间 I/O 操作,使用工作项(WorkItem)异步处理。
  • 使用对象属性:通过 WDF_OBJECT_ATTRIBUTES 设置上下文大小和清理回调,减少手动内存管理开销。
性能指标参考: 在典型硬件上,DriverEntry 应控制在 1ms 以内,EvtDriverDeviceAdd 应控制在 10ms 以内。超过这些阈值可能影响系统启动体验。
初始化性能优化决策树 初始化操作分类 关键路径操作 非关键路径操作 阻塞/耗时操作 在 EvtDriverDeviceAdd 执行 延迟到 EvtDeviceD0Entry 使用工作项异步处理 目标:DriverEntry < 1ms,EvtDriverDeviceAdd < 10ms 超过阈值需使用延迟初始化或异步策略