Windows 驱动开发

52
Windows 驱驱驱驱 驱驱驱驱驱驱 驱驱 2005.10.18

description

Windows 驱动开发. 新产品开发部 郑然 2005.10.18. 讲解内容. Windows XP 系统简介 Windows Driver Model 工作机制 处理 IRP 的标准模型 WDM 中的 HelloWorld 程序 Windows XP 的 IO 流程 用户程序和驱动程序的交互 ——IOCTL 内核调试器 SoftIce. Windows XP 简介. Windows XP 的特性. 支持对称多处理器 基于对象 支持抢占式多任务 异步 IO. Windows XP 的系统结构图. Windows XP 的系统组件. - PowerPoint PPT Presentation

Transcript of Windows 驱动开发

Page 1: Windows 驱动开发

Windows 驱动开发

新产品开发部 郑然2005.10.18

Page 2: Windows 驱动开发

讲解内容

  Windows XP 系统简介  Windows Driver Model 工作机制 处理 IRP 的标准模型 WDM 中的 HelloWorld 程序  Windows XP 的 IO 流程 用户程序和驱动程序的交互—— IOCTL 内核调试器 SoftIce

Page 3: Windows 驱动开发

Windows XP 简介

Page 4: Windows 驱动开发

4

Windows XP 的特性

支持对称多处理器 基于对象 支持抢占式多任务 异步 IO

Page 5: Windows 驱动开发

5

内核模式

用户模式

Win32

子系统

安全

子系统

POSIX

子系统

硬件抽象层(HAL)

硬件

文件系统,

中间驱动程序

设备驱动程序

I/O管理器 对象管理器

配置管理器 进程管理器

安全监视器

系统服务接口

内核

虚拟内存

管理器 本地过程

保护子系统

PNP管理器

电源管理器

执行体支持

Windows XP 的系统结构图

Page 6: Windows 驱动开发

6

Windows XP 的系统组件

硬件抽象层( HAL ):硬件抽象层隐藏各种与硬件相关的细节,例如 IO 接口、中断控制器以及多处理器通信机制等硬件信息, HAL 为不同的硬件提供了统一的接口。

内核:内核是整个操作系统的神经中枢,内核的目标之一是提供一个严格定义的,可预测的操作系统基本要素和机制的低级操作。

执行体:图中的暗纹部分都属于执行体,但它们是完全独立的,只通过很好定义的接口来通讯 。

Page 7: Windows 驱动开发

7

Windows XP 驱动程序分类 (1/2)

Windows XP 中存在很多种驱动程序,如图

Page 8: Windows 驱动开发

8

Windows XP 驱动程序分类 (2/2)

虚拟设备驱动程序( VDD ): VDD 是一种用户态组件,用于基于 MS-DOS 的应用程序访问Inter X86 体系结构的硬件。

文件系统驱动程序:实现 Windows XP 中的文件系统。

遗留设备驱动程序:是一种不需要其他驱动程序帮助的直接访问控制硬件的驱动程序,其中大部分是原来 windows NT 中的驱动程序,不加修改的放在 Windows XP 中。

PnP 驱动程序是一种遵循即插即用协议的驱动程序。 WDM 驱动程序属于 PnP 驱动程序,同时它还支持电源管理协议。

Page 9: Windows 驱动开发

9

WDM 驱动程序

类驱动程序:为一类设备开发的驱动程序,负责完成设备所作的工作。

迷你驱动程序:如果你的设备在 windows 中存在类驱动程序,那么就需要一个迷你驱动程序。迷你驱动程序负责控制设备,和类驱动程序协同工作。

单功能 WDM 驱动程序:这种驱动程序控制设备所有的细节,不需要和其他设备驱动程序交互。

WDM 过滤驱动程序:通常这种驱动程序截获 IO 的请求来修改某个驱动程序的行为。

Page 10: Windows 驱动开发

Windows Driver Model 的工作机制

Page 11: Windows 驱动开发

11

WDM 驱动程序的工作机制 (1/4)

你可以把 WDM 驱动程序想象成一个例程的容器,操作系统会在适当的时机调用你的驱动程序的例程完成你的驱动程序想要完成的工作。作为一个 WDM 驱动程序的开发者,你的一项工作就是确定在这个容器中,放入多少例程。

和用户态应用程序类似,驱动程序也是一种可执行文件,文件扩展名为 .sys 。 WDM 驱动程序也有一个程序的入口, DriverEntry 例程,类似于 main ()函数。和应用程序不同的是,驱动程序工作在系统进程的进程地址空间中,它只是提供一些例程供系统调用,而应用程序拥有自主权。

Page 12: Windows 驱动开发

12

WDM 驱动程序的工作机制 (2/4)

