驅動程序在任何操作系統下都和系統內核有著密切的關系,尤其在WIN2000下。在進入WIN2000驅動程序世界之前,本章先介紹驅動程序設計原理和WIN2000構架。
系統的整體結構
WIN2000操作系統是計算機歷史上最安全的操作系統,本節介紹WIN2000系統中驅動程序設計者最關心和最感興趣的部分。
WIN2000的設計目標
有趣的是,原始的NT("New Technology")概念中不包含操作系統環境,直到1989年第一個NT操作系統出現了很長時間后。但是它還保持著原始的設計目標:
兼容性: 盡可能的支持現有的軟件和硬件 。
穩定性和可靠性: 操作系統不會因為用戶的誤操作而損壞,一個用戶程序應該不會使操作系統崩潰。
可移植性: 操作系統應當可在盡可能多的當前和未來的平臺上運行。
可擴展性: 隨著時間的流逝,市場的改變,操作系統應當可以只用添加少的代碼就可以支持新的硬件和添加新的功能。
性能: 操作系統應當盡可能大的發揮硬件的效能。
當然,隨著時間的流逝,操作系統的設計目標也是改變的,剩下的部分介紹怎樣在設計中實現這些目標。
WIN2000的硬件特權級別
為實現穩定性和可靠性的設計目標,WIN2000的設計者使用用戶模式服務結構,用戶的程序在操作系統的用戶模式服務程序中運行。
用戶模式中,代碼被嚴格約束在對系統沒有損害的范圍內。例如: 通過虛擬內存映像,一個程序不能訪問其它程序的內存區(兩個程序共同定義的公用內存區除
外)。硬件I/O指令不能被執行。所有的CPU指令(如CPU中斷)不能被執行(在特定的特權級下)。所有的這些被阻止的操作如果想運行,它們必須通過陷
阱門來請求操作系統內核。
操作系統內核程序運行在內核模式下,它可以執行所有有效的CPU指令,包括I/O操作,可訪問任何程序的內存區,當然是那些沒有被翻出內存而被存到磁盤的內存區。
所有的現代的處理器都可以工作在特權級別模式和非特權級別模式下,用戶模式工作在非特權級別模式下,內核模式工作在特權級別模式下。而不同的平臺和
CPU執行特權級別模式是不同的,為了達到可以在這兩個模式下運行的目標,操作系統抽象了這兩個模式,操作系統總是使用這些抽象的代碼來在這兩個操作模式
下切換。例如: 在Intel平臺上,內核模式使用Ring 0指令系統,而用戶模式使用了Ring 3指令系統。
我們編寫的驅動程序是運行在內核模式下,我們的不正確的代碼將危及到WIN2000操作系統的安全,所以,我們必須格外小心我們代碼的邊界條件,以確保它們不會損壞整個操作系統。
可移植性
為了達到可移植性的目標,NT設計者選擇了軟件的分層結構。如圖1.1所示:

