引言
驱动的设备栈可以参看:http://blog.csdn.net/hgy413/article/details/17737517,如下:
驱动设备的创建顺序是,先创建底层PDO,再创建高层的FDO,PDO和FDO之间可能夹杂着各种过滤驱动,每次的设备对象由不同驱动程序所创建,有的驱动程序是系统自带的,有的需要程序员来编写,底层设备对象寻找上层的设备对象,是依靠底层设备对象的AttachedDevice寻找的,如果某一设备的AttachedDevice为空,说明已经到了设备堆栈的顶部,而高层设备找低一层的设备对象,只能能过设备扩展来记录,如下图:
PDO:物理设备对象,由总线(BUS)创建
FDO:功能驱动对象,实现PDO的某些功能
FIDO:可插入由PDO-FDO组在的设备栈中,参与IRP处理
CDO:控制设备对象,不对应真实/逻辑的物理设备,我们大部分是写这种,一般来讲,一个驱动程序只会创建唯一的功能设备对象, 功能设备对象一般不用来处理具体的物理设备功能,仅仅作为 驱动程序的编程接口,与其他模块交互
设备栈
1.系统中的I/O请求虽然发送给指定的设备对象,但请求却是通过 设备栈来传递的
2.最上层的设备对象首先获得机会处理请求,然后传递给下层设 备对象。如果上层设备对象处理完请求,则可以拒绝将命令继 续下传,下层设备对象就失去了处理的机会
3.功能设备对象会完成大多数的工作,只把部分I/O请求传递给物 理设备对象。 I/O请求在设备栈中传递完毕后,还会有一次从栈底开始的逆向 回调过程,进行完成后操作
4.过滤设备对象可以把自己插入到设备栈中任意位置,过滤顺向 的IO请求包,或者逆序的回调过程。多个过滤设备对象可以叠 加
!drvobj
!drvobj 扩展命令显示DRIVER_OBJECT 的详细信息。
Flags
(Windows 2000和之后) 可以是下面这些位的任意组合。(默认为0x01)
-
Bit 0 (0x1)
- 显示驱动拥有的设备对象。 Bit 1 (0x2)
- 显示驱动的dispatch例程的入口点。 Bit 2 (0x4)
- 显示驱动的设备对象的详细信息(需要设置bit 0)
以打印机驱动为例:
0: kd> !drvobj parport
Driver object (89a48ce8) is for:
\Driver\Parport
Driver Extension List: (id , addr)
Device Object list:
895e3040 8969d030
等同于
0: kd> !drvobj \Driver\Parport
Driver object (89a48ce8) is for:
\Driver\Parport
Driver Extension List: (id , addr)
Device Object list:
895e3040 8969d030
等同于
0: kd> !drvobj 89a48ce8
Driver object (89a48ce8) is for:
\Driver\Parport
Driver Extension List: (id , addr)
Device Object list:
895e3040 8969d030
!devstack
!devstack 扩展显示设备对象关联的设备栈的格式化后的信息。
DeviceObject
指定设备对象。可以是DEVICE_OBJECT 结构的16进制地址或者设备名。
以上面为例:
0: kd> !devstack 895e3040
!DevObj !DrvObj !DevExt ObjectName
> 895e3040 \Driver\Parport 895e30f8 Parallel0
!DevNode 899ce970 :
DeviceInst is "LPTENUM\MicrosoftRawPort\6&16ccfde1&0&LPT1"
0: kd> !devstack 8969d030
!DevObj !DrvObj !DevExt ObjectName
> 8969d030 \Driver\Parport 8969d0e8 ParallelPort0
89a56bb8 \Driver\ACPI 89bfeb30 00000071
!DevNode 89a56728 :
DeviceInst is "ACPI\PNP0400\5&324d5432&0"
ServiceName is "Parport"
从上面可以看到设备栈,它的底层设备栈是89a56bb8,对应的驱动是ACPI,
我们来看看ACPI一共创建了多少个设备:
0: kd> !drvobj \Driver\ACPI
Driver object (89c5c8b0) is for:
\Driver\ACPI
Driver Extension List: (id , addr)
Device Object list:
89ba9870 89ba9988 89ba9aa0 89ba9bb8
89ad59a0 89ad5ab8 89ad5bd0 89ad5ce8
89ad5e00 89ad5f18 89ad5030 8971c2b0
8971c3c8 8971c4e0 8971cce8 8971ce00
8971cf18 89a87208 89ae4770 89ae4888
89ae49a0 89ae4ab8 89ae4bd0 89ae4ce8
89ae4e00 89ae4f18 89a63540 89a63658
89a63770 89a63888 89a639a0 89a63ab8
89a63bd0 89a63ce8 89a63e00 89a63f18
89c14658 89c14770 89c14888 89c149a0
89c14ab8 89c14bd0 89c14ce8 89c14e00
89c14f18 89bab4c8 89c46db0 89c10f18
89baa6b8 89bf91f8 89c471f8 89aa74e8
89b94378 897068a8 8972d218 89bcb1a8
89be01a8 89bf51a8 89c11e70 89c11920
89c5c520
有点多啊,它们分布在不同的设备栈中,随便取个看看,比如第三个:
0: kd> !devstack 89ba9aa0
!DevObj !DrvObj !DevExt ObjectName
8970f030 \Driver\serenum 8970f0e8
89b84638 \Driver\Serial 89b846f0 Serial0
> 89ba9aa0 \Driver\ACPI 89c474a0 00000074
!DevNode 89ba9608 :
DeviceInst is "ACPI\PNP0501\1"
ServiceName is "Serial"
来看看AttachedDevice,当一个FDO附加在一个PDO上时,PDO的AttachedDevice会记录FDO的位置,PDO会被称为底层驱动或下层驱动,而FDO会被称为高层驱动或上层驱动,越上层越接近发出IO请求的地方,如上面,
0: kd> dt 89ba9aa0 _DEVICE_OBJECT -y AttachedDevice
nt!_DEVICE_OBJECT
+0x010 AttachedDevice : 0x89b84638 _DEVICE_OBJECT
0: kd> dt 89b84638 _DEVICE_OBJECT -y AttachedDevice
nt!_DEVICE_OBJECT
+0x010 AttachedDevice : 0x8970f030 _DEVICE_OBJECT
0: kd> dt 8970f030 _DEVICE_OBJECT -y AttachedDevice
nt!_DEVICE_OBJECT
+0x010 AttachedDevice : (null)
可以看到_DEVICE_OBJECT的AttachedDevice可以从下向上遍历设备栈,而设备栈中每一层设备都分属于不同驱动,而_DEVICE_OBJECT的NextDevice可以遍历当前驱动创建的所有设备,这是两个不同的概念