DriverEntry

初始化驱动及其驱动对象 AddDevice

初始化设备并创建设备对象 Dispatch Routines

接收和处理 IRPs

Unload

释放驱动获得的系统资源

Page 13: Windows 驱动开发

13

WDM 驱动程序的工作机制 (3/4)

下面简单解释一下系统可能调用哪些例程1. 用户将设备插入插槽中,系统将你的 .sys 文件映射到

系统进程的地址空间,调用你的驱动程序的 DriverEntry 例程

2. PnP 管理器调用 AddDevice 例程,创建设备对象3. 应用程序打开设备的句柄,系统发送一些请求给你的

派遣例程4. 应用程序试图向设备进行 IO , IO 管理器向你的派遣

例程发送读写请求5. 用户拔掉设备,系统调用 DriverUnload 例程

Page 14: Windows 驱动开发

14

WDM 驱动程序的工作机制 (4/4)

和应用程序另一个不同的地方是驱动程序运行在任意线程上下文中,系统并不会为你的驱动程序代码产生一个单独的线程,系统会在需要的时候调用你的驱动程序例程,此时你不能确定是哪一个线程在调用你的例程。

Page 15: Windows 驱动开发

15

分层驱动程序模型 (1/4)

对于 WDM 驱动程序,每个设备至少有两个驱动程序,一个称为功能驱动程序,另一个称为总线驱动程序。功能驱动程序了解设备的所有细节,负责处理 IO 和中断;总线驱动程序负责设备和计算机的连接,例如一个设备插入 PCI总线插槽中后, PCI总线驱动程序负责分配给设备所需的资源。通常情况下,一个设备存在多个驱动程序,这些驱动程序被组合成堆栈的结构,这个堆栈成为设备堆栈

Page 16: Windows 驱动开发

16

分层驱动程序模型 (2/4)

Page 17: Windows 驱动开发

17

分层驱动程序模型 (3/4)

PDO :物理设备对象,代表设备与总线的连接 FDO :功能设备对象,功能驱动程序利用 FDO

完成设备的功能 FiDO :过滤设备对象,代表过滤设备

Page 18: Windows 驱动开发

18

分层驱动程序模型 (4/4)

IRP : IO 请求包( IO Request Packet ), IO 管理器将所有与 IO 相关的上层用户 IO 请求封装成 IRP 这一个特殊的数据结构里, WDM驱动程序是包驱动的,通常 IO 管理器将 IRP 发送给设备堆栈上栈顶的驱动程序,然后每层驱动程序将 IRP逐个向下传递。

Page 19: Windows 驱动开发

19

DriverEntry 例程

DriverEntry 例程是驱动程序的入口地址,系统在加载你的驱动程序的时候调用 DriverEntry例程, DriverEntry 例程主要是做一些初始化工作,填充驱动程序对象结构体的相关域,主要是各个例程的地址,包括 DriverUnload 例程,AddDevice 例程, DriverStartIo 例程,各个派遣例程。

Page 20: Windows 驱动开发

20

AddDevice 例程 (1/2)

AddDevice 例程创建代表你的设备的设备对象结构体,并填充该结构体的相关域。其中在设备对象结构体中有一个可以保留用户数据的 DeviceExtension域,在 AddDevice 例程中通常开发人员将和设备相关的数据保留在这个结构中。创建好设备对象后 AddDevice 负责将设备对象关联到这个设备的设备堆栈上

Page 21: Windows 驱动开发

21

AddDevice 例程 (2/2)

Page 22: Windows 驱动开发

处理 IRP 的标准模型

Page 23: Windows 驱动开发

23

中断优先级

Page 24: Windows 驱动开发

24

中断优先级与线程优先级

绝大部分线程运行在 IRQL 0或者 IRQL 1上,所以不管线程的优先级是多少都不可以封锁硬件中断。线程调度是在 IRQL 2上做出的,所以内核决定下一个将要运行的线程时,不会有线程被执行。

CPU 只可以被高中断优先级的中断请求所中断也就是说运行在 IRQL 1上的线程可以中断运行在 IRQL 0上的线程,而不管线程的优先级是多少。

IRQL 的重要性主要体现于运行在 IRQL 2上的例程绝对不能产生页面错误,也就是说不能访问分页内存,因为系统无法进行调度。

Page 25: Windows 驱动开发

25

IRP 的数据结构 (1/3)

Page 26: Windows 驱动开发

26

IRP 的数据结构 (2/3)

MdlAddress 是内存描述符的地址, IO 方式有两种 DO_DIRECT_IO 和 DO_BUFFERD_IO ,当使用 DO_DIRECT_IO 时用这个域间接表示 IO 的数据在内存中的地址

