1、 设备对象概述
操作系统用device objects(设备对象)来表示设备。每个设备可以有一个或者多个设备对象与之关联。通过操作设备对象来作为对设备的所有操作的目标对象。
内核模式驱动程序必须为每个设备创建至少一个设备对象,下面情况例外:
l 与类型或者端口驱动程序关联的Minidrivers(微型驱动程序)不需要创建他们自己的设备对象。有类型或者端口驱动程序来创建设备对象,并将操作转发到这个微型驱动程序上。
l 在一些特定类型子系统中,驱动程序是设备的一部分,就像NDIS微型端口驱动程序,它们的设备对象是由这个子系统创建的。
要确定一个驱动程序是否需要创建它自己的设备对象,需要参看这个特定设备类型的文档。
有些设备对象表示的不是一个实际的物理设备。它仅仅是一个软件设备驱动程序,只是用来处理I/O请求而不会将这些请求传递给实际硬件。这些驱动程序仍然必须一个创建设备对象来作为对设备操作的目标对象。
设备通常有多个设备对象来表示,它们是处理某个设备I/O请求的驱动程序栈中的每个驱动程序所关联的设备对象的其中一个。设备的设备对象组成了一个device stack(设备栈)。当要处理一个对设备的操作时,系统会将一个IRP数据结构传递给设备栈中最顶层设备的驱动程序。每个驱动程序要么处理这个IRP,要么将这个IRP传递给这个设备栈中下一个紧邻的设备对象的驱动程序。
设备对象由一个 DEVICE_OBJECT结构来表示,这个结构由对象管理器来管理。就像对其他系统对象一样,对象管理器为设备对象提供一样的功能。特别是,设备对象可以被命名,一个被命名的设备对象还可以处理对其的打开操作。
系统为每个设备对象提供了一个称为 device extension(设备扩展)的专用存储区,驱动程序可以使用其存储设备特有的信息。这个设备扩展的创建和释放都是由系统负责的,设备对象无需关心。
下面用一个图片来说明设备对象和I/O管理器之间的关系。对于驱动程序编写者,要多关注下图中DEVICE_OBJECT结构的成员。
2、 WDM设备对象和设备栈
1) WDM设备对象的类型
WDM设备对象有三种类型:
1. Physical Device Object (PDO):物理设备对象,为一个总线驱动程序表示总线上的一个设备。
2. Functional Device Object (FDO):为一个功能驱动程序表示一个设备。
3. Filter Device Object (Filter DO):为一个过滤驱动程序表示一个设备。
这三种类型的设备对象都是DEVICE_OBJECT类型,但用法不同,还有不同的设备扩展。
驱动程序将自己添加到驱动程序栈中,通过创建一个设备对象(IoCreateDevice)来处理一个设备的I/O操作,并且将这个设备对象附加到设备栈中(IoAttachDeviceToDeviceStack)。IoAttachDeviceToDeviceStack函数计算设备栈的当前栈顶位置,并将这个新的设备对象加入到这个设备栈的顶部。
2) 举例说明一个WDM设备对象
下面的图片显示了表示键盘和鼠标设备的设备对象,就是前面的键盘和鼠标的硬件配置章节中图表所示的。下图所示的键盘和鼠标驱动程序层次结构中的键盘和鼠标驱动程序,通过调用I/O支持例程(IoCreateDevice)来创建它们的设备对象。
键盘和鼠标的设备对象
对于键盘和鼠标设备,都是它们的各自的端口和类型驱动程序创建设备对象。端口驱动程序创建一个代表物理端口的物理设备对象(PDO)。每个类型驱动程序创建它们自己的功能设备对象(FDO),这个FDO代表了一个键盘和鼠标的I/O请求的目标对象。
每个类型驱动程序调用一个I/O支持例程来获取一个指针,这个指针指向了紧邻的下一个驱动程序的设备对象,因此类型驱动程序可以将自己链接到一个端口驱动程序之上。这样一来,类型驱动程序就可以将I/O请求下发到代表物理设备的端口驱动程序。
可以像上述配置中加入一个可选的过滤驱动程序,这个过滤驱动程序将创建一个过滤设备对象(filter DO)。就像类型驱动程序一样,这个可选的过滤驱动程序将自己链接到在设备栈中紧邻的下一个驱动程序,而且还会将目标PDO的I/O请求下发到紧邻的下一个的驱动程序。
上图中所示,每个端口驱动程序就是一个总线(低级的)驱动程序,所以每个产生中断的设备的端口驱动程序,必须建立中断对象和注册一个ISR。
一个双端口设备驱动程序,就像用于键盘和辅助设备控制器的i8042驱动程序,如果每个设备使用不同的中断向量,那么就必须分别建立设备特定的中断对象。一旦要编写一个这样的驱动程序,那么既可以为每个设备分别实现一个单独的ISRs,也可以为这两这个设备实现一个单一ISR。
3) WDM设备对象何时会被创建?
下图说明了在一个设备栈中可能有的设备对象类型,描述了那些处理设备I/O请求的驱动程序。
从上图的底部开始:
l 一个总线驱动程序为其总线上的每个设备创建一个PDO。
一旦总线驱动程序枚举到一个设备,他就会给这个子设备创建一个PDO。总线驱动程序从PnP管理器中枚举对BusRelations的IRP_MN_QUERY_DEVICE_RELATIONS做出相应的设备。如果自从上次总线驱动程序响应一个BusRelations的查询关系请求起就被加入到这个总线的话(或者这时从系统启动后的第一个查询关系请求),总线驱动程序会为这个子设备创建一个PDO。
一个PDO代表一个总线驱动程序的设备,就像其他内核模式系统组件一样,比如电源管理器、PnP管理器和I/O管理器。
其他设备驱动程序会将设备对象附加在PDO之上,但是PDO始终处于设备栈的底部。
l 可选的总线过滤驱动程序为每个它们过滤的设备创建过滤DOs。
一旦PnP管理器在BusRelations列表中检测到一个新的设备,它会检测是否有适用于这个设备的总线过滤驱动程序。如果有,则对于每个这样的驱动程序,PnP管理器将确保将其加载运行(如果有必要的话会调用DriverEntry)并且调用这些驱动的AddDevice例程。一旦总线过滤驱动程序要过滤设备的操作,那么过滤驱动程序会创建一个设备对象,并且会在它的AddDevice例程中将这个设备对象附加到设备栈上。如果与这个设备相关的总线过滤驱动程序不止一个,那么每个过滤驱动程序都会创建设备对象,并将其附加到设备栈上。
l 可选的低级过滤驱动程序为每个它们过滤的设备创建过滤DOs。
如果设备有一个可选的低级过滤驱动程序,则PnP管理器将确保将其加载到总线驱动程序和任何总线过滤驱动程序之后。而且PnP管理器还会调用过滤驱动程序的AddDevice例程。在AddDevice例程中,低级过滤驱动程序为设备创建一个过滤DO,并将其附加在设备栈中。如果有不止一个低级过滤驱动程序,那么每个驱动程序都将创建自己的fileter DO并将其附加在设备栈中。
l 功能驱动程序为这个设备创建一个FDO。
PnP管理器确保设备的功能驱动程序被加载,并且调用功能驱动程序的AddDevice例程。功能驱动程序创建一个FDO,并将其附在到设备栈上。
l 可选的较高级过滤驱动程序为每个它们过滤的设备创建一个过滤DO。
如果设备有一个可选的较高级过滤驱动程序,PnP管理器将确保将其加载到功能驱动程序之后,并调用它们的AddDevice例程。每个过滤驱动程序都会将其设备对象附加到设备栈中。
总的来说,设备栈包含了每个驱动程序的设备对象,这些驱动程序都是专门处理某一设备I/O操作的。父总线驱动程序有一个PDO,功能驱动程序有一个FDO,还有每个可选的过滤驱动程序都有一个filter(过滤)DO。
需要注意的是,所有的设备,包括总线适配器/控制器设备和非总线设备,在它们的设备栈中都有一个PDO和一个FDO。总线适配器/控制器的PDO是总线驱动程序为其父总线创建的。例如,一个SCSI适配器插入到一个PCI总线上,那么PCI总线驱动程序将为这SCSI适配器创建一个PDO。
如果一个设备以原始模式使用,那就没有功能和过滤驱动程序。其父总线驱动程知只有一个PDO以及零个或者多个总线过滤Dos。
设备栈为一个设备附加上一些额外的信息组成了这个设备的devnode。PnP管理器维护设备devnode中的信息,比如,设备是否已经启动或者属于哪些驱动程序,如果有的话,还有是否注册了设备改变通知。内核调试器命令 !devnode 会显示devnode的相关信息。
4) 举例说明WDM设备栈
本节描述了由一组可能的USB硬件驱动程序创建的设备对象,以此来阐述WDM设备对象和他们的分层结构。
下图显示了由前文描述的样例驱动程序创建的设备对象。,参看MSDN中 WDM Driver Layers: An Example章节。
这是一个USB游戏杆的WDM设备对象分层样例。
从这个图的底部开始,在这个样例设备对象栈中的设备对象包括以下内容:
1. PCI总线的一个PDO和一个FDO。
根总线驱动程序枚举内部的系统总线,并且为每个发现的设备创建一个PDO。这些PDOs中的一个是代表PCI总线的。(上图没有显示,根总线的PDO和FDO。)
PnP管理器将PCI驱动程序等同于一个PCI总线的功能驱动程序,并将加载这个驱动程序(如果还没有加载的话),还将这个PDO传递给PCI驱动程序。在这个PCI驱动程序的AddDevice例程中,PCI驱动程序为PCI总线创建一个FDO,并将这个FDO附加到这个PCI总线的设备栈上(使用IoAttachDeviceToDeviceStack函数)。PCI驱动程序创建并将这个FDO作为PCI总线功能驱动程序的一部分。
这个例子中PCI总线没有过滤驱动程序。
2. USB主控制器的一个PDO和一个FDO。
PnP管理器指引PCI驱动程序来启动它的设备(IRP_MN_START_DEVICE)并为其子设备查询适合的PCI驱动程序(使用BusRelations关联的IRP_MN_QUERY_DEVICE_RELATIONS)。作为回应,PCI驱动程序会枚举在其总线上的设备。在这里例子中,PCI驱动程序找到了一个USB主控制器并为这个设备创建了一个PDO。图中的宽箭头表明USB主控制器是PCI总线的“子”设备。PCI驱动程序为其子设备创建PDO,这是作为PCI总线驱动程序应有职能的一部分。
PnP管理器将USB主控制器miniclass/class(微类型/类型)驱动程序对等同于一个USB主控制器的功能驱动程序,并加载这个驱动程序对。PnP管理器在适当的时候调用这个驱动程序对来为USB主控制器创建并附上一个FDO。
在这个例子中,USB主控制器没有过滤驱动程序。
3. USB hub的一个PDO和一个FDO。
USB主控制器枚举它的总线,在一个单独的端口中定位到一个USB hub,并为这个hub创建一个PDO。USB hub驱动程序为这个hub创建并附上一个FDO。
这个例子中的USB hub没有过滤驱动程序。
4. 游戏杆设备的一个PDO、一个FDO和两个过滤
USB hub驱动程序枚举它的总线,定位到了一个HID设备(就是这里的游戏杆),并为其创建一个PDO。
在这个例子中,已经为游戏杆设备在注册表中建立了一个低级的过滤驱动程序,因此PnP管理器就加载这个过滤驱动程序。这个过滤驱动程序检测与之关联的设备,然后为设备栈创建并附上一个过滤DO。
PnP管理器确定这个游戏杆设备的功能驱动程序是一个HID class/miniclass驱动程序对,并加载那些驱动。这个驱动程序对由一个链接到一个类型驱动程序DLL的微类型驱动程序组成,他们一起为这个设备服务,就像一个完整的功能驱动程序一样。这个类型/微类型驱动程序对创建只一个设备对象,就是这里的FDO,并将其附到设备栈上。
一个较高级的过滤驱动程序为设备栈创建并附上一个过滤DO,在一定程度上类似低级的过滤器。
需要注意的是,对一个特定设备来说,由父总线驱动程序创建的PDO总是在设备栈的底部。在驱动程序处理PnP或者电源IRPs时,他们必须将每个IRP在设备栈中一直向下传递到PDO,还有与之关联的总线驱动程序。
下图显示了与上图一样的设备栈,只是特别强调了哪些设备被创建和由哪个驱动程序管理。
一个总线驱动程序会涉及不止一个设备栈。一个总线驱动程序为其总线适配器/控制器创建FDO,并且为其每个子设备都创建一个PDO。
No comments:
Post a Comment