圖 1.1:WIN2000系統的分層結構
硬件抽象層(HAL)隔開了硬件平臺和操作系統以及驅動程序,驅動程序依賴硬件抽象層的代碼和宏去識別硬件的寄存器和總線,有時,驅動程序依賴I/O管理器去分享硬件資源,在以后的章節中將介紹利用硬件抽象層和其它的操作系統服務程序去開發設備無關的驅動程序。
可擴展性
WIN2000的內核也負責系統中所有線程的調度與分配,線程是程序中最小的可獨立運行的部分,為保持每個線程的獨立性,每個線程的設備上下文必須被保
存下來,線程的上下文由CPU寄存器狀態(包括一個獨立的堆棧和程序計數器),ID(線程ID,也叫線程標識符),特權級別代碼,線程地址和其它線程相關
信息組成。
調度程序決定哪一個線程何時運行,在單處理機的環境中,一個時間只能有一個線程得到處理機的執行。
在多處理機的環境中,同一時刻不同的線程可能工作在不同的處理機上,是真正的并發執行。調度程序分配時間片給各個線程,高優先權的線程搶先占有時間片。
操作系統的主要任務是調度線程,還有一些必要的工作,如: 內存管理,進程管理,安全管理和I/O管理。這些部分叫做執行部件,它被作為軟件模塊(除了
I/O管理器這個重要部分),隨著時間的推移,微軟會作一些必要的增加,刪除,分離來作為改進或折衷。WIN2000就是后來才加了活動目錄服務。
保持小的,干凈的內核,外加執行模塊是WIN2000的原則,這個原則使WIN2000經過近十年的修改,維護依然是一個流行的操作系統。
性能
分層的軟件設計表現出良好的性能,NT的開發團隊當然也注意到了:
到目前為止,所有的層別運行在同一硬件模式,即內核模式,因此,中間層的調用比處理器的調用不會多花多少時間,確實,HAL常常使用宏來完成內嵌程序的執行。
有助于集中精力去處理并發,分配盡可能多的線程給任務的不同部分,因為所有的執行部分都是多線程的,幫助程序盡可能少的阻塞,處理器忙等待和中斷停機時間。
當用戶和系統線程通過驅動程序來請求服務的時候,驅動程序代碼阻塞執行是致命的錯誤,如果這些請求不能快速處理,將會導致設備忙或者很慢,這些請求將排隊等候后續處理,幸運的是,I/O管理器使這個過程變的很容易。
執行部件
執行部件提供WIN2000操作系統最基本的服務(除了線程調度),它們的作用非常明顯,解釋如下:

