各位同学,大家好!很高兴再次和大家相聚在课堂上。在上一次的课程中,我们已经成功完成了驱动开发环境的配置,并初步创建了一个空的驱动程序项目框架。今天,我们将进一步探索驱动程序的核心内容,即其基本构成和编程范式。
第二课:驱动程序的基础架构与编程范式
1. 驱动程序的分类体系
在 Windows 操作系统的生态中,驱动程序主要根据其运行环境和权限划分为两大类别:
- 内核模式驱动程序 (Kernel-Mode Driver): 这类驱动程序在操作系统的核心空间中执行,享有最高级别的系统权限,能够直接与硬件设备进行交互。常见的内核模式驱动程序类型包括:
- WDM (Windows Driver Model) 驱动程序: 作为最基础的驱动模型,WDM 直接与硬件层进行对接,提供最原始的设备操作能力。
- KMDF (Kernel-Mode Driver Framework) 驱动程序: 基于WDM模型发展而来,采用面向对象的框架设计,显著简化了驱动开发流程,同时提升了代码的可维护性和系统稳定性。
- NDIS (Network Driver Interface Specification) 驱动程序: 专为网络设备设计的驱动程序规范。
- 文件系统驱动程序: 负责管理文件系统的底层驱动程序。
- 用户模式驱动程序 (User-Mode Driver): 这类驱动程序在用户空间运行,权限相对受限,无法直接访问硬件资源,必须借助内核模式驱动程序作为中介来操作硬件。常见的用户模式驱动程序类型主要有:
- UMDF (User-Mode Driver Framework) 驱动程序: 基于UMDF框架构建的用户模式驱动程序,通常用于开发功能相对简单的设备驱动,如打印机、扫描仪等外设驱动。
鉴于我们本次课程专注于内核驱动开发领域,因此我们将重点讲解内核模式驱动程序,特别是KMDF驱动程序的相关内容。
2. KMDF 驱动程序的核心架构
一个典型的KMDF驱动程序通常包含以下几个关键组成部分:
- DriverEntry 函数: 驱动程序的启动函数,相当于应用程序的主函数。当驱动程序被系统加载时,系统会自动调用DriverEntry函数。该函数的主要职责包括初始化驱动程序对象、设备对象以及其他必要的系统资源。
- EvtDriverDeviceAdd 函数: 当系统检测到新设备接入时,会触发EvtDriverDeviceAdd函数的执行。该函数负责创建设备上下文、配置设备参数、建立I/O请求队列等关键任务。
- EvtIoXXX 回调函数: 用于处理各类I/O请求,包括读操作、写操作、IOCTL指令等。这些回调函数由驱动程序预先注册,一旦系统接收相应的I/O请求,就会自动调用对应的处理函数。
- 其他辅助函数: 用于实现特定功能的辅助性函数,例如中断处理函数、定时器回调函数等。
3. KMDF 编程范式
KMDF提供了一套完整的面向对象编程模型,其核心对象体系包括:
- WDFDRIVER (Driver Object): 代表整个驱动程序,是驱动程序的根节点对象。
- WDFDEVICE (Device Object): 代表一个具体的设备,每个设备都会对应一个设备对象实例。
- WDFQUEUE (Queue Object): 代表I/O请求队列,负责管理和调度各类I/O请求。
- WDFREQUEST (Request Object): 代表单个I/O请求。
- WDFMEMORY (Memory Object): 代表系统内存资源。
- WDFINTERRUPT (Interrupt Object): 代表硬件中断。
- WDFTIMER (Timer Object): 代表系统定时器。
KMDF编程的核心思想在于:通过操作这些对象之间的交互关系,实现对硬件设备的控制和管理工作。
4. KMDF 驱动程序的简易示例
接下来,我们将通过一个简单的KMDF驱动程序示例,了解其基本实现方式。该示例驱动程序将实现最基础的加载和卸载功能。
content_copy 使用代码时请谨慎操作.C++
代码解析:
- #include <ntddk.h>: 引入Windows内核编程所需的标准头文件。
- #include <wdf.h>: 引入KMDF框架的相关头文件。
- DriverEntry: 驱动程序的初始化函数,在驱动加载时由系统自动调用。
- WDF_DRIVER_CONFIG_INIT: 初始化驱动程序配置结构体。
- config.DriverInitFlags |= WdfDriverInitNonPnpDriver;: 将驱动程序类型设置为非即插即用模式,表明该驱动不与特定硬件设备绑定。
- WdfDriverCreate: 创建驱动程序对象实例。
- DbgPrintEx: 内核态下的调试输出函数,类似于用户态的printf,用于开发过程中的信息记录。
- EvtDriverUnload: 驱动程序的卸载函数,在驱动被移除时触发。
编译与测试流程:
- 将示例代码复制到先前创建的驱动程序项目工程中。
- 在Visual Studio集成开发环境中执行项目构建操作。
- 将生成的.sys驱动文件部署到目标测试环境(物理机或虚拟机)的指定目录。
- 使用专业的驱动加载工具进行测试验证。
课程总结
在本节课中,我们系统学习了驱动程序的分类体系、KMDF驱动程序的基本架构和编程范式,并完成了简易驱动程序的编写。希望同学们能够深入理解这些核心概念,并积极尝试编译和测试示例代码,为后续的驱动开发打下坚实基础。