AssociateIrp 是一个联合结构,当使用 DO_BUFFERD_IO 时,这个结构中包含进行 IO 时需要的参数

IoStatus表示这个 IRP被完成的情况 PendingReturned表示下层驱动程序是否返回

STATUS_PENDING

Page 27: Windows 驱动开发

27

IRP 的数据结构 (3/3)

Cancel表示这个 IRP 是否被取消了 CancelRoutinue表示当 IRP被取消时调用的取消例程的地址

Tail 是一个复杂的结构,里面有一些关于设备队列的结构

Page 28: Windows 驱动开发

28

IO堆栈的数据结构 (1/4)

当 IO 管理器或者驱动程序生成 IRP 的时候,还需要为这个 IRP 创建一个 IO堆栈数组。通常这个设备堆栈有多少层就会创建多少个 IO堆栈数组单元,有时候也会多创建一个。

IO堆栈保存了相关 IRP 的许多重要参数,供驱动程序执行 IO 时使用。 IO堆栈的使用为 IRP复用技术提供了必要的条件。

Page 29: Windows 驱动开发

29

IO堆栈的数据结构 (2/4)

Page 30: Windows 驱动开发

30

IO堆栈的数据结构 (3/4)

MajorFunction 这是一个整型变量,称为主功能代码,系统定义了一些列宏表示 IRP 的功能,例如 IRP_MJ_READ表示这是个读操作

MinorFunction 副功能代码,细化 IRP 的功能,同样,系统也定义了一些列宏

Parameters 这是个联合,定义了一些参数信息,随主功能代码的不同而不同

DeviceObject 表示这个 IRP 将要被传送的设备对象地址

Page 31: Windows 驱动开发

31

IO堆栈的数据结构 (4/4)

FileObject 表示和这个 IRP 相关联的文件对象的地址。例如对文件做 IO 时,这个域指向做 IO的文件地址。

CompletionRoutine IRP 的完成例程的地址,当驱动程序完成 IRP表示的操作后调用这个例程处理完成 IRP后的操作

Context 作为参数传入完成例程

Page 32: Windows 驱动开发

32

处理 IRP 的标准模型 (1/2)

Page 33: Windows 驱动开发

33

处理 IRP 的标准模型 (2/2)

IO 管理器生成 IRP

将 IRP 发送给驱动程序的派遣例程,派遣例程或者完成 IRP或者将 IRP传递给下层驱动程序或者将 IRP排队

调用 StartIo 例程,该例程负责控制设备进行 IO ,通常 StartIo 设置一些状态位然后连接一个中断服务例程

ISR 当 IO 操作完成时设备向 CPU产生中断,系统调用你的中断服务程序,中断服务程序的最主要的任务是安排一个 DPC 例程

DPC 例程从设备队列中删除 IRP然后返回 IRP

Page 34: Windows 驱动开发

WDM 中的 HelloWorld 程序

Page 35: Windows 驱动开发

35

编译和安装驱动程序

安装 DDK ,利用 DDK 工具编译驱动程序编译、链接驱动程序需要 sources 文件和 mak

efile 文件安装驱动程序需要 inf 文件或者直接修改注册表

Page 36: Windows 驱动开发

Windows XP 的 IO流程

Page 37: Windows 驱动开发

37

同步 IO 与异步 IO

同步 IO :调用 IO 函数的线程在发送完 IO 请求后阻塞本线程,直到这个 IO 请求被完成才唤醒本线程

异步 IO :调用 IO 函数的线程在发送完 IO 请求后并不阻塞本线程,完成这个 IO 请求后通过一些同步机制本线程可以得到请求完成的通知

Page 38: Windows 驱动开发

38

Windows XP 的 IO 执行流程

Readfi l e调用

NtReadfi l e调用

Int 2E

NtReadFi l e调用

调用驱动程序

IO启动 操作

应用程序

KERNEL32.DLL

NTDLL.DLL

NTOSKRNL.EXE

NTOSKRNL.EXE

DRIVER.SYS

ReadFi l e

NtReadFi l e

NtReadFi l e

Ki SystemServi ce

Page 39: Windows 驱动开发

39

Windows XP IO 驱动程序结构

Wi ndows NT IO系统接口

CD-ROM文件系统 NTFS FAT文件系统

FtDi sk驱动程序

磁盘驱动程序

CD-ROM类驱动程序

磁带类驱动程序

端口驱动程序

小端口驱动程序

Page 40: Windows 驱动开发

40

单层驱动程序处理 IRP 的详细流程 (1/5)

环境子系统或DLL

服务IO管理器

设备驱动程序

设备

(1)NtWri teFi l e

(2) IRP创建

(3) IRP传输 指定的数据

