2018年5月16日 星期三

Device Instance ID

A device instance ID is a system-supplied device identification string that uniquely identifies a device in the system. The Plug and Play (PnP) manager assigns a device instance ID to each device node (devnode) in a system's device tree.
設備實例ID是系統提供的設備標識字符串,用於唯一標識系統中的設備。 即插即用(PnP)管理器將設備實例ID分配給系統設備樹中的每個設備節點(devnode)。
The format of this string consists of an instance ID concatenated to a device ID, as follows:
<device-ID>\<instance-specific-ID>
該字符串的格式由連接到設備ID的實例ID組成,如下所示:
<設備-ID>\ <實例特定-ID>
The number of characters of a device instance ID, excluding a NULL-terminator, must be less than MAX_DEVICE_ID_LEN. This constraint applies to the sum of the lengths of all the fields and "\" field separator between the device ID and instance-specific-ID fields.
設備實例ID的字符數(不包括空終止符)必須小於MAX_DEVICE_ID_LEN。 此限制適用於設備ID和實例特定ID字段之間的所有字段長度和“\”字段分隔符的總和。
A device instance ID is persistent across system restarts.
設備實例ID在系統重新啟動時保持不變。
The following is an example of an instance ID ("1&08") concatenated to a device ID for a PCI device:
PCI\VEN_1000&DEV_0001&SUBSYS_00000000&REV_02\1&08
以下是連接到PCI設備的設備ID的實例ID(“1&08”)的示例:
PCI \ VEN_1000&DEV_0001&SUBSYS_00000000&REV_02\1&08

https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids





Catalog Files

A signed catalog file (.cat) can be used as a digital signature for an arbitrary collection of files. A catalog file contains a collection of cryptographic hashes, or thumbprints. Each thumbprint corresponds to a file that is included in the collection.
一個簽名的目錄文件(.cat)可以當作任意文件集合的數字簽名。目錄文件包含一組加密哈希值或指紋。每一個指紋都對應於集合中所包含的文件。
Plug and Play (PnP) device installation recognizes the signed catalog file of a driver package as the digital signature for the driver package, where each thumbprint in the catalog file corresponds to a file that is installed by the driver package. Regardless of the intended operating system, cryptographic technology is used to digitally-sign the catalog file.

隨插即用(PnP)設備安裝將驅動程序包的簽名目錄文件識別為驅動程序包的數位簽章,其中目錄文件中的每個指紋都對應於驅動程序包安裝的文件。 無論預期的操作系統如何,都使用加密技術對目錄文件進行數字簽名。
The CatalogFile directive in the INF Version section of the driver's INF file specifies the name of the catalog file for the driver package. During driver installation, the operating system uses the CatalogFile directive to identify and validate the catalog file. The system copies the catalog file to the%System%\CatRoot directory and the INF file to the %System%\Inf directory.

驅動程序INF文件的INF版本部分中的CatalogFile指令指定驅動程序包的目錄文件的名稱。 在驅動程序安裝期間,操作系統使用CatalogFile指令來識別和驗證目錄文件。 系統將目錄文件複製到%System%\ CatRoot目錄,並將INF文件複製到%System%\ Inf目錄。
PnP device installation considers the digital signature of a driver package to be invalid if any file in the driver package is altered after the driver package was signed. Such files include the INF file, the catalog file, and all files that are copied by INF CopyFiles directives. For example, even a single-byte change to correct a misspelling invalidates the digital signature. If the digital signature is invalid, you must either resubmit the driver package to the  Windows Hardware Quality Labs (WHQL) for a new signature or generate a new Authenticode signature for the driver package.

如果任何在驅動程序包內的檔案在簽名以後有所變動,則PnP裝置安裝會認定這個驅動程序包的數位簽名無效。這些檔案包括INF文件,目錄文件以及INF CopyFiles指令複製的所有文件。例如,即使是單字節更改以糾正拼寫錯誤也會使數字簽名無效。 如果數字簽名無效,則必須將驅動程序包重新提交給Windows硬件質量實驗室(WHQL)以獲取新簽名或為驅動程序包生成新的驗證碼簽名。

Similarly, changes to a device's hardware or firmware require a revised device ID value so that the system can detect the updated device and install the correct driver. Because the revised device ID value must appear in the INF file, you must either resubmit the package to WHQL for a new signature or generate a new Authenticode signature for the driver package. You must do this even if the driver binaries do not change.

