windows下底層驅(qū)動程序設(shè)計隨筆(轉(zhuǎn)載)windows下底層驅(qū)動程序設(shè)計隨筆1 一、 驅(qū)動程序設(shè)計的必要性
在傳統(tǒng)DOS系統(tǒng)下,每個應(yīng)用程序都有權(quán)利讀寫硬件,讀寫I/O端口,控制系統(tǒng)中斷,然而到了Windows系統(tǒng)中,為了保持良好的系統(tǒng)安全性,對應(yīng)用程 序的權(quán)限作出了限制,因為不適當(dāng)?shù)挠布x寫會引發(fā)整個系統(tǒng)的崩潰。在Windows系統(tǒng)中,將整個程序設(shè)計為分層結(jié)構(gòu),其中,應(yīng)用程序位于ring3,驅(qū) 動程序位于ring0,應(yīng)用程序不能讀寫底層硬件,對于硬件操作必須借助于底層驅(qū)動程序,所以,只要是與硬件系統(tǒng)打交道的Windows程序,必然會涉及 到驅(qū)動程序的開發(fā)和設(shè)計。 二、 驅(qū)動程序的分類和設(shè)計工具 驅(qū)動程序是Windows系統(tǒng)的內(nèi)核,驅(qū)動程序的分類與Windows相關(guān),在Windows 9X下,驅(qū)動程序的類型為VXD(虛擬設(shè)備驅(qū)動程序),在Windows 2000/XP,驅(qū)動程序的類型為WDM(Windows驅(qū)動程序設(shè)計模型),生成的驅(qū)動程序設(shè)計文件為.sys格式。 在Windows9X下,設(shè)計驅(qū)動程序的工具稱為VTOOLSD,而在Windows 2000/xp下,設(shè)計驅(qū)動程序的工具為DriverStudio中的DriverWorks,另外的設(shè)計驅(qū)動程序的工具還有WinDriver,微軟提 供的開發(fā)工具為Windows DDK。由于所有的驅(qū)動設(shè)計工具均以DDK作為基本的類或者參照,加上DDK是一個免費軟件,所以在下面主要以DDK為例進(jìn)行講解,掌握了DDK工具,其 他工具也就變得簡單了。 三、 Window DDK軟件的安裝與環(huán)境設(shè)置 每個Windows系統(tǒng)都有各自的DDK開發(fā)工具,在安裝DDK前,請先根據(jù)Windows系統(tǒng)的不同,安裝不同的DDK工具。在安裝DDK之前,請先安 裝相應(yīng)的編譯器如Visual C++6.0,本文以Windows 2000下的DDK為例,說明安裝過程,安裝DDK完成后,選擇菜單“開始”->“Development Kit”->“Check Build environment”將自動進(jìn)行各項環(huán)境的設(shè)置,當(dāng)然用戶也可選擇“Free Build environment”,二者的區(qū)別在于“check”帶有調(diào)試信息,“Free”則不帶有調(diào)試信息,一般情況下,在軟件開發(fā)階段,選用 “check”,而在發(fā)布階段,選用“Free”。 選擇上述命令后,將進(jìn)入編譯環(huán)境,該環(huán)境為“DOS”界面,進(jìn)入驅(qū)動程序所在的目錄,一般情況下,該目錄包含了以下文件: makefile 編譯文件,一般不作更改 sources 規(guī)定了其中的源文件,驅(qū)動程序的類型 源文件 為.c或者.h文件 為了編寫方便,我們可以進(jìn)入DDK提供的例子下面,將makefile和sources拷貝到我們程序所在的目錄下,將sources進(jìn)行簡單的修改,編 譯時,進(jìn)入相應(yīng)的目錄,在該目錄下輸入“Build”,系統(tǒng)編譯完成后,將在objchk\i386目錄下生成相應(yīng)的.sys文件。 四、 驅(qū)動程序的編寫 尋找一個合適的編譯器如EditPlus,當(dāng)然也可以用VC,只不過需要手動編譯,第一步,找到驅(qū)動程序的入口函數(shù)DriverEntry(),相當(dāng)于 Main()或者WinMain(),所有的驅(qū)動函數(shù)入口均從DriverEntry()開始,下面以端口驅(qū)動程序為例,說明驅(qū)動的編寫。該文件位于 NTDDK\src\general\portio下。 1. 創(chuàng)建設(shè)備 對于設(shè)備驅(qū)動程序,首先要創(chuàng)建該設(shè)備,這段代碼可以放在DriverEntry中,也可放在AddDevice中。 首先,調(diào)用IoCreateDevice()創(chuàng)建自己的設(shè)備,該函數(shù)用法可以參考DDK或者相關(guān)示例。在端口操作中,可以將函數(shù)寫為: status = IoCreateDevice (DriverObject, sizeof (LOCAL_DEVICE_INFO), &7, GPD_TYPE, 0, FALSE, &deviceObject); 其次,調(diào)用函數(shù)IoCreateSymbolicLink()創(chuàng)建一個符號連接,方便應(yīng)用程序查找設(shè)備 status = IoCreateSymbolicLink( &win32DeviceName, &ntDeviceName ); 2. 初始化所用的資源 在驅(qū)動程序中,總需要訪問I/O端口、系統(tǒng)中斷、內(nèi)存地址以及DMA,使用這些資源之前,需要獲取資源并且初始化,一種簡單的方法是直接指定,如中斷 10,DMA3等,這種方法雖然簡單,但靈活性差,任何硬件資源的改變均需在驅(qū)動程序中作出修改;另一種較為科學(xué)的方法就是讓驅(qū)動程序訪問注冊表,從注冊 表中訪問硬件資源,然后進(jìn)行初始化。 在驅(qū)動程序中,訪問注冊表的函數(shù)為RtlQueryRegistryValues(),該函數(shù)的用法較為復(fù)雜,可參考相關(guān)資料,建議在驅(qū)動程序開始開發(fā)時,直接給資源賦值,等驅(qū)動程序調(diào)試成功后再加入訪問注冊表代碼。 3. 注冊驅(qū)動程序的各個處理函數(shù) DriverObject->MajorFunction[IRP_MJ_CREATE] = GpdDispatch; DriverObject->MajorFunction[IRP_MJ_CLOSE] = GpdDispatch; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = GpdDispatch; DriverObject->DriverUnload = GpdUnload; DriverObject->MajorFunction[IRP_MJ_PNP] = GpdDispatchPnp; DriverObject->MajorFunction[IRP_MJ_POWER] = GpdDispatchPower; DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL]= SystemControl; DriverObject->DriverExtension->AddDevice = GpdAddDevice; 處理函數(shù)的注冊方法有點類似Windows下應(yīng)用程序設(shè)計的消息處理函數(shù),注冊完成后,當(dāng)處理相應(yīng)的IRP時,自動調(diào)用相應(yīng)的函數(shù)模塊。 五、 驅(qū)動程序與應(yīng)用程序間的信息交互 驅(qū)動程序用以訪問底層硬件,應(yīng)用程序?qū)崿F(xiàn)人機(jī)交互,驅(qū)動程序和應(yīng)用程序之間需要實現(xiàn)相應(yīng)的信息交互,一方面,應(yīng)用程序通過對驅(qū)動程序發(fā)送相應(yīng)的指令,實現(xiàn) 硬件控制的動作指令,另一方面,驅(qū)動程序?qū)⒂布x寫的狀態(tài)、從硬件上獲得的數(shù)據(jù)傳送給驅(qū)動程序,實現(xiàn)應(yīng)用程序與驅(qū)動程序間的交互函數(shù)包括以下API函數(shù); 相應(yīng)的API函數(shù)能夠激發(fā)驅(qū)動程序的消息。 接口API函數(shù) 驅(qū)動程序的中IRP CreateFile IRP_MJ_CREATE CloseHandle IRP_MJ_CLOSE ReadFile IRP_MJ_READ WriteFile IRP_MJ_WRITE DeviceIoControl IRP_MJ_DEVICE_CONTROL 在應(yīng)用程序中,用戶可以調(diào)用上述函數(shù)操作驅(qū)動程序,其中CreateFile( )用于打開驅(qū)動程序,在使用完驅(qū)動程序之后,可以用CloseHandle()關(guān)閉驅(qū)動程序,ReadFile( )用于從驅(qū)動程序中讀取數(shù)據(jù),WriteFile()用以往驅(qū)動程序中寫入數(shù)據(jù),在函數(shù)中,最重要的是DeviceIoControl(),通過定義各種 ITL_CODE來實現(xiàn)應(yīng)用程序與驅(qū)動程序間的通訊函數(shù),并可以傳遞各種參數(shù)和數(shù)據(jù)。 六、 驅(qū)動程序的安裝(最終都是體現(xiàn)在注冊表里) 1.手動安裝方法 生成的驅(qū)動程序為sys后綴,一般放于Windows\System32\Drivers目錄下,如果進(jìn)行手動安裝,可以將生成好的驅(qū)動程序拷貝到該目錄 中,然后修改注冊表,對于注冊表的修改,可以進(jìn)入注冊表修改程序進(jìn)行修改,也可編寫注冊表程序進(jìn)行修改,以下為一注冊驅(qū)動程序的注冊表文件示例。 REGEDIT4 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Device] "Type"=dword:00000001 "Start"=dword:00000001 "ErrorControl"=dword:00000001 "DisplayName"="Device" "Group"="port" "Tag"=dword:00000001 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Device\Parameters] "IRQ Line"=dword:00000003 直接在資源管理器下雙擊reg文件,在彈出的窗口上選擇“是”將直接修改注冊表,完成后,重新啟動Windows系統(tǒng),將調(diào)用驅(qū)動程序。 2.編寫安裝文件INF INF文件含有安裝一個WDM設(shè)備驅(qū)動程序需要的所有必需的信息,包括賦值的文件列表,要創(chuàng)建的注冊表項等,Windows為大多數(shù)類型的設(shè)備提供了一個 標(biāo)準(zhǔn)的安裝程序。INF文件是一個文本文件,由節(jié)組成,每一節(jié)從括在方括號中的節(jié)的名稱開始,后面是節(jié)的內(nèi)容,每一行可以是簡單的一項,或者設(shè)置一個一個 值。具體的INF文件編寫可以參考現(xiàn)成的示例。 DDK安裝完成后,其中存在工具GenINF,可以按照該向?qū)нM(jìn)行INF文件的編寫。 3.利用API函數(shù)編程實現(xiàn)驅(qū)動程序的安裝 利用API函數(shù)實現(xiàn)注冊表的安裝,其實是利用訪問注冊表的API函數(shù)訪問修改注冊表,實現(xiàn)驅(qū)動程序的安裝。這種方法完全可以嵌入到我們的應(yīng)用程序中,以下 提供了安裝驅(qū)動程序的API代碼。主要的API函數(shù)包括RegCreateKeyEx(),RegSetValueEx(), RegQueryValueEx(),RegCloseKey() 。 七、 驅(qū)動程序的調(diào)試 由于驅(qū)動程序的所有信息不能直接輸出到屏幕上,所以驅(qū)動程序的調(diào)試較一般應(yīng)用程序要難得多,在調(diào)試時,可以利用應(yīng)用程序中的 DeviceIoControl()獲取驅(qū)動程序的狀態(tài),也可借助調(diào)試工具SoftIce,比較方便的工具是SysInternals公司的 DebugView,如果驅(qū)動程序中帶有調(diào)試語句信息DbgPrint(),可以直接將該函數(shù)提供的信息顯示到屏幕上。 |
|