前一篇 DDK樣例toaster分析(1) 主要讨論了toaster樣例中的busenum總線驅動。本篇将讨論從總線驅動過渡到功能驅動,也就是toaster.sys。
成功安裝busenum.sys後,運作toaster/exe/enum目錄下的enum程式模拟一個toaster裝置插入:
enum -p 1
前面busenum.sys!Bus_AddDevice建立Fdo的同時還為Fdo建立一個接口:
status = IoRegisterDeviceInterface (
PhysicalDeviceObject,
(LPGUID) &GUID_DEVINTERFACE_BUSENUM_TOASTER,
NULL,
&deviceData->InterfaceName);
DEFINE_GUID (GUID_DEVINTERFACE_BUSENUM_TOASTER,
0xD35F7840, 0x6A0C, 0x11d2, 0xB8, 0x41, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71);
// {D35F7840-6A0C-11d2-B841-00C04FAD5171}
enum.exe通過SetupDi函數打開并通過ioctl通路這個接口:
hardwareDeviceInfo=SetupDiGetClassDevs(GUID_DEVINTERFACE_BUSENUM_TOASTER,...);
SetupDiEnumDeviceInterfaces(hardwareDeviceInfo,...,&deviceInterfaceData);
file = CreateFile ( deviceInterfaceDetailData->DevicePath,...);
調用Ioctl後,最終進入到Bus_Ioctl中,因為是插入裝置,是以最終會調用Bus_PlugInDevice
NTSTATUS
Bus_PlugInDevice (
PBUSENUM_PLUGIN_HARDWARE PlugIn,
ULONG PlugInSize,
PFDO_DEVICE_DATA FdoData
)
先看下FdoData中的内容,确定enum打開的是busenum.sys建立的Fdo:
kd> dd FdoData l1
0x81ec60e8
kd> dt _FDO_DEVICE_DATA 81ec60e8
busenum!_FDO_DEVICE_DATA
+0x01c UnderlyingPDO : 0x823e73d0 _DEVICE_OBJECT
kd> !devobj 0x823e73d0
Device object (823e73d0) is for:
00000034 \Driver\PnpManager DriverObject 823eb2b0
Current Irp 00000000 RefCount 1 Type 00000004 Flags 00001040
Dacl e1594174 DevExt 823e7488 DevObjExt 823e7490 DevNode 823e7288
ExtensionFlags (0000000000)
AttachedDevice (Upper) 81ec6030 \Driver\busenum
Device queue is not busy.
FdoData用UnderlyingPDO指出了堆疊在裝置下面的裝置。從windbg的輸出看出,UnderlyingPDO就是busenum.sys所依賴的pnpmanager裝置對象。
M$的幫助文檔将busenum.sys!Bus_AddDevice建立的裝置描述為Fdo,而将Bus_PlugInDevice建立的裝置描述為Pdo。這是因為在Bus_PlugInDevice中建立出來的devobj代表了busenum總線對象,作為toaster.sys建立的裝置對象的堆疊基石。另外也可以從windbg的輸出看到,busenum新建立的裝置對象并沒有attach到任何已有裝置對象上:
1).調用Bus_PlugInDevice!IoCreateDeviceSecure前,屬于busenum.sys驅動對象的裝置對象:
kd> !drvobj busenum
Driver object (81dfdda0) is for:
\Driver\busenum
Driver Extension List: (id , addr)
Device Object list:
81ec6030 <---是attach在\Driver\PnpManager上的Fdo對象,上一張圖中有描述
kd> !devstack 81ec6030
!DevObj !DrvObj !DevExt ObjectName
> 81ec6030 \Driver\busenum 81ec60e8
823e73d0 \Driver\PnpManager 823e7488 00000034
!DevNode 823e7288 :
DeviceInst is "Root\UNKNOWN\0000"
ServiceName is "busenum"
上圖中,busenum.sys隻有一個裝置對象
2).調用IoCreateDeviceSecure後,busenum.sys會新增一個裝置對象:
kd> !drvobj busenum
Driver object (81dfdda0) is for:
\Driver\busenum
Driver Extension List: (id , addr)
Device Object list:
82062408<---新加的裝置對象 81ec6030 <---原有的裝置對象
kd> !devobj 82062408
Device object (82062408) is for:
0000008a \Driver\busenum DriverObject 81dfdda0
Current Irp 00000000 RefCount 0 Type 0000002a Flags 000000c0
Dacl e23ad84c DevExt 820624c0 DevObjExt 820624f8
ExtensionFlags (0000000000)
Device queue is not busy.
從windbg輸出可以看到,這個新的裝置對象下面并沒有attach其他裝置對象
之後,busenum為這個新建立的裝置對象建立HardwareID(總線裝置的職責不就是為新加入的裝置配置設定裝置ID嗎?)
pdoData->HardwareIDs =
ExAllocatePoolWithTag (NonPagedPool, length, BUSENUM_POOL_TAG);
RtlCopyMemory (pdoData->HardwareIDs, PlugIn->HardwareIDs, length);
後配置設定busenum pdo的HardwardID
kd> dd pdoData l1
b21fdbec 820624c0
kd> dt _PDO_DEVICE_DATA 820624c0
busenum!_PDO_DEVICE_DATA
+0x020 HardwareIDs : 0x8213aa50 -> 0x7b
kd> du 0x8213aa50 <------注意,這是busenum.sys為pdo對象設定的硬體id,之後要按這個id比對功能驅動
8213aa50 "{B85B7C50-6A01-11d2-B841-00C04FA"
8213aa90 "D5171}\MsToaster"
最後,Bus_PlugInDevice通過IoInvalidateDeviceRelations,通知pnp管理器:有新的裝置加入裝置樹,pnp管理器要更新裝置樹關系(說人話,就是為新裝置加載比對的驅動)
由于系統中并沒有安裝這個Pdo的驅動,是以會跳出搜尋驅動的對話框,這裡選擇手動安裝,選擇toaster/inf/sample.inf檔案。至于為什麼要選這個檔案,因為sample.inf檔案的硬體相容清單裡表示支援這個裝置:
[Manufacturer]
%StdMfg%=Standard
[Standard]
; DisplayName Section DeviceId
; ----------- ------- --------
%ToasterDevice.DeviceDesc%=Toaster_Device, {b85b7c50-6a01-11d2-b841-00c04fad5171}\MsToaster <---硬體相容清單
這個清單中的内容完全比對新建立裝置對象的HardwareID,是以系統加載sample.inf中指定的sys檔案,并建立對應的服務,最後把執行權限交給toaster.sys:
[Version]
Signature="$WINDOWS NT$"
Class=TOASTER
ClassGuid={B85B7C50-6A01-11d2-B841-00C04FAD5171}
Provider=%MSFT%
DriverVer=09/21/2006,6.0.5736.1
CatalogFile=toaster.cat
...
[Toaster_Device.NT]
CopyFiles=Toaster_Device.NT.Copy
[Toaster_Device.NT.Copy]
toaster.sys
驅動安裝後,裝置管理器裡多出一個toaster裝置,檢視Driver Detail可以看到驅動檔案的資訊:

