设备栈是windows内核中非常重要的部分,这部分理解可以让我们在调试中节省大量的时间,
在windows NT体系中,内核所有的设备被按照连接次序加载到设备树上,这棵树的根节点是ROOT节点,每一个设备可以从当前路径一直遍历到根节点,从而遍历整个设备树。这里我们看一下USB的例子:
从此图底部开始,示例设备堆栈中的设备对象包括:
1. PCI 总线的 PDO 和 FDO:
根总线驱动程序枚举内部系统总线 (根总线) ,并为找到的每个设备创建 PDO。 其中一个 PDO 适用于 PCI 总线。 (图中未显示根总线的 PDO 和 FDO。)
PnP 管理器将 PCI 驱动程序标识为 PCI 总线的功能驱动程序, 加载驱动程序(,并将 PDO 传递给 PCI 驱动程序。 在其 AddDevice 例程中,PCI 驱动程序为 PCI 总线 (IoCreateDevice) 创建 FDO,并将 FDO 附加到 PCI 总线的设备堆栈 (IoAttachDeviceToDeviceStack) 。 PCI 驱动程序创建并附加此 FDO,作为其作为 PCI 总线的功能驱动程序的职责的一部分。
在此示例中,PCI 总线没有Filter驱动程序。
2. USB 主控制器的 PDO 和 FDO:
PnP 管理器指示 PCI 驱动程序启动其 设备 (IRP_MN_START_DEVICE) ,然后查询其子级 (IRP_MN_QUERY_DEVICE_RELATIONS 的关系类型为 BusRelations) 。 作为响应,PCI 驱动程序枚举其总线上的设备。 在此示例中,PCI 驱动程序查找 USB 主控制器并为该设备创建 PDO。 图中的宽箭头表示 USB 主机控制器是 PCI 总线的“子级”。 作为 PCI 总线的总线驱动程序的一部分,PCI 驱动程序为其子设备创建 PDO。
PnP 管理器将 USB 主机控制器的mini Class/Class加载驱动程序对标识为 USB 主机控制器的功能驱动程序,并加载驱动程序。 PnP 管理器在适当的时间调用驱动程序,以便为 USB 主控制器创建和附加 FDO。
在此示例中,USB 主控制器没有Filter驱动程序。
3. USB 集线器的 PDO 和 FDO:
USB 主机控制器枚举其总线,在唯一端口中定位 USB 集线器,并为集线器创建 PDO。 USB 集线器驱动程序为集线器创建并附加 FDO。
此示例中没有 USB 集线器的Filter驱动程序。
4. 手柄设备的 PDO、FDO 和两个Filter DO。
USB 集线器驱动程序枚举其总线, 手柄设备的 HID 设备,并为手柄创建 PDO。
在此示例中,已在手柄设备的注册表中设置了较低级别的Filter驱动程序,因此 PnP 管理器加载Filter驱动程序。Filter驱动程序确定它与设备相关,并创建Filter DO 并将其附加到设备堆栈。
PnP 管理器确定游戏杆设备的函数驱动程序是 HID Class/mini Class加载驱动程序对并加载这些驱动程序。 驱动程序对由链接到类驱动程序 DLL 的微型类驱动程序组成;它们共同充当设备的一个函数驱动程序。 类/微型类驱动程序对创建一个设备对象 FDO,并将其附加到设备堆栈。
上层Filter驱动程序以类似于较低级别Filter的方式创建Filter DO 并将其附加到设备堆栈。
请注意,父总线驱动程序创建的 PDO 始终位于特定设备的设备堆栈底部。 当驱动程序处理 PnP 或电源 IRP 时,它们必须将每个 IRP 一直向下传递到 PDO 及其关联的总线驱动程序。
下图显示了与上图相同的设备堆栈,但强调由哪些驱动程序创建和管理哪些设备对象。
总线驱动程序跨越多个设备堆栈。 总线驱动程序为其总线适配器/控制器创建 FDO,并为其每个子设备创建 PDO。
设备栈的总结:
设备堆栈本身描述了内核设备的组织形式,这个形式我们可以在设备管理器中看到:
需要注意的是即插即用软件设备枚举器,这个实际上是PNP管理器在应用层看到的接口,当然,它也是第一个在ACPI总线上枚举出来的设备,本身的作用就是枚举PNP设备。
设备栈和I/O请求是息息相关的,I/O请求本身在设备栈中向下传递,直到有一个驱动程序完成了I/O请求,它才会依次返回并一一通知所有在它上面挂载了完成通知的驱动。