跳轉到內容

Windows 程式設計/裝置驅動程式簡介

來自華夏公益教科書,開放書籍,開放世界

驅動程式型別

[編輯 | 編輯原始碼]

Windows 裝置驅動程式通常有兩種型別:虛擬裝置驅動程式 (VXD) 和Windows 驅動程式模型 (WDM)。VxD 樣式驅動程式比較舊,相容性較差,而 WDM 驅動程式應該可以完全程式碼相容,一直追溯到 Windows 98。

驅動程式歷史

[編輯 | 編輯原始碼]

在 DOS 的早期,計算機是自由之地,一切皆有可能。為此,開發者編寫了自己的硬體驅動程式,不符合任何特定規範或介面,使用真實模式彙編程式碼。隨著 Windows 3.0 的出現,作業系統開始對應用程式管理採取更加積極主動的方式,透過建立和維護各種虛擬機器,在不同的處理器上下文中執行不同的程式。驅動程式不再能夠以不符合規範的真實模式 DOS 驅動程式存在,而是必須減輕多個程式之間的訪問,這些程式或多或少並行執行。Windows 3.0 將“真實裝置”更改為稱為“虛擬裝置”的受管理資源,並將真實模式驅動程式替換為新的虛擬裝置驅動程式 (VDD)。

Windows NT 產品線作為一個獨立的實體存在於“普通”Windows 品牌之外。這兩個作業系統在幾乎所有你能想到的方面都完全不同,除了外殼看起來相似。Windows NT 是一個完全受管理的作業系統,NT 核心阻止未經授權的資源訪問。這意味著在 Windows NT 中,裝置驅動程式需要透過特定方法與計算機互動,而標準的 Windows 驅動程式(Windows 3.0、3.1、3.11、95、98、Me)可以直接訪問硬體,無需任何管理。此時,這兩個系統的驅動程式通常也用匯編語言編寫。

認識到市場在 Windows 和 Windows NT 之間分裂,微軟看到了引入單一驅動程式模型的必要性,以便裝置驅動程式可以在 Windows 和 Windows NT 之間移植。此外,微軟知道驅動程式必須用 C 語言等高階語言編寫,以便能夠在不同的硬體系統中程式碼相容。為了滿足這些需求,微軟建立了Windows 驅動程式模型 (WDM)。WDM 驅動程式使用 DDK 編譯,用 C 語言編寫,並遵循嚴格的規範,確保它們可以在任何 Windows 系統上執行。本書將嘗試專注於 WDM 驅動程式,但也將包含有關編寫 DOS TSR 驅動程式和 VDD 的說明。

驅動程式問題

[編輯 | 編輯原始碼]

裝置驅動程式在核心模式下執行,因此編寫、測試和除錯驅動程式可能是一項棘手的任務。驅動程式應在安裝之前始終經過充分測試。

由於裝置驅動程式不在使用者模式下執行,因此使用者模式庫(kernel32.dll、user32.dll、wingdi.dll、msvcrt.dll)不可用於裝置驅動程式。相反,裝置驅動程式必須直接連結到 ntoskrnl.exe 和 hal.dll,它們提供本機 API 和執行服務。

編寫驅動程式

[編輯 | 編輯原始碼]

裝置驅動程式通常用 C 語言編寫,使用驅動程式開發工具包 (DDK)。根據所選擇的程式語言,可以使用函式式和麵向物件的方式來編寫驅動程式。通常無法使用 Visual Basic 或其他高階語言來編寫驅動程式。

由於驅動程式在核心模式下執行,因此對驅動程式可以執行的操作沒有限制。驅動程式可以讀取和寫入記憶體的受保護區域,可以直接訪問 I/O 埠,並且通常可以執行各種非常強大的操作。這種能力使驅動程式能夠以極高的效率破壞一個原本穩定的系統。

Windows 平臺 DDK 附帶標頭檔案、庫檔案和一個命令列編譯器,可用於用 C 或 C++ 編寫裝置驅動程式。DDK 編譯器沒有圖形介面。

裝置驅動程式堆疊

[編輯 | 編輯原始碼]

