首页 > 代码库 > WDM驱动模型框架简介
WDM驱动模型框架简介
前几天刚刚看了《windows驱动开发技术详解》,在网上看到这篇文章时觉得总结的很好,所以整理收藏!
=========================================================
WDM驱动程序的前世今生
WDM驱动程序在2000年左右还是一种很新的东西,相信很多人都跟我一样,对它很感兴趣,但是又找不到学习的切入点。究其原因,还是因为WDM是一种非常“死板板”的程序,它一运行就是工作在Windows系统的底层RING 0处,提供各种接口给应用程序调用。也正因为如此,它不像Windows普通的应用程序一样,可以很快地上手——更多的时候,你是在阅读它的Windows技术资料和各种Windows接口信息,你还要非常地熟悉Windows系统底层的工作原理,否则一个不小心,就“蓝屏”了,不过话说回来,写Windows驱动程序的时候,死机是家常便饭。
因此很多人都对WDM驱动心怀恐惧。而事实上,我刚开始学WDM的时候,在家看书看了整整3天,但是看完之后好像跟没看也差不了多少,还是不知道怎么WDM驱动程序如何入门,甚至连怎么写一个“Hello World”都不知道。也是后来才知道其实WDM驱动程序根本就没有所谓的“Hello World”程序的,苦逼啊,这主要是因为当时网络上的有关WDM驱动程序资料太少,因为WDM真正得到大面积应用是win2000之后。下面我们说说WDM驱动程序前世今生。
WDM驱动程序前世今生
WDM(Windows Driver Model)模型是从WinNT3.51和WinNT4的内核模式设备驱动程序发展而来的。WDM主要的变化是增加了对即插即用、电源管理、Windows Management Interface(WMI)、设备接口的支持。WDM模型的主要目标,是实现能够跨平台使用、更安全、更灵活、编制更简单的Windows设备驱动程序。WDM采用了“基于对象”的技术,建立了一个分层的驱动程序结构。
WDM首先在Windows98中实现,在Windows2000中得到了进一步的完善,并在后续开发的Windows操作系统中都将存在,比如Windows Me和Windows XP。微软在通过WDM模型的引入,希望减轻设备驱动程序的开发难度和周期,逐渐规范设备驱动程序的开发,应该说,WDM将成为以后设备驱动程序的主流。
Windows系列的跨平台兼容能力的价值
Windows设备驱动程序发展的历史微软已经发布了很多的“Windows”操作系统,从开始的Windows3.0到Windows2000和Windows XP。一些底层的技术一直在各个“Windows”平台下共享,而其他的一些技术随版本的不同有了很大的变化。微软发布Win32 API的目的之一,就是鼓励开发者能够编制出在“Windows”平台之间兼容的应用程序。
由于设备驱动程序是与操作系统最低层的功能发生交互,因此,如果要实现跨平台的兼容,首先必须在不同平台的底层结构上做到兼容。Windows3.0的基本结构一直延续到Windows9x家族,虽然后来的操作系统在驱动程序的开发和管理上有了非常大的改变,但底层的基本结构没有变化。也就是说,一个为Windows3.0开发的设备驱动程序,在大多数情况下,可以不加修改的使用在Windows95和Windows98平台下。在Windows3.x,Windows95,Windows98下使用的是虚拟设备驱动(Virtual Device Driver),也称为VxD。
虚拟设备驱动程序,原来的设计目标是为了支持在Windows平台下的设备,它作为动态连接库(DLL)链接到操作系统里,工作在保护模式下(ring 0)。VxDs解决了那些常规应用程序不能完成的工作,比如直接硬件的读写,也可以说,使用VxD是扩展操作系统内核的一种方法。VxDs最初的编写采用的是Intel汇编语言,后来随着VtoolsD的使用,使用C和C++也开始流行起来。
Windows NT的设计目标
Windows NT的设计体现了更现代和模块化的内部体系,它的目标是更好的灵活性和更加的健壮,兼容Windows3.x和Windows9x并不是它的设计目标,因此,Windows NT的内部体系中没有提供对以前Windows平台的兼容。NT采用了一种特有的内核模式驱动程序体系,一般也采用C语言来编写。
当NT下的驱动程序需要直接控制机器时,它会向硬件抽象层(HAL)发出请求。硬件抽象层建立在驱动程序和实际的硬件之间,为驱动程序隐藏了硬件的不同,这样就可以编制出跨处理器(比如Pentium和Alpha)、源代码兼容的设备驱动程序。因为Windows NT可以工作在单处理器和多处理器环境中,驱动程序必须十分小心的保护关键的数据结构。Windows NT提供了一种分层的体系结构,每一个NT设备驱动程序有一个低层和一个上层接口。低层的驱动程序直接控制硬件。在低层和上层驱动程序之间的是中间层驱动程序。Windows NT也定义了一种类驱动程序体系,并且支持某些设备类。比如,系统中有SCSI类驱动程序支持SCSI磁带设备和SCSI磁盘。Windows NT的这种驱动程序体系,在Windows 98和Windows 2000中得到了继承和扩展,形成了现在的WDM体系。
认识到跨平台兼容能力的价值后,微软开始尝试统一设备体系,给未来的驱动程序开发提供一个简单的平台。微软的做法,不是重新开发一套新的体系,而是在更合理的Windows NT体系的基础上,进行必要的完善,从而形成一个新的设备驱动程序体系,称为Windows driver model,或WDM,在更早的技术文档中,微软也曾用过Win32 Driver Model这个名字。Windows 98最先支持WDM,微软随后推出的操作系统中也都支持WDM,包括Windows 2000系列,Windows Me,Windows XP,但不包括Win CE。
WDM驱动程序模型概论
WDM模型主要采用分层的方法,模仿面向对象的技术,按照微软一贯的思路,先进行逻辑上的“分层”,然后将标准的实现和低层细节“封装”起来,形成“基类”,客户程序通过“继承”的方式来扩展“基类”的功能,完成所需要的实现。在微软的技术文献中,称Windows NT和Windows 2000为“基于对象”(object-based)的系统,和操作系统一样,WDM驱动程序模型也是“基于对象”的系统。
我们知道,在系统中既使用对象又使用类和继承等机制,而且对象之间仅能通过传递消息实现彼此的通信,这样的方法才称为“面向对象的方法”。如果仅使用对象,则这种方法可以称为“基于对象”的方法。“基于对象”的方法虽然不能得到“面向对象”的所有优点,但依然可以使系统的设计、分析和理解更加的清楚。
WDM模型包含了很多的内容,下面主要讨论WDM模型中两个主要的内容:驱动程序的类型和分层的驱动程序结构,以此展开对WDM模型的讨论。其实,只要很好的理解了这两个方面的内容,就能够很快的掌握WDM了。
2.1驱动程序的类型
在WDM模型中,每个硬件设备至少有两个驱动程序:一个功能驱动程序(function driver)和一个总线驱动程序(bus driver)。一个设备还可能有过滤驱动程序(filter driver),用来变更标准设备驱动程序的行为。这些服务于同一个设备的驱动程序组成了一个链表,称为设备栈。
总线驱动程序
总线驱动程序为实际的I/O总线服务,比如IEEE 1394。在WDM的定义中,一个总线是这样的设备,它用来连接其他的物理的、逻辑的、虚拟的设备。总线包括传统的总线SCSI和PCI,也包括并口、串口、以及i8042端口。微软已经为Windows操作系统提供了总线驱动程序。总线驱动程序已经包含在操作系统里了,用户不必安装。一个总线驱动程序负责以下的工作:
- 枚举总线上的设备;
- 向操作系统报告总线上的动态事件;
- 响应即插即用和电源管理的I/O请求;
- 提供总线的多路存取(对于一些总线);
- 管理总线上的设备;
功能驱动程序功能驱动程序是物理设备的主要驱动程序,它实现设备的具体功能,一般由设备的生产商来编写。功能驱动程序的主要功能是:提供对设备的操作接口;操作对设备的读写;管理设备的电源策略;过滤驱动程序过滤驱动程序是一个可选项,当一个用户需要改变或新添一些功能到一个设备、一类设备或一种总线时,就可以编写一个过滤驱动程序。在设备栈里,过滤驱动程序安装在一个或几个设备驱动程序的上面或下面。
过滤驱动程序
过滤驱动程序拦截对具体设备、类设备、总线的请求,做相应的处理,以改变设备的行为或添加新的功能。但过滤驱动程序只处理那些它所关心的I/O请求,对于其他的请求可以交给其他的驱动程序来处理,这样可以非常灵活改变设备的行为,至少用户会这样看。比如:一个USB键盘的上层过滤驱动程序可以强制执行附加的安全检查。
一个鼠标的低层过滤驱动程序,通过对鼠标移动的数据做非线性的转换,可以得到一个有加速效果的鼠标轨迹。功能驱动程序的组成功能驱动程序由类驱动程序和微型驱动程序(Minidriver)组成。
类驱动程序
类驱动程序实现了某一类设备的常用操作,由微软提供,驱动程序的开发者可以只编写非常小的微型驱动程序,去处理具体设备特殊的操作,而对于其他大量的常规操作,可以调用该类的类驱动程序,这也是WDM驱动程序的优点之一。
微软提供的类驱动程序处理常用的系统任务,比如,即插即用功能和电源管理。类驱动程序保证了操作系统在处理类似的任务时的一致性,从而提高了系统的稳定性。设备生产商提供微型驱动程序,以实现自己设备的特殊功能,同时调用合适的类驱动程序完成其他的通用工作。
将大量的标准操作的代码通过各种类驱动程序来实现,并集成在操作系统中,这样的方式可以有效的减少具体设备的微型驱动程序的大小,也就减小了程序出错的可能。如果某一类设备存在着工业标准,微软就会提供一个该类设备的WDM类驱动程序。这个类驱动程序实现了该类设备所有必须的任务,但不实现任何具体设备所特有的东西。
比如,微软提供的HID(人工输入设备)类驱动程序的实现,是根据USB HID 类规范v.11的规定,但并不实现任何一种具体设备的特殊功能,比如,USB键盘、鼠标、游戏控制等等。微软支持的WDM总线和类驱动程序详细的细节请参考驱动程序开发工具包(DDK)。
客户驱动程序
使用总线驱动程序或类驱动程序的任何驱动程序常常称为客户驱动程序。高级配置和电源接口(ACPI)总线驱动程序与PC机的ACPI BIOS打交道,枚举系统中的设备并控制它们的功率使用。外设组件互联(PCI)总线驱动程序枚举和配置PCI总线上的设备。PnP ISA总线驱动程序对可以使用即插即用配置的工业标准体系结构(ISA)设备做类似的工作。流类驱动程序支持数据流的高带宽传输,以得到更快的数据处理速度。这个类驱动程序经常与音频端口类驱动程序结合使用,以支持实时的视频和音频。
该类驱动也负责多任务时序,直接内存存取(DMA),内存优化,即插即用和I/O缓冲区管理。IEEE 1394总线驱动程序枚举和控制IEEE 1394高速总线。USB总线驱动程序枚举和控制低速的USB总线。
USB客户驱动程序使用各种IOCTL通过USB类驱动程序访问它们的设备。SCSI和CDROM/DVD驱动程序用于访问硬盘、软盘、光驱和DVD。人工输入设备(HID)类驱动程序管理多种总线(如USB)间的数据与指令语法翻译。
大多数时候,本类驱动控制由用户交互接口传来的数据,如键盘,鼠标和游戏杆等。静态图像体系结构(STI)根本不是一个驱动程序,而是使用微型驱动程序获得扫描仪和静态相机的一种手段。
STI目前支持SCSI设备、串行设备、并行设备和USB设备。STI是基于COM(组件对象模型)。2.2 分层的驱动程序结构我们已经知道,WDM使用了分层的驱动程序结构,而且WDM是基于对象的。为了便于对硬件的管理,WDM里对每一个单一的硬件引入了一些数据结构,在图3的左手部分描述了一个DEVICE_OBJECT数据结构栈。
在数据结构栈中最低层的是物理设备对象(Physical Device Object),用于描述我们的设备与物理总线的关系,简称为PDO。在PDO的上面,有功能设备对象(Function device Object),用来描述设备的逻辑功能,简称为FDO。在数据结构栈的其他位置, FDO的上面或下面,有许多的过滤设备对象(Filter Device Objects),简称为FiDO。在数据结构栈中的每一个对象都属于一个特定的驱动程序,
如图3中间的虚线所指示的,PDO属于总线驱动程序,FDO属于功能驱动程序,FiDO属于过滤驱动程序。操作系统中的即插即用管理器(PnP Manager)根据设备驱动程序的指令来建立这个数据对象堆栈。前面我们已经知道,总线驱动程序的作用之一是枚举总线上的设备,当总线驱动程序检测到一个设备时,PnP管理器就马上建立一个PDO。当建立好PDO之后,PnP管理器通过查找注册表来找到其他的过滤驱动程序和功能驱动程序。
Windows驱动程序的安装过程
设备的安装程序负责建立这些注册表里的表项,驱动程序的安装,是根据INF文件中的指令进行的。注册表中的表项指明了各种驱动程序在数据对象堆栈中的位置,于是PnP管理器开始装载最低层的过滤驱动程序,并调用该驱动程序的AddDevice函数。该函数在数据对象堆栈中建立一个FiDO,同时也将前面建立的PDO和这个FiDO联系在一起。
PnP管理器反复的实现该过程,装载其他位置靠上的低层过滤驱动程序、功能驱动程序、上层过滤驱动程序,直到该堆栈完成。应用程序对设备的存取通过提交IO请求包(IRP)来进行。在操作系统中,对设备的存取过程是这样的:操作系统中的I/O管理器接受I/O请求(通常是由用户态的应用程序发出的),建立相应的IRP来描述它,将IRP发送给合适的驱动程序,然后跟踪执行过程,当操作完成后,将返回的状态通知请求的发起者。操作系统中的I/O管理器、即插即用管理器、电源管理器都使用IRP来与内核模式驱动程序、WDM驱动程序进行通信,并且,各驱动程序之间的通信也是依靠IRP。
在WDM驱动程序中,IRP首先从最上层进入,如图3里右手边的箭头,然后,依次往下传送。在每一层,驱动程序自行决定对IRP的处理。有时,一个驱动程序除了把继续IRP向下传递外,并不做任何事情。有时,一个驱动程序会完全接管IRP,不再把它向下传递了。当然,一个驱动程序也可以处理IRP后,再把它继续向下传递。这取决于驱动程序的功能和IRP的含义。
从这里,可以知道微软在WDM模型中使用分层的驱动程序结构的原因了,通过分层的方法,在处理对设备的I/O请求时,利用添加合适的驱动程序层的方法,从而非常灵活的改变设备的行为,以实现不同设备的功能。