1.1 WDM驱动模型概述

WDM(Windows Driver Model)是微软为 Windows 2000 及后续操作系统引入的驱动程序框架,旨在统一设备驱动开发模型,支持即插即用(PnP)和电源管理。WDM 驱动运行于内核态,通过分层结构处理 I/O 请求,是 Windows 驱动开发的核心基础。

1.1.1 WDM体系结构

WDM 体系结构建立在操作系统内核与硬件设备之间,采用对象化和分层化设计。驱动不直接操作硬件,而是通过 I/O 管理器(I/O Manager)与设备对象交互。整个体系分为三个关键层次:

  • 总线驱动(Bus Driver):负责枚举总线上的设备,检测设备插拔,管理总线电源。例如 PCI、USB 总线驱动。
  • 功能驱动(Function Driver):实现设备的主要功能,处理设备的读写、控制请求。通常由设备厂商提供。
  • 过滤驱动(Filter Driver):可选层,位于功能驱动之上或之下,用于拦截、修改或扩展 I/O 请求,如加密过滤、日志过滤。
关键概念:WDM 驱动不直接绑定硬件,而是绑定到设备对象(Device Object)。每个设备对象代表一个逻辑或物理设备实例,驱动通过设备对象接收 IRP(I/O Request Packet)。
WDM体系结构分层示意图 WDM 体系结构分层 用户模式 (User Mode) — 应用程序 / Win32 API 内核模式 (Kernel Mode) I/O 管理器 (I/O Manager) 上层过滤驱动 (Upper Filter Driver) 功能驱动 (Function Driver) 下层过滤驱动 (Lower Filter Driver) 总线驱动 (Bus Driver)

1.1.2 层次模型与IRP传递

WDM 的层次模型决定了 I/O 请求的传递路径。当应用程序发起 I/O 操作时,I/O 管理器创建 IRP,并依次传递给设备栈中的各层驱动。每一层驱动可以选择处理 IRP,或将其传递到下一层。

层次 典型职责 示例
上层过滤驱动 数据加密、日志记录、访问控制 磁盘加密过滤驱动
功能驱动 设备核心功能实现,处理读写、控制 键盘类驱动、鼠标类驱动
下层过滤驱动 硬件错误修正、特殊协议转换 USB 协议过滤驱动
总线驱动 设备枚举、资源分配、电源管理 PCI 总线驱动、USB 主控制器驱动
开发提示:功能驱动是 WDM 开发中最常见的类型。大多数设备厂商只需编写功能驱动,过滤驱动通常用于系统级扩展或安全产品。
IRP在设备栈中的传递流程 IRP 在设备栈中的传递流程 应用程序 I/O 管理器 设备栈 (Device Stack) 上层过滤驱动设备对象 功能驱动设备对象 总线驱动设备对象

1.1.3 驱动对象与设备对象

WDM 驱动开发的核心是理解两个关键内核对象:驱动对象(DRIVER_OBJECT)和设备对象(DEVICE_OBJECT)。驱动对象代表一个已加载的驱动程序,设备对象代表一个逻辑设备实例。

驱动对象(DRIVER_OBJECT)

驱动对象由 I/O 管理器在驱动加载时创建,包含驱动入口点、派遣函数指针、设备对象链表等关键信息。驱动开发者通过 DriverEntry 函数初始化驱动对象。

// 驱动对象关键字段(简化)
typedef struct _DRIVER_OBJECT {
    PDEVICE_OBJECT   DeviceObject;       // 设备对象链表头
    PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION]; // 派遣函数表
    PDRIVER_UNLOAD    DriverUnload;      // 卸载函数
    PDRIVER_STARTIO   DriverStartIo;     // 启动I/O函数
    // ... 其他字段
} DRIVER_OBJECT, *PDRIVER_OBJECT;

设备对象(DEVICE_OBJECT)

设备对象由驱动调用 IoCreateDevice 创建,代表一个设备实例。设备对象包含设备类型、标志、当前 IRP 等信息,并链接到对应的驱动对象。

// 创建设备对象示例
NTSTATUS CreateDevice(PDRIVER_OBJECT DriverObject) {
    PDEVICE_OBJECT deviceObject = NULL;
    UNICODE_STRING deviceName;
    RtlInitUnicodeString(&deviceName, L"\\Device\\MyDevice");

    NTSTATUS status = IoCreateDevice(
        DriverObject,           // 驱动对象
        sizeof(DEVICE_EXTENSION), // 设备扩展大小
        &deviceName,            // 设备名称
        FILE_DEVICE_UNKNOWN,    // 设备类型
        0,                      // 设备特征
        FALSE,                  // 是否独占
        &deviceObject           // 返回设备对象
    );
    return status;
}
常见错误:忘记在 DriverEntry 中设置 DriverUnload 和 MajorFunction 派遣函数,会导致驱动卸载时资源泄漏或 IRP 无法被处理。
驱动对象与设备对象关系 驱动对象与设备对象关系 DRIVER_OBJECT DriverEntry: MyDriverEntry DriverUnload: MyUnload MajorFunction[0] : Create MajorFunction[2] : Read MajorFunction[3] : Write MajorFunction[14]: DeviceControl DeviceObject: ——————→ DEVICE_OBJECT Type: FILE_DEVICE_UNKNOWN Flags: DO_BUFFERED_IO CurrentIrp: NULL DriverObject: ——————→ DeviceExtension: 0xFFFF... NextDevice: NULL AttachedDevice: NULL

1.1.4 设备扩展与上下文

WDM 驱动通常需要为每个设备对象维护私有数据,如硬件资源、状态标志、自旋锁等。这些数据存储在设备扩展(Device Extension)中。设备扩展是驱动开发者自定义的结构体,在调用 IoCreateDevice 时分配。

// 设备扩展结构体示例
typedef struct _DEVICE_EXTENSION {
    PDEVICE_OBJECT  Self;               // 指向自身设备对象
    PDEVICE_OBJECT  LowerDeviceObject;  // 下层设备对象(用于传递IRP)
    PDEVICE_OBJECT  PhysicalDeviceObject; // 物理设备对象
    ULONG           DeviceState;        // 设备状态
    KSPIN_LOCK      SpinLock;           // 自旋锁
    LIST_ENTRY      IrpQueue;           // IRP队列
    // ... 其他自定义字段
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
最佳实践:设备扩展是驱动中访问最频繁的数据结构。建议在设备扩展中保存下层设备对象指针(LowerDeviceObject),以便在派遣函数中快速传递 IRP。

1.1.5 本章小结

WDM 驱动模型的核心在于分层协作:总线驱动发现设备,功能驱动实现功能,过滤驱动扩展行为。驱动对象是驱动的“入口表”,设备对象是设备的“实例句柄”,两者通过设备扩展紧密关联。理解这些基础概念,是后续学习中断处理与派遣函数参数配置的前提。