Windows 以高度模組化的方式實現裝置驅動程式,在我們繼續討論驅動程式程式設計之前,我們必須討論一些術語。任何特定裝置所需的驅動程式都按驅動程式堆疊排列,並透過一個單向連結串列在內部連線在一起,該連結串列從堆疊底部(根驅動程式)開始,在最高階驅動程式處終止。每個驅動程式必須包含至少兩個模組,一個根驅動程式和一個功能驅動程式。這種組合,加上一些可選的補充,構成了人們通常稱為完整的“裝置驅動程式”的全部內容。功能驅動程式將是最常見的編寫型別,並且將是本華夏公益教科書的重點。

微軟認識到,某些型別的裝置都以類似的方式工作,如果每個硬體製造商都不得不從頭開始編寫所有驅動程式程式碼,這將是巨大的時間浪費。為此,Windows 允許使用一種稱為類驅動程式的驅動程式型別。類驅動程式本身不是完整的功能驅動程式,但類驅動程式可以動態連結到常規功能驅動程式,並且可以簡化開發過程。可以編寫自己的類驅動程式,但第三方程式設計師通常不用擔心這一點。通常,微軟會提供類驅動程式,驅動程式開發者會利用這些類驅動程式。這確保了類驅動程式完全經過微軟測試和認證,並且非常通用。

驅動程式的另一個分類是篩選器驅動程式。篩選器驅動程式通常有兩種型別,一種是上層篩選器驅動程式,另一種是下層篩選器驅動程式。上層篩選器驅動程式位於功能驅動程式堆疊之上,顧名思義,它們會過濾傳入的 I/O 請求。下層篩選器驅動程式位於功能驅動程式和根驅動程式之間的堆疊中。篩選器驅動程式通常作為錯誤修復或對現有驅動程式的快速 hack 擴充套件來實現。

以下是驅動程式堆疊的通用示意圖

Upper filter driver
     |
     |
  Function Driver <-------> Class Driver
     |
     |
Lower Filter Driver
     |
     |
  Root driver
     |
     |
   Hardware

匯流排和物理裝置

[編輯 | 編輯原始碼]

為了簡化,讓我們使用術語“匯流排”來指代計算機上任何可以從一個地方傳輸到另一個地方的資訊的地方。這是一個非常寬泛的定義,並且理應如此:“匯流排”一詞需要涵蓋從 USB、序列埠、PCI 卡、影片輸出等等所有內容。每個匯流排都由其自己的根驅動程式控制。有一個 USB 根驅動程式、一個 PCI 根驅動程式等等。

現在讓我們考慮一種名為根匯流排的神話構造,它是一個所有其他匯流排都連線到的結構。根匯流排物件實際上並不存在於你的計算機中,但將其視為一個方便的思考方式。此外,根匯流排也有自己的驅動程式。根匯流排驅動程式物件負責跟蹤連線到你整個計算機中任何總線上的裝置,並確保資料到達目的地。

即插即用

[編輯 | 編輯原始碼]

即插即用 (PnP) 是一種技術,允許計算機上的硬體動態更改,PnP 軟體會自動檢測更改,並分配重要的系統資源。PnP 有自己的根驅動程式,該驅動程式與根匯流排驅動程式密切通訊,以跟蹤系統中的裝置。

裝置名稱空間和命名裝置

[編輯 | 編輯原始碼]

"任意上下文"

[編輯 | 編輯原始碼]

驅動程式在呼叫驅動程式時執行的任何執行緒的上下文中執行。為此,我們說驅動程式在“任意上下文”中執行。因此,驅動程式程式設計師不應該對驅動程式入口點的處理器狀態做任何假設。這會帶來一些問題,所以我們將在本文中討論它們。

浮點運算

[編輯 | 編輯原始碼]

想要使用 MMX 或浮點運算的驅動程式可能會發現它們遇到了一些不必要的困難。因為驅動程式可以在任何時間在任何上下文中進入,所以浮點單元可能包含來自中斷以呼叫驅動程式的使用者模式程式的部分結果和未處理的異常。僅僅儲存上下文然後恢復它是不夠的,因為任何未處理的異常都可能變成“無法處理”,並引發系統錯誤或錯誤檢查。微軟只在某些情況下建議使用浮點運算,我們將在後面討論它們。

[編輯 | 編輯原始碼]
華夏公益教科書