扯點題外話,可以通過Update Driver替換新的inf檔案,比如選擇toasterf.inf(含裝置過濾驅動的toaster.sys),并指定sys檔案路徑後,再檢視Driver Detail可以看到功能驅動和過濾驅動:(tmd公司要做驅動測試,測試老問我加載過濾驅動後,怎麼在裝置管理器裡看到!還一定要在裝置管理器裡看到,系統資料庫裡不算,我折騰很久才發現這個!!)
當然這種更新操作要底層裝置支援disable/enable,像磁盤裝置的,不支援disable/enable操作就不能這樣更新驅動(這要感謝同僚周AM的解釋)
好好,扯遠了,回到正題,執行權從busenum.sys過渡到toaster.sys。當然了進入toaster.sys後還會調用toaster的AddDevice函數ToasterAddDevice,是以要在這個函數上下斷:
DriverEntry
kd> !drvobj 8216db10
Driver object (8216db10) is for:
\Driver\toaster
Driver Extension List: (id , addr)
Device Object list:
kd> bp toaster!ToasterAddDevice;g
kd> dd DriverObject l1
f8aed9e8 8216db10
kd> !drvobj 8216db10
Driver object (8216db10) is for:
\Driver\toaster
Driver Extension List: (id , addr)
Device Object list:
剛進入ToasterAddDevice時,驅動對象下還沒有裝置對象。順帶看下ToasterAddDevice的接口
NTSTATUS
ToasterAddDevice(
__in PDRIVER_OBJECT DriverObject,
__in PDEVICE_OBJECT PhysicalDeviceObject
)
DriverObject不用說肯定是toaster.sys的,PhysicalDeviceObject,則是前面busenum建立的pdo了(由于剛才更新驅動時停用啟用過裝置,裝置對象跟上文不能連續了,不過還是能通過!drvobj !devstack來觀察結果):
kd> dd PhysicalDeviceObject l1 ;<---PhysicalDeviceObject的值
f8ae99ec 82062408
kd> !devstack 82062408 ;<---通過裝置堆棧證明這個是前面busenum建立的Pdo
!DevObj !DrvObj !DevExt ObjectName
> 82062408 \Driver\busenum 820624c0 0000008a ;<---這個裝置對象下面并沒有attach其他裝置,跟上文的結論一下,是以可以認為是Pdo
!DevNode 82266878 :
DeviceInst is "{B85B7C50-6A01-11d2-B841-00C04FAD5171}\MsToaster\1&1aafb3d5&0&01"
ServiceName is "toaster"
kd> !drvobj busenum ;<---當然,有人不信,那隻能列出busenum驅動對象下的裝置對象
Driver object (81dfdda0) is for:
\Driver\busenum
Driver Extension List: (id , addr)
Device Object list:
82062408 81ec6030 <---這個驅動對像目前隻有2個裝置對象,為了證明82062408對象是Pdo,隻要證明81ec6030 是Fdo就行了,剩下的靠排除法就能證明
kd> !devstack 81ec6030 ;<---81ec6030的裝置棧顯示,這個就是Fdo,attach在pnpmanager裝置對象上
!DevObj !DrvObj !DevExt ObjectName
> 81ec6030 \Driver\busenum 81ec60e8 823e73d0 \Driver\PnpManager 823e7488 00000034!DevNode 823e7288 : DeviceInst is "Root\UNKNOWN\0000" ServiceName is "busenum"
之後,Toaster.sys調用IoCreateDevice建立功能驅動(注意是toaster.sys的Fdo不是busenum.sys的Fdo),把這個Fdo堆疊到busenum.sys的Pdo上:
status = IoCreateDevice (DriverObject,
sizeof (FDO_DATA),
NULL,
FILE_DEVICE_UNKNOWN,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&deviceObject);
...
fdoData->NextLowerDriver = IoAttachDeviceToDeviceStack (deviceObject,
PhysicalDeviceObject);
這樣就完成了從busenum到toaster的過渡。