用ReactOS上明确说过,Pnp管理器对每种设备都会创建一个虚拟root device用于构建设备树;同时这个新创建的root device又作为一个设备栈的栈底,往上形成完整的设备栈。用windbg调试时,可以看到这个虚拟设备属于/driver/pnpmanager驱动。
昨天出于好奇想看下设备树,结果发现只有虚拟设备attach在/driver/pnpmanger创建的设备上,而类似pci/usb设备的设备栈栈底根本不是/driver/pnpmanager设备,这让我很是怀疑,M$到底怎样形成以root为根节点的设备树。
如mssmbios.sys位于设备管理器system设备类下,注册表路径为:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\SYSTEM\0002
用windbg查看设备堆栈,可以看到这个设备attach在/driver/pnpmanger根节点上:
kd> !drvobj mssmbios
Driver object (81f81da0) is for:
\Driver\mssmbios
Driver Extension List: (id , addr)
Device Object list:
81c8e408
kd> !devstack 81c8e408
!DevObj !DrvObj !DevExt ObjectName
> 81c8e408 \Driver\mssmbios 81c8e4c0
821e73d0 \Driver\PnpManager 821e7488 00000034
!DevNode 821e7288 :
DeviceInst is "Root\SYSTEM\0002"
ServiceName is "mssmbios"
又如DDK样例toaster的虚拟总线设备busenum同样位于system设备类下,注册表路径为:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\SYSTEM\0003
其设备栈为:,亦可看到栈底pnpmanager设备
kd> !drvobj busenum
Driver object (81f81030) is for:
\Driver\busenum
Driver Extension List: (id , addr)
Device Object list:
81ff3030
kd> !devstack 81ff3030
!DevObj !DrvObj !DevExt ObjectName
> 81ff3030 \Driver\busenum 81ff30e8
821e7190 \Driver\PnpManager 821e7248 00000035
!DevNode 821a0008 :
DeviceInst is "Root\SYSTEM\0003"
ServiceName is "busenum"
然而,对于一些总线设备根本找不到pnpmanager,如PCI总线和USB总线:
kd> !drvobj pci
Driver object (82189218) is for:
\Driver\PCI
Driver Extension List: (id , addr)
Device Object list:
82127c70 82127e50 82127030 821e03a0
...
8219cb98 821e5370 821ba160
kd> !devstack 82127c70
!DevObj !DrvObj !DevExt ObjectName
81d34028 \Driver\usbehci 81d340e0 USBFDO-1
82127790 \Driver\ACPI 82187810 00000064
> 82127c70 \Driver\PCI 82127d28 NTPNP_PCI0043
!DevNode 821272e8 :
DeviceInst is "PCI\VEN_15AD&DEV_0770&SUBSYS_077015AD&REV_00\4&47b7341&0&1888"
ServiceName is "usbehci"
kd> !drvobj usbhub
Driver object (820de2c0) is for:
\Driver\usbhub
Driver Extension List: (id , addr)
Device Object list:
81c74c98 81d542f0 820f1b70 81fcac98
81c7ac98
kd> !devstack 81c74c98
!DevObj !DrvObj !DevExt ObjectName
> 81c74c98 \Driver\usbhub 81c74d50 00000079
81d542f0 \Driver\usbhub 81d543a8 USBPDO-3
!DevNode 81c82c48 :
DeviceInst is "USB\Vid_0e0f&Pid_0002\6&2edefd9b&0&2"
ServiceName is "usbhub"
对此,我百思不得解,pnpmanager去哪了?经过周AM指点,搞明白一件事:用!drvobj PCI列出pci设备中,除了最后一个是Fdo,其他都是Pdo(这里Fdo设备的意思是由PCI总线驱动AddDevice函数创建的设备,附加在底层的ACPI总线上,而Pdo设备是PCI总线探测到总线上接入了新设备,从而为这个新设备创建了一个Pdo以形成设备栈)。这些Fdo本身是由PCI总线创建,因此并不会attach在pnpmanager上,而通过查找Fdo设备的设备栈,才能找出栈底Pnpmanager。
顺着周AM的思路,我重新调试了一遍,的确找到了PCI总线所在的Pnpmanager,以上面的环境为例,
kd> !drvobj pci
Driver object (82189218) is for:
\Driver\PCI
Driver Extension List: (id , addr)
Device Object list:
82127c70 82127e50 82127030 821e03a0
...
8219cb98 821e5370 821ba160
Pci总线驱动创建的设备0x821ba160就是Fdo(为什么Fdo位于最后?因为这是PCI!AddDevice创建的第一个设备对象,之后创建的设备对象都通过InsertListTail插入到设备队列头部,因此遍历设备队列时,Fdo是最后被遍历到的),查看它的设备栈:
kd> !devstack 821ba160
!DevObj !DrvObj !DevExt ObjectName
> 821ba160 \Driver\PCI 821ba218
821731a8 \Driver\ACPI 821e2940 00000038
!DevNode 821de178 :
DeviceInst is "ACPI\PNP0A03\2&daba3ff&0"
ServiceName is "pci"
PCI设备堆叠在ACPI的Pdo上,怪不得找不到在PCI的设备栈中找不到Pnpmanager。继续寻祖,查找ACPI驱动创建的Fdo:
kd> !drvobj ACPI
Driver object (8219ca10) is for:
\Driver\ACPI
Driver Extension List: (id , addr)
Device Object list:
8212c628 8212c740 8212c858 82126538
...
821731a8 8219c8f8
kd> !devstack 8219c8f8
!DevObj !DrvObj !DevExt ObjectName
> 8219c8f8 \Driver\ACPI 821e2ea0
821a0aa8 \Driver\ACPI_HAL 821a0b60 00000037
!DevNode 8219cd50 :
DeviceInst is "ACPI_HAL\PNP0C08\0"
ServiceName is "ACPI"
同样ACPI的Fdo堆叠在ACPI_HAL驱动的Pdo上,继续寻祖,这次找ACPI_HAL的堆叠情况:
kd> !drvobj ACPI_HAL
Driver object (821a0f38) is for:
\Driver\ACPI_HAL
Driver Extension List: (id , addr)
Device Object list:
821a0aa8 821a0bc8
kd> !devstack 821a0bc8
!DevObj !DrvObj !DevExt ObjectName
> 821a0bc8 \Driver\ACPI_HAL 821a0c80
821a4c68 \Driver\PnpManager 821a4d20 00000001
!DevNode 821a4b20 :
DeviceInst is "Root\ACPI_HAL\0000"
终于在ACPI_HAL驱动的Fdo设备栈中找到了Pnpmanager。这和Windows内核原理与实现书中提供的设备树的结构完全相似
如果此时再深究一下PnpManager驱动创建的设备对象,会发现系统中果真只有一个根设备节点,而其他的PnpManager设备对象都是为了扩展设备树一点一点生长出来的:
kd> !drvobj PnpManager
Driver object (821eb2e8) is for:
\Driver\PnpManager
Driver Extension List: (id , addr)
Device Object list:
821e7190 821e73d0 821e7610 821e7850
...
821a4c68 821a4020
kd> !devstack 821a4020
!DevObj !DrvObj !DevExt ObjectName
> 821a4020 \Driver\PnpManager 821a40d8
!DevNode 821a4ee8 :
DeviceInst is "HTREE\ROOT\0" <----从名字能感觉出这是根设备节点
kd> !devstack 821a4c68
!DevObj !DrvObj !DevExt ObjectName
821a0bc8 \Driver\ACPI_HAL 821a0c80
> 821a4c68 \Driver\PnpManager 821a4d20 00000001 <----<span style="font-family: Arial, Helvetica, sans-serif;">名字看着这么没个性,肯定不是根设备节点了</span>
!DevNode 821a4b20 :
DeviceInst is "Root\ACPI_HAL\0000"