(4) IO执行 并中断

Page 41: Windows 驱动开发

41

单层驱动程序处理 IRP 的详细流程 (2/5)

派遣例程

StartIO例程 ISR

DPC例程

DPCDPCDPC

(6)ISR DPC停止设备中断并将 排队

掉电

IRQL设备

DPCAPC

PASSIVE

(5)内核中断调度程序将控制交给设备的服务例程

中断调度表

Page 42: Windows 驱动开发

42

单层驱动程序处理 IRP 的详细流程 (3/5)

派遣例程

StartIO例程 ISR

DPC例程

DPCDPCDPC

掉电

IRQL设备

DPCAPC

PASSIVE

(8)内核中断调度程序将控DPC制交给驱动程序的 例程

中断调度表

(7)IRQL DPC降低处理

(9)DPC例程启动设备队列中的下IO一个 请求然后完成中断服务

Page 43: Windows 驱动开发

43

单层驱动程序处理 IRP 的详细流程 (4/5)

派遣例程

StartIO例程 ISR

DPC例程

IO管理器

(10)DPC IO例程调用IO管理器来完成 请求

APC APC

(11)IO管理器将一APC个 放入队列中以在调用程序的描述

IO表中完成 请求

Page 44: Windows 驱动开发

44

单层驱动程序处理 IRP 的详细流程 (5/5)

APC APC

APC线程的 队列

掉电

IRQL设备

DPCAPC

PASSIVE中断调度表

APC例程

IO管理器

(12)调用线程下次运行时APC中断发生

(13)中断调度程序APC将控制交给 例

(14) APC核心态例程在线程的地址空间写数据,将原始文件句柄设置为信号态,将所有用户态APC放入队列中

执行

环境子系DLL统或

用户态

核心态

Page 45: Windows 驱动开发

用户程序和驱动程序的交互

Page 46: Windows 驱动开发

46

应用程序需要的工作

调用 CreateFile 打开设备的句柄Handle = CreateFile("\\\\.\\IOCTL", GENERIC_R

EAD │ GENERIC_WRITE,    0, NULL, OPEN_EXISTING, flags, NULL);

调用 DeviceIoControl 向设备发送特定请求的 IRP

result = DeviceIoControl(Handle, Code, InputData, InputLength,   OutputData, OutputLength, &Feedback, &Overlapped);

Page 47: Windows 驱动开发

47

驱动程序需要的工作 处理 IRP_MJ_DEVICE_CONTROL 的 IRP

为这样的 IRP添加派遣例程NTSTATUS DispatchControl(PDEVICE_OBJECT fdo, PIRP Irp) {

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);   

ULONG cbin =     stack->Parameters.DeviceIoControl.InputBufferLength;   

ULONG cbout =     stack->Parameters.DeviceIoControl.OutputBufferLength;   

ULONG code =     stack->Parameters.DeviceIoControl.IoControlCode;   

switch (code)     {

……

default:     

status = STATUS_INVALID_DEVICE_REQUEST;     break;     }   

return CompleteRequest(Irp, status, info);   }

Page 48: Windows 驱动开发

内核调试器 SOFTICE

Page 49: Windows 驱动开发

49

SOFTICE

SOFTICE 是一种内核级别的调试器,功能十分强大,不仅可以对应用程序调试,还可以对驱动程序进行调试,除了可以在代码中设置断点外,还可以设置条件断点和内存断点等。同时 SOFTICE 还支持源代码级别和汇编代码级别的调试。

SOFTICE 的窗口界面

Page 50: Windows 驱动开发

50

加载驱动程序符号表

SOFTICE使用自己定义的符号表。 SOFTICE的 SymbolLoader 可以很好的完成这个过程。启动 SymbolLoader ,设置驱动程序 .sys 文件的路径,然后点击 Load 和 Translate选项,这样它就可以将 .sys 的符号信息转化为 .nms符号文件并加载。可以选择 SOFTICE 的加载时机,这样用户就不用每次手动加载了。

Page 51: Windows 驱动开发

51

在源代码中查找

键入 CTRL+ D 可以唤醒 SOFT 的界面,如果没有 SOFTICE没有被唤醒,使用 StartSoftice程序启动 SOFTICE 。执行 table命令, SOFTICE 就列出了所加载的所有符号表的名称,符号表与 .sys 文件同名。

File+文件名命令就可以定位到指定的文件。 U . 行号命令就可以将光标定位到指定文件的行

数。

Page 52: Windows 驱动开发

52

SOFTICE使用

改变调试窗口大小命令 关于断点的命令 BPX WinMain

BPMD MyGlobalVariable W IF MyGlobalVariable==5

运行控制命令 G .145

WATCH命令