同樣,對設備硬件或固件的更改需要修改設備ID值,以便系統可以檢測更新的設備並安裝正確的驅動程序。 由於修改後的設備ID值必須出現在INF文件中,因此您必須重新提交包到WHQL以獲取新簽名或為驅動程序包生成新的Authenticode簽名。 即使驅動程序二進製文件沒有更改,您也必須這樣做。
If the driver package installs the same binaries on all versions of Windows beginning with Windows 2000, the INF file can contain a single, undecorated CatalogFile directive. However, if the package installs different binaries for different versions of Windows, the INF file should contain decorated CatalogFile directives. For more information about the CatalogFile directive, see INF Version Section.

如果驅動程序包在從Windows 2000開始的所有版本的Windows上安裝相同的二進製文件,則INF文件可以包含一個未修飾的CatalogFile指令。 但是,如果程序包針對不同版本的Windows安裝不同的二進製文件,則INF文件應包含裝飾的CatalogFile指令。 有關CatalogFile指令的更多信息,請參閱INF版本部分。
If you have more than one driver package, you should create a separate catalog file for each driver package and give each catalog file a unique file name. Two unrelated driver packages cannot share a single catalog file. However, a single driver package that serves multiple devices requires only one catalog file.

如果您有多個驅動程序包,則應為每個驅動程序包創建一個單獨的目錄文件,並為每個目錄文件指定一個唯一的文件名。 兩個不相關的驅動程序包不能共享單個目錄文件。 但是,為多個設備提供服務的單個驅動程序包只需要一個目錄文件。
另外針對.cat files在INF內的配置原則也有說明如下:
CatalogFile=filename.cat

Specifies a catalog (.cat) file to be included on the distribution media of a device/driver. Catalog files are supplied by the Microsoft Windows Hardware Quality Lab (WHQL), after WHQL has tested and assigned digital signatures to driver files. (Contact WHQL for more information about the testing and signing of IHV and/or OEM driver packages.)
Catalog files are not listed in the SourceDisksFiles or CopyFiles sections of the INF. Setup assumes that the catalog file is in the same location as the INF file.
指定要包含在設備/驅動程序的分發介質上的目錄(.cat)文件。 目錄文件由Microsoft Windows硬件質量實驗室(WHQL)提供,在WHQL已經測試並將數字簽名分配給驅動程序文件之後。 (有關IHV和/或OEM驅動程序包的測試和簽署的更多信息,請聯繫WHQL。)

目錄文件未列在INF的SourceDisksFiles或CopyFiles部分中。 安裝程序假定目錄文件與INF文件位於同一位置。

System-supplied INF files never have CatalogFile= entries because the operating system validates the signature for such an INF against all system-supplied xxx.cat files.
[CatalogFile.nt=unique-filename.cat] |
[CatalogFile.ntx86=unique-filename.cat] |
[CatalogFile.ntia64=unique-filename.cat] |
[CatalogFile.ntamd64=unique-filename.cat]
Specifies another INF-writer-determined, unique file name, with the .cat extension, of a catalog file that is specific to Windows 2000 or later.
If these optional entries are omitted from a dual-operating system INF file, a givenCatalogFile=filename.cat is used for validating WDM device/driver installations on all Windows 2000 and later and Windows 98/Me machines. If any decorated CatalogFile.xxx= entry exists in an INF'sVersion section together with an undecorated CatalogFile= entry, the undecorated entry is assumed to identify a filename.cat for validating device/driver installations only on Windows 98/Me machines.
Note that any cross-platform and/or dual-operating system device/driver INF file that hasCatalogFile= and CatalogFile.xxx= entries must supply a unique IHV/OEM-determined name for each such .cat file.
For information about how to use the system-defined .nt.ntx86.ntia64, and .ntamd64 extensions, see Creating INF Files for Multiple Platforms and Operating Systems.

2017年11月3日 星期五

How Windows Installs Devices

本章提供一個裝置安裝過程的高階概述。這個處理過程為當一個新的裝置連接到電腦時,由Windows以及裝置的安裝組件所執行,並由以下的步驟所組成:


Step1:  新的裝置被識別

在新裝置安裝驅動程式之前,裝置所連接的bus或是hub驅動會配置一個硬體識別碼(hardware ID)給裝置。Windows使用硬體識別碼來找尋最適合的裝置驅動包。