圖1.2 執行部件的組成
系統服務接口
它提供從用戶模式到內核模式的入口。它允許內核模式代碼安全的調用操作系統服務,依靠這個接口,從用戶模式到內核模式可能只是簡單的一個CPU指令或者是一個存儲于恢復上下文開關。
對象管理器
WIN2000操作系統幾乎將所有的服務看成對象提供給用戶,例如: 用戶模式程序為了使線程同步而向操作系統請求互斥對象,操作系統提供的互斥對象是一個操作系統對象,用戶模式程序只能通過句柄來操作它。文件,進程,線程,事件,內存塊,注冊表的鑒值都是以操作系統對象的形式出現,所有的這些都是被對象管理器創建和銷毀。
配置管理器
配置管理器紀錄了計算器上所有硬件和軟件的安裝配置情況,這些信息被紀錄在一個叫做注冊表的數據庫中,設備驅動程序通過注冊表可得到它的工作環境信息。
進程管理器
在WIN2000中,進程是線程的工作環境,每個進程包含一個私有地址空間和一個安全標識。線程是最小的可執行實體,一個進程可以包含一個或者多個線程。
進程管理器依靠執行部件的其它部分才能工作,如: 對象管理器和虛擬內存管理器。
虛擬內存管理器
在WIN2000中,程序的地址空間是平坦的,有4GB大小。只有低2GB可以被用戶模式的程序訪問,也就是說,用戶模式的程序占用低2GB空間,如果程序需要動態連接庫(DLL),動態連接庫也必須在2GB空間內。
高2GB空間被內核模式程序占用,當然,驅動程序也被映像到了這里。
虛擬內存管理器(VMM)管理整個系統的內存,對于一般的用戶模式程序,如果訪問的虛擬內存地址不在物理內存上,虛擬內存管理器將磁盤上相應的文件映像到內存中,這樣,內存在磁盤和有限的RAM之間移動,好象程序可以訪問比RAM大的多空間。
本地進程調用
本地進程調用是同一個計算器上不同進程間通訊的機制。驅動程序不需要這個工具。
I/O管理器
I/O管理器將用戶模式的I/O操作轉變成一系列統一的例程(例行的過程),I/O管理器的一個目標就是使所有的從用戶模式到內核模式的訪問設備無關,無論程序訪問鍵盤,通訊口,磁盤文件都是一樣的。
I/O管理器將用戶模式的I/O操作轉變成I/O請求包(IRP)的形式傳給驅動程序,I/O請求包是I/O管理器將命令的綜合。作為用戶模式程序于驅動程序的中間層,I/O管理器于驅動程序結合部分的代碼將是最重要的部分。
活動目錄服務
活動目錄服務是WIN2000的新的部分,它給系統資源提供無限的名字空間。以前,標識系統資源的名字被定義在操作系統的有限空間內(硬盤名,打印機
名,用戶名,文件名等),活動目錄是一個統一,安全,標準的方法去標識系統資源,它是基于一個分等級的圖,將資源根據實體分成元,樹和森林。
基本操作系統的延伸
WIN2000定義了這幺多的服務,它們沒有被直接的暴露給用戶模式的程序。取而代之的是,WIN2000定義了很多應用程序接口(API),用它們來使用操作系統的服務。應用程序接口在不同的子系統中的形式是不同的,WIN2000包含了以下的子系統:
WIN32子系統: 它是WIN2000固有的應用程序接口模式,所有的其它的子系統都依賴于它去執行它們的工作,因為它是很重要的,所以我們將要在后面詳細的討論。
DOS虛擬器(VDM): 提供一個16位的MS-DOS環境給一些老的16位程序。盡管它承諾了兼容性,但是很多現有的16位程序還是不能完全的運行。這都是因為WIN2000的堅固性和安全性,操作系統將干涉企圖直接訪問設備和其它系統資源的操作。
窗口子系統(WOW): 提供一個16位的WIN3X環境給一些老的16位Windows程序。有趣的是,在僅有的一個窗口子系統進程中,每一個16位Windows程序都是一個單獨線程,它們還互相阻止分享資源,這也正是WIN3X的環境。
POSIX子系統: 提供POSIX1003.1標準的UNIX程序環境,很不幸,這個子系統不能支持其它的標準UNIX程序,這樣的話,很多UNIX程序必須在WIN2000下重寫。
OS/2子系統: 提供一個16位的OS/2程序執行環境,至少不再需要OS/2的陳述管理器(PM),這個子系統只能工作在80X86平臺上。
每個用戶程序都必須和相應的子系統結合起來。例如: 程序的應用程序接口函數不能調用其它的子系統,或者使系統性能下降,這些子系統的設計目的是兼容性,而不是速度。
環境子系統(以上的五個都是WIN2000下的環境子系統)是隔離用戶模式程序的一般手段,它們的運作是必須的。每一個用戶請求都經過本地進程調用傳遞給這些子系統去加工處理,這些子系統或者直接執行這些請求,或者傳遞請求給執行部件。
WIN32子系統
這個子系統提供的應用程序接口有以下幾個方面:
圖形用戶接口: 提供給用戶可視的窗口,對話框,控件,字體等接口。
控制臺I/O: 包括鍵盤,鼠標,顯示器,以及其它子系統。
執行WIN32應用程序接口: 提供應用程序或者其它子系統與執行部件的接口。
因為WIN32子系統在操作系統中的特殊地位和它所提供的高性能,所以它的實現方式與其它的子系統完全不同。它被分成了好幾個部分,其中一些工作在用戶模式,一些工作在內核模式。通常,WIN32應用程序接口被分成3部分:
USER函數: 管理窗口,菜單,控件,對話框等。
GUI函數: 在物理設備(如: 顯示器,打印機)上繪圖。
KENEL函數: 管理非GUI資源,例如: 進程,線程,文件,同步服務,KENEL函數接近于執行部件的服務。
WIN NT4.0以后,USER函數和GUI函數被移到內核模式,因此,用戶模式的請求用系統服務接口直接送到內核模式。USER函數和GUI函數被安置在WIN32K.SYS中,如圖1.3所示:
相反的,KENEL函數依賴于一個標準的服務程序CSRSS.exe去反應用戶程序請求。
其它子系統
除了環境子系統之外,還有一些重要的子系統,它們是用戶模式的過程:
安全管理子系統: 使用一個變化的過程方法和動態庫來管理本地的和遠程的安全問題,部分活動目錄工作也在這個邏輯子系統中。
服務控制管理器: 管理服務和驅動程序。
RPC服務: 它支持網絡的分布式應用程序,通過遠程的程序調用,一個計算器可將自己的一部分任務分配給其它網絡終端。

