用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"