一個獨立硬體供應商(IHV)也可以定義一個或多個裝置相容識別碼(compatible IDs)。識別碼的格式類似硬體識別碼; 然而比起硬體識別碼更為通用,並且不需要特定的製造商或型號的訊息。如果作業系統透過硬體識別碼找不到匹配的驅動程式包,那Windows就會使用這些識別碼來選擇一個裝置驅動程式包。IHVs可以在INF檔案裡指定一個或多個compatible IDs。

Windows使用硬體識別碼以及相容識別碼來收尋裝置的驅動程式包。通過將設備的硬件ID和相容的ID與包的INF文件中指定的ID進行比較,為設備找到匹配的驅動程式包。

舉例當一個使用者將一個WLAN adapter插進電腦端的USB hub,會發生以下的事情:
  1. USB hub驅動程式會偵測到這個裝置。根據他從adapter查詢的信息,hub驅動程式會建立裝置的硬體識別碼。例如USB hub驅動對WLAN adapter建立USB\VID_1234&PID_5678&REV_0001  的硬體識別碼。其中VID_1234為供應商(vendor)識別碼,PID_5678為產品或是型號的識別碼,REV_001為裝置的修訂識別碼。
  2. USB hub驅動通知隨插即用管理員(PNP manager)已偵測到一個新的裝置。隨插即用管理員向hub驅動詢問此裝置所有的硬體識別碼。這個hub驅動可以對相同的裝置建立多個硬體識別碼。
  3. 隨插即用管理員通知Windows有一個新的裝置需要被安裝。作為通知的一部分,Windows得到一組硬體識別碼的列表。
  4. Windows開始收尋符合裝置識別碼的驅動包。如果無法透過硬體識別碼來找到匹配的驅動包,則會透過相容識別碼來找尋。


Step2:  裝置驅動被選取

當偵測以及辨識一個新的裝置以後,Windows以及他的裝置安裝組件會按照下面的步驟:

  • Windows為裝置收尋適合的驅動程式包。
    使用硬體識別碼來收尋適合的裝置驅動包。如果硬體識別碼或是相容識別碼符合INF黨內的ID,表示為適合的裝置驅動程式包。 根據作業系統版本的不同,Windows將在各個位置搜索匹配的驅動程式包。
    舉例在W7插入一個WLAN adapter,會發生以下的事情:
    在USB hub建立了WLAN adapter的硬體識別碼列表後,Windows 首先會收尋裝置儲存區(driver store)內符合的裝置驅動程式包。裝置安裝程序會在下面其中一個位置找尋匹配的驅動程式包。如果找到了一個驅動安裝包,則會將它放入驅動儲存區。
    如果是Windows 8以後則會發生以下的事情:
    在USB hub建立了WLAN adapter的硬體識別碼列表後,Windows 首先會收尋驅動儲存區(driver store)內符合的裝置驅動程式包。如果找到了一個驅動安裝包,則會立即安裝這個驅動程式。這個改動讓裝置可以更快的啟動。另外,在另一個程序,Windows會收尋Windows Update以及DevicePath,看有沒有比安裝的驅動更適合的驅動包。如果有發現,則會將它放入驅動儲存區內,然後在稍後安裝他。 


  • Windows從一個或多個驅動程式包中為設備選擇最合適的驅動程式。
    一旦Windows找到一個或多個匹配的裝置驅動包,Windows透過以下的步驟選擇最好的驅動包:
    1) 如果只有找到一個匹配的驅動包,則安裝此包。
    2) 如果找到多個匹配的驅動程式包,則Windows會對每一個驅動程式包,分配一個排名值,Windows會選擇最低排名值的驅動包來安裝。
    3) 如果多個驅動包擁有相同的最低排名值,Windows會使用下面的條件來選擇最佳的驅動程式:  (3.1) 驅動是否有被數位簽屬,始於Windows Vista,Windows總是會選擇簽屬的驅動來取代未簽屬的驅動程式。(3.2)在INF檔內的驅動日期以及版本。

Step3:  該設備的驅動程序已安裝