圖1.3 USER在GUI內核中
內核模式I/O構成
本章的目的是討論內核模式I/O子系統的設計目的,既然很多種類的驅動器都要討論,那幺,I/O管理器的分層驅動器也將討論。
內核模式I/O管理器的設計目標
內核模式I/O管理器的總的設計目標包括:
1.可移植性: 平臺之間。
2.可配置: 包括軟件和硬件,如WIN2000,包括完全的支持即插即用總線和設備。
3.可搶先和中斷: I/O代碼應該不會被阻塞。
4.支持多處理器: 同樣的I/O代碼應可在單處理器下運行,也可在多處理器下運行。
5.基于對象: I/O代碼提供的服務應該被封裝成定義好的結構中。包括數據于操作。
6. 支持I/O請求包: I/O管理器的請求使用一種獨特的格式。
7.支持異步I/O: I/O管理器的請求支持重新請求的模式,完成后,應有一個機制去退出和通知調用者已完成。
除了這些眾所皆知的目標外,它們將重點放在代碼的重用性上,將驅動程序代碼合理的分層。例如: 總線驅動器從特定的驅動器代碼被分成一些獨立的層,使很多總線共享一部分層別。在很多情況下,不同的代理商提供不同的層別,只有小心的模塊化設計才能完成代碼重用的目標。
WIN2000驅動器的種類
曾經有一段時間,驅動程序的作者只要理解復雜的新硬件,學會操作系統接
口,就可以開始工作了,無論好壞,數天后一個驅動器就會完成。今天,驅動程序的作者必須了解復雜的硬件和I/O的分層子系統,才只不過到了工作描述的階
段,下決心開發一個什幺樣的驅動程序都是一個有趣的挑戰,下決心去重寫或者重用一個層別將是令一個挑戰,這一部分描述在硬件世界,操作系統中不同的驅動程
序。
在最高層,WIN2000支持用戶模式,內核模式兩種驅動程序,從名字上來看,用戶模式驅動程序是運行在用戶模式的系統級代
碼,例如: 一個為虛擬的硬件或者新的環境子系統所寫的虛擬驅動器。既然WINN2000不支持直接訪問硬件,虛擬驅動器依賴運行在內核模式的真正的驅動
器。本書不將討論用戶模式驅動程序。
內核模式驅動程序使用系統級代碼編寫,且運行在內核模式下,因為內核模式允許直接訪問硬件,這些驅動程序被用來直接控制硬件。
向下移動一層,內核模式驅動程序可被進一步的分成兩種,遺留模式的驅動程序和Windows驅動模式的驅動程序(WDM)。遺留模式的驅動程序需要去偵測硬件和與I/O子系統連接,這些是已經由其它文獻說明過了。感激的,這些遺留模式的驅動程序可被移植到WIN2000(和WIN98)上。
Windows驅動模式的驅動程序支持即插即用,電源管理,熱拔插,自動配置。一個好的Windows驅動模式的驅動程序可以在WIN2000和Win98上使用,雖然微軟不保證二進制兼容。最多我們再用WIN98 DDK編譯一遍。
再向下移動一層,遺留模式的驅動程序和Windows驅動模式的驅動程序可被進一步的分成三種: 高層,中間層,低層。顧名思義,高層驅動程序依靠中間層和低層驅動程序去完成工作,中間層驅動程序則依靠低層驅動程序去完成工作。
高層驅動程序包括文件系統驅動程序(FSDs),依次的翻譯程序請求成為特定的驅動器請求,當低層的驅動程序的服務已經準備好的時候它也是需要的。
微軟提供一個安裝文件系統工具包(IFS),不在MSDN和其它產品中,是單獨出售的。這個安裝文件系統工具包需要和驅動程序開發包和其它產品一起才能完成開發。使用這種工具包有很多限制。相關信悉請登祿微軟的網站,本書不介紹文件系統的開發。
中間層驅動程序包括磁盤鏡像驅動器,類驅動器(Class),迷你驅動器(MINI),過濾驅動器(FILTER)等。這些驅動器位于低層驅動器和高層
驅動器之間。例如: 磁盤鏡像驅動器接收到文件系統傳來的寫文件的請求,將它轉換成為兩個不同的請求傳給兩個不同的低層驅動器。
類驅動器是對代碼重用的一次嘗試,因為一種特定設備有多個驅動程序,它們之間大部分是相同的,這些相同的部分被作為一個類驅動器和其它部分分開。例如:
所有的IDE驅動器共享大部分的代碼,這樣就只用一次編寫好這些公用的代碼,把它作為一般的類驅動器加載。對于一個指定的設備,我們就只用編寫以類驅動
器為基礎的迷你驅動程序就可以了。
過濾驅動器可以截取程序對存在的驅動程序發出的請求。在請求到達驅動程序之前,它給我們一個更改請求內容的機會。
事實上,在Windows驅動模式的世界中,中間層驅動程序也是由基本的驅動程序所組成,這些驅動程序可能即不是類驅動器,也不是迷你驅動器,但是,它
們縱是扮演著轉換抽象的I/O請求到低層物理驅動器代碼的角色。在DDK的文獻中,迷你驅動器和類驅動器的術語有時顛倒了,但從上下文可以分辨出來。
低層驅動器包括硬件和總線的控制器。例如: SCSI適配器是一個低層驅動器,這些低層驅動器和HAL于硬件結合緊密。在WDM中低層驅動器包括物理驅動器的概念,行為。這些物理驅動器與一個或者多個功能驅動器結合。圖1.4是WIN2000的分層驅動器總圖。