在Windows對新的裝置選取了最佳的驅動以後,他透過以下的方式保存裝置與驅動的訊息:

  • 電腦可以連接擁有相同型號以及版本的多個裝置。每個設備連接表示為一個設備實體。Windows將每個設備實例表示為唯一的設備節點(devnode)。 devnode包含有關設備的信息,例如設備是否已啟動以及哪些驅動程序已在設備上註冊通知。
  • Windows將每一個裝置驅動表示為一個驅動節點(driver node)。驅動節點包含所有裝置的所有軟體支援,例如任何的服務以及註冊項目。


一旦裝置與驅動實體化,Windows透過下面的步驟安裝驅動:
  1. 根據驅動程式包的INF文件中的指令,Windows執行以下的操作:
    將驅動程式的binary檔和其他關聯的文件複製到INF CopyFiles指令指定的硬碟上的位置。執行裝置實體有關的設定,例如註冊機碼的撰寫。
  2. Windows從驅動程式包的INF文件的Class和ClassGuid中確定設備設置類。為了優化裝置的安裝,對於同一類的裝置設定類將以相同方式設定和配置。
  3. 一旦驅動檔案被複製以後,Windows將控制權轉給PnP管理者。PnP管理者會讀取驅動並且啟動裝置。
  4. PnP管理者為了裝置加載相應的驅動以及可選的過濾式驅動。PnP管理者對尚未加載的驅動調用DriverEntry歷程。然後PnP管理者會對每一個驅動調用AddDevice歷程,始於低過濾式驅動(lower-filter),然後功能驅動(function driver),最後是高過濾式驅動(High-filter)。PnP對裝置配置資源,並且發送IRP_MN_START_DEVICE給裝置驅動程式。
一旦完成以後,表示裝置已經成功安裝並且準備好使用。






2017年11月1日 星期三

Roadmap for Device and Driver Installation

在Windows7以及之後的版本處理裝置驅動的安裝可以依據下面的步驟:
  • 步驟1: 學習Windows裝置與驅動的基本原理。
    你必須了解Windows系列中作業系統的裝置與驅動程式安裝的基本原理。這可以有助於你做出合適的設計決策,並且精簡你的開發程序。
  • 步驟2: 學習相關的驅動包(Driver Packages)以及他們的組成。
    驅動程式包含了所有你必須在Windows底下提供給裝置所安裝的組件。 要安裝裝置或是驅動程式,你必須擁有系統提供以及供應商提供的組件。系統提供的是所有裝置類別的通用安裝軟體。而供應商必須提供一個或多個裝置專用組件在驅動程式包裡面。
  • 步驟3: 學習INF檔案。
    INF檔案包含了用於提供系統安裝驅動包的資訊以及裝置設定,例如裝置的驅動以及任何裝置專用的應用軟體。
  • 步驟4: 為你的裝置驅動程式建立一個驅動程式包。
    你的驅動程式包必須提供一個INF檔案,裝置驅動檔案,以及可以選擇的附加軟體組件。你可以參考Toaster驅動包的例子來決定你的驅動安裝包所需要的組件。
  • 步驟5: 在開發與測試期間測試簽屬(Test-sign)你的驅動包。
    測試簽署是指使用一個測試憑證來簽屬一個預發行版本的驅動程式包,這可以用於在測試電腦上使用。特別的是這允許開發者使用自己簽屬的憑證來簽署驅動包,例如MakeCert工具來產生。這個功能允許開發者在啟動了驅動程式簽名驗證的Windows上安裝並且測試驅動程式包。
  • 步驟6: 發行簽署(Release-sign)你的驅動包並進行發布。
    在測試以及驗證完驅動包以後,你應該進行release-sign驅動包,release-sign識別了驅動包的發行者。雖然這個步驟是可以選擇的,但基於下面的原因還是應該對驅動包release-sign。
    1. 確保驅動包的真實性,完整性以及可靠度。Windows使用數位簽章來驗證發行者的身分並且驗證發布後的程式完整性。
    2. 提供最好的自動安裝體驗。
    3. 在Windows Vista以及之後的版本運行64位元的核心驅動程式。
    4. 播放下一代某些類型的優質內容。

    驅動程式包透過以下兩種方式發行簽名(release-sign)。1. 通過硬件認證工具包(HCK)獲得WHQL的發行簽名(release-sign) 2. 通過Software Publisher Certificate(SPC)來建立發行簽名。
  • 步驟7:  發布你的驅動程式包。最後的步驟就是發佈驅動包。如果你的驅動包符合HCK定義的品質標準,你可以透過微軟更新程式來發布。