圖1.4 WIN2000的分層驅動器
特殊驅動器結構
除了上節介紹的驅動器外,WIN2000還提供一些特殊的驅動器:
視頻驅動程序,打印機驅動程序,多媒體驅動程序,網絡驅動程序。
視頻驅動程序
視頻驅動程序非常特殊,因為圖形接口經常暴露給用戶,系統的速度也是通過這個部分判斷的。
WIN2000視頻驅動程序構架如圖1.5所示,陰影部分為WIN2000所有,視頻驅動程序為廠商提供,因為很多視頻適配器選用相同的視頻芯片,視頻
芯片制造商提供給視頻適配器制造商的是類(CLASS)驅動程序,例如: ET4000 MINI
驅動程序提供給所有使用ET4000芯片的視頻適配器,這個芯片的其它硬件環境的驅動程序則是視頻適配器自己的驅動代碼。
基本的,視頻驅動程序在請求畫圖系統服務的時候可以直接和I/O管理器通訊,這點和一般的I/O構架是不同的。用戶模式的代碼通常和GDI交互。
GDI函數支持畫線,幾何圖形,文字。因此,GDI好象一個高層驅動器,GDI也依賴I/O管理器和顯示驅動來完成工作,顯示驅動和GDI的通訊是雙向
的。GDI可直接調用顯示驅動的函數,這里的速度是致關重要的。這些函數是顯示驅動的驅動驅動接口(DDI),前綴是Drv,相反的,顯示驅動需要GDI
中的圖形庫例程,叫做圖形引擎調用(GEC),前綴是Eng。
GDI通過傳統分層的設計來訪問I/O子系統,GDI使用I/O管理器去調用MINI 驅動程序和視頻口的例程,例如: 模式開關命令,它被傳給視頻口驅動器的是標準的IRP格式,視頻口驅動器轉換IRP格式為視頻請求包格式,然后傳給MINI 驅動程序處理。
圖1.5 WIN2000視頻驅動程序構架
打印機驅動程序
打印機驅動程序與標準的WIN2000驅動程序有以下幾點不同:
1.假脫機: 一個打印工作在傳送到物理打印機之前先傳送到假脫機,因為物理打印機的速度太慢。
2.遠程操作: 物理打印機通常被連接到一個遠程計算器上,這里用到RPC.
3.不定的打印協議: 不同的打印機當然有不同的打印協議。
假脫機部分如圖1.6所示,以后不再重復說明,陰影部分為WIN2000所有,如果假脫機被擊活,打印工作先被假脫機紀錄進一個文件,假脫機像打印機一樣退出隊列,而后變的可用,這時數據才被傳入本地或者遠程的打印機驅動。
圖1.5 打印機驅動程序的假脫機
客戶端的假脫機部分(winspool.drv 或者 Win32spl.DLL(遠程打印時)),是一個以RPC為基礎的程序,它連接服務端(Spoolsv.exe)和假脫機的API函數。
服務端的代碼依賴路由服務器(spoolss.dll),
這個路由服務器連接一個打印提供者,打印提供者是指定的打印機服務或者驅動程序的抽象。打印提供者創建和管理一個指定的打印工作隊列。一個簡單的打印提供
者可以向整個打印機類提供服務,本地,遠程,網絡的打印提供者都被包含在WIN2000中。
不同的打印機,網絡協議有時需要特殊的打印提供者,例如: Novell INC 提供給WIN2000設計了一個直接輸出到網絡打印服務的打印提供者。
GDI必須轉換程序的畫圖命令成為打印機使用的特殊格式,GDI依靠打印機驅動程序工作, 打印機驅動程序由打印機繪圖DLL和打印機接口DLL組成。
打印機繪圖DLL負責給指定的打印機轉換數據,在WIN2000中,打印機繪圖DLL可以放置在用戶模式或者內核模式中,用戶模式放置在可以產生高的系統可靠性和靈活的配置。
打印機繪圖DLL的接口函數的前綴是Drv,這些接口函數在GDI轉換命令時被調用。
打印機繪圖DLL負責依照用戶的參數配置打印機設備,例如: 多進紙盒的打印機需要被設定缺省的紙張大小和進紙盒。打印機繪圖DLL通過構建一個或者多個配置窗體的形式提供給用戶接口,這些配置窗體上有一些標準的Windows控件,通過它可以方便的配置打印機。
多媒體驅動程序
Windows
2000提供了內核流(KS)去支持多媒體驅動程序像聲卡驅動程序,電視卡驅動程序等。KS由過濾驅動程序和功能驅動程序組成,應用軟件將KS和方法,事
件,等來自組件對象模型(COM)的東西于KS結合,這些機制應用于四種提供給應用程序的KS對象: 過濾器,針腳,時鐘,分配算符。每一個提供給應用程
序的KS對象都是一個標準的I/O文件對象。
過濾器對象(FILTER)(用以區別過濾器驅動程序)是顯露給用戶的執行多媒體操作的高層實體,例如: 應用程序可以打開一個聲卡的話筒過濾器。
針腳對象(PINS)是FILTER的子對象,它是設備的一個節點(輸入或者輸出),例如: 一個話筒過濾器可能給輸入提供一個針腳對象,一個輸出針腳對象然后去獲得(讀)那個數字化的信號。
時鐘對象(CLOCK)給多媒體設備提供(在有請求時鐘的情況下)一個實時鐘,當時間到的情況下,時鐘對象將發送給應用程序一個事件。
分配算符對象(Allocator)給多媒體設備提供一個直接內存接口。這些內存可以通過Allocator去分配或者釋放。
Windows
2000擁有一個通用的類驅動器Stream.sys,在多數情況下,必須編寫一個MINI驅動器去支持指定的像聲卡,攝像機的設備。制造商提供的
MINI驅動器利用類驅動器(包括緩沖器和DMA支持)去支持設備指定的動作,類驅動器執行Windows 2000的KS的抽象。
網絡驅動程序
網絡驅動程序使用ISO的開放的系統互連網羅標準(OSI),這是一個七層的模型,它的頂層是應用軟件層,底層是硬件連接和網絡的拓撲結構,網絡接口卡(NIC)給大多數的平臺提供網絡的硬件接口,網絡驅動程序是寫給指定的NIC的驅動程序。
網絡驅動程序接口規范(NDIS)給NIC驅動程序提供庫支持,通常只允許NIC廠商提供管理硬件特殊細節的MINI驅動程序,更高層的NDIS(中間驅動程序,協議驅動程序)在需要的時候提供媒體轉換,過濾。分層的NDIS如圖1.7所示。
WIN2000提供一個分層的內核模式軟件傳輸驅動接口(TDI),這個分層的在NDIS層和高層軟件抽象像插座和NetBIOS,TDI層使WIN2000的高層結構具有更多的可移植性。
圖1.7網絡驅動程序接口規范
小結
WIN2000為應用程序的開發提供充足的體系結構,當然,這需要驅動程序開發者花費巨大的心血。WIN2000 I/O處理過程圖解是復雜的,但是必須的。這是對理解WIN2000中有什幺驅動器,以及這些驅動器在什幺位置是有益的。