2017年8月9日 星期三

Use "DebugView" to show log in c++ dll

void log(char* pszFormat, ...)
{

 static char logbuf[512]; 
 va_list args;

#if _DEBUG
 
 va_start(args, pszFormat);
 vsprintf_s(logbuf, pszFormat, args);
 OutputDebugStringA(logbuf);
 va_end(args);

#endif

}

2017年3月16日 星期四

Bug Check: STATUS_HEAP_CORRUPTION

前言:
同事最近遇到了服務程式莫名其妙停止的問題,通常服務程式(Service)會異常停止,不外乎程式異常或是記憶體操作異常所導致的程式崩潰,但這種timing問題其實是很難靠log去追蹤的(如果幾個月才發生一次,log的累積量其實不難想像的龐大)。好在系統還是有辦法記錄這類的程式崩潰,並且隨後再透過Windbg來分析問題的狀況。

工具:
首先,你會需要知道系統產生dump的位置在哪裡。通常我會直接開軟體(AppCrashView)來看,順便初步看一下問題發生的原因。

再來就是找出dump的所在地。


分析:
這是一個HEAP崩壞問題,發生核心要做HeapFree的時候。

可能是heap manager偵測到heap區塊被多次釋放所導致(heap_failure_block_not_busy)。下面是問題heap block的詳細情形,值得注意的是Entry的位址為block的起始位址也是heap block header的位址,總共是16bytes,然後User就是資料所在的位置,也是動態記憶體配置後,程式設計者實際存取操作的地方。Size就是整個區塊的大小。然後Unused特別解釋一下,當設計者配置一個byte的記憶體大小(char*a = malloc(1))時,系統實際上會配置16bytes倍數的區塊,所以如果你對a[15]操作的時候,是不會有問題的,但如果對a[16]操作可能就會發生heap overrun的問題,而這個a[1]-a[15]的區間就是所謂的Unused區,而heap header也包含在這裡,因為這是不可動的。而這裡的0x10bytes 指的就是header的大小(16bytes)。再來,透過下一個block的位址,我們也可以查詢記憶體的操作有沒有溢位(overflow)。

參考:
最後是參考的網址

2017年2月21日 星期二

Bug Check 0xE4: WORKER_INVALID

前言:
在驅動開發中常會使用到系統執行緒(System thread)來處理一些異步工作,例如一個虛擬串列阜驅動,對上接收應用程式(SCADA)的讀寫控制請求來讀取PLC下的感測器的數據。驅動可能會在短時間內收到大量的命令(non blocking write),然後將命令依序傳給底下的裝置。這時候驅動通常會把這些命令依序放入佇列中,然後交給另一個執行緒來處理這些動作。這個執行緒在核心驅動中有兩種寫法,一種是透過調用PsCreateSystemThread(用於長週期)來建立自己的工作執行緒,另一種則是透過建立WorkItem(用於短周期)來讓系統執行緒調用。

問題:
我在設計驅動架構中有一層就是實作一個TDI client來負責發送網路封包給遠端裝置,這會透過插入WorkItem的方式來處理這些命令。後面試跑了一下,常常會隨機發生BSOD。

分析:

透過下圖可以知道問題出在哪裡,一個配置的workitem已經在佇列中。表示說同一個workitem我插入了兩次。檢查程式碼,發現我配置的Routine,因為處理網路封包的時候與上層的命令是非同步的,所以在共用workitem的情況下,IoQueueWorkItem會被呼叫了兩次。藍屏之所以會隨機發生的原因就是因為有時候Routine處理的速度比插入workitem的時間還要慢。後來我在接收命令的dispatch中透過IoAllocateWorkItem來配置新的workitem,然後在Routine結束前透過IoFreeWorkItem來釋放,問題就可以解決。


補充:
1. 驅動會讓一個WorkItem關聯一個WorkItem回呼例程(routine) ,當系統工作線程處理一個work item時,他會調用關聯的WorkItem例程。

2. 系統工作線程會先移除在佇列中的workitem,然後在調用workitem關聯的回呼例程,所以在回呼例程中釋放workitem是安全的。

3.workitem關聯的routine運行在系統執行緒的上下文(context)。因為系統執行緒的pool是有限資源(推測是紀錄有關插入佇列中的workitem資源),所以執行rountine的時間要短,不然會造成系統死鎖。

參考:
System worker thread