windows WDM驅動程式設計

來源:互聯網
上載者:User

      回顧微軟10年,驅動開發模型從VxD->WDM->WDF,開發工具從VtoolsD-->DDK-->WDK,在這個過程中,出現了一些優秀的開發工具,windriver,driver studio 3.2 等。其中windriver適合用來調試硬體,driver studio 3.2 採用C++開發架構,使用者只要簡單的寫幾個回呼函數就可以完成驅動的編寫,但是該軟體又微軟新的驅動模型WDF的衝擊,不在對它進行開發了,將最終版本定格在3.2,我最先學習驅動程式就是通過driver studio學習的。

     從windows 2000開始,開發驅動程式以WDM為基礎,但開發難度大,為了改善這種局面,微軟推出WDF,它以WDM為基礎進行建模和封裝,降低了開發的難道。

    (一)WDF驅動模型到windows WDF驅動程式設計中進行講解:下面主要講講WDM驅動模型和WDF驅動模型的區別;

    1)WDF採用基於對象的技術對WDM進行封裝,對象包括,屬性,方法和事件,屬性好比C++中類中的成員變數,而方法好比C++類中的成員函數,事件就是回呼函數;

    2)無論核心模式的驅動程式或者使用者模式的驅動程式,都採用同一套物件模型構建,採用同一個基礎承載。這個基礎就是WDF。 WDF包括KMDF和UMDF,兩者都是繼承了WDF,無論哪種架構,內部封裝的方法還是WDM。

    3)WDF驅動模型封裝了很多通用的功能,比如Pnp管理和電源管理,在WDM驅動模型下,Pnp和電源管理是很複雜的,最多有300種狀態,但是WDF驅動模型下,WDF架構實現了Pnp和電源管理的功能,驅動開發人員幾乎不要寫一行代碼就可以實現Pnp和電源管理,舉個不恰當的例子,WDF驅動架構就是對WDM驅動的一次抽象,好像C++中抽象類別,其中以純虛函數的形式實現了PNp和電源管理,如果使用者沒有特殊的要求直接使用架構提供的電源管理和Pnp管理就行了。如果要實現特殊的功能,架構提供了回呼函數,驅動開發人員實現回呼函數的功能就可以了,這個回呼函數就好比C++中的override,將基類提供的虛函數覆蓋掉,實現自己的函數;

    4)WDF 採用了基於隊列的I/O派遣隊列,這樣的好處是可以指定哪些IO在哪個隊列上使用;這樣我個人認為 好處就是,會減少IO同步操作,減少系統資源的佔用,比如說鎖的佔用;

 

  (二) 講了WDM驅動模型和WDF驅動模型的區別後,我們下面講解WDM驅動模型,首先從WDM驅動模型中重要的資料結構談起:

   1)驅動對象(DRIVER_OBJECT)

•     每個驅動程式會有唯一的驅動對象與之對應,它作為驅動的一個執行個體在核心的I/O管理器負責載入。 • typedef struct •  { •  PDEVICE_OBJECT DeviceObject; •  PUNICODE_STRING HardwareDatabase; •  PFAST_IO_DISPATCH FastIoDispatch; •  PDRIVER_INITIALIZE DriverInit; •  PDRIVER_STARTIO DriverStartIo; •  PDRIVER_UNLOAD DriverUnload; •  PDRIVER_DISPATCH MajorFunction[IRP_MJ_NUM+1]; •  } DRIVER_OBJECT,*PDRIVER_OBJECT; •DeviceObject:指向驅動程式建立的裝置對象。這個驅動程式調用IoCreateDevice的時候會自動賦予正確的裝置對象指標。每個驅動程式會有一個或多個裝置對象。其中,每個裝置對象都有一個指標指向下一個驅動對象,最後一個裝置對象指向空。此處的 DeviceObject指向驅動對象的第一個裝置對象。通過 DeviceObject,就可以遍曆驅動對象裡的所有裝置對象。• MajorFunction[IRP_MJ_NUM+1]:函數指標的數組 ,每一個指標指向一個函數,這個函數就是處理IRP的派遣函數。 對於驅動程式來說,每個驅動都有唯一的驅動對象與之對應,驅動對象由IO管理器負責載入;         將完驅動對象後,另外一個重要的資料結構就是裝置對象了,在DRIVER_OBJECT中也包含DeviceObject對象的一項成員,一般在驅動的DriverEntry中調用IoCreateDevice建立裝置對象,然後將裝置對象和驅動對象聯絡起來,下面先看看裝置對象的資料結構吧。     

•2)裝置對象(DEVICE_OBJECT) •typedef struct _DEVICE_OBJECT { •..... •  struct _DRIVER_OBJECT *  DriverObject; •  struct _DEVICE_OBJECT *  NextDevice; •  struct _DEVICE_OBJECT *  AttachedDevice; •.... •  PVOID                       DeviceExtension; •..... •} DEVICE_OBJECT, *PDEVICE_OBJECT; •DriverObject:指向驅動程式中的驅動對象; •NextDevice:指向下一個裝置對象,這裡指的下一個裝置對象是同屬於一個驅動對象的裝置,每個裝置對象根據NextDevice域形成鏈表,從而可以枚舉每個裝置對象;•AttachedDevice:指向下一個裝置對象,如果有更高層的驅動附加到這個驅動的時候, AttachedDevice指向那個更高層的驅動。 •DeviceExtension:指向的是裝置的擴充項物件,也就是程式員自己定義的結構體。  通過AttachedDevice可以將上層的驅動附加到下層驅動;而DeviceExtension資料結構也是很重要的資料結構,一般儲存全域的資訊,這樣這些資訊便於管理,比如同步加鎖管理等等;增加驅動的可重新進入性。在DeviceExtension 結構中可以提供一個指向下層裝置的指標,這樣從可以從上層裝置找到下層裝置,同時也可以通過AttachedDevice從下層裝置找到上層裝置。這樣方便尋找裝置  (三)介紹完WDM驅動模型重要的資料結構後,我們下面來看看,Windows應用程式怎麼和驅動程式進行通訊,對於windows 平台來說,應用程式和驅動程式進行通訊,就是通過windows提供的api,如:CreateFile,ReadFile,WriteFile,DeviceIoControl,CloseFile等等。  那麼這些api是怎麼聯絡到驅動程式的呢,舉個簡單的例子來說吧,CreateFile,當應用程式調用這個函數時,通過註冊表,進入核心調用NtCreateFile,然後在核心用系統的IO管理器建立和發送IRP,對於IRP,就是輸入輸出請求包,驅動程式都是IRP驅動的,對於IO管理,Pnp管理,電源管理,都會轉化成對應的IRP,然後轉寄給驅動程式,而相對驅動程式,主要的功能就是實現這些IRP的回呼函數,而在WDF驅動模型下,IO是由IO管理器的IRP和隊列共同作用的。這一點在WDM驅動模型和WDF驅動的差別中進行了講解。 同樣對於ReadFile和WriteFile的流程和CreateFile相似,都是通過IRP轉寄給驅動的。  (四)對於驅動人員來說,最關心的就是IO操作了,在WDM和WDF驅動中,驅動程式所建立的裝置一般有2種讀寫方式:1)緩衝區方式;2)Direct方式 ;3)Neither•緩衝區方式:在系統核心中建立和使用者模式相同的緩衝區,用於發送或接收硬體的資料,然後將緩衝區的資料copy給應用程式; •Direct方式:和緩衝區方式讀寫裝置不同,直接方式讀寫裝置,作業系統會將使用者模式下得緩衝區鎖住,然後作業系統將這段緩衝區在核心模式地址再次映射一遍。這樣使用者模式的緩衝區和核心模式的緩衝區指向的是同一地區的實體記憶體。Neither讀寫方式在此不在進行介紹。   對於windows驅動開發的痛點,在於在驅動程式中減少緩衝區的copy,因為memcpy是很耗時間和cpu的。  (五)Irp派遣函數,派遣函數是windows驅動程式中的一個重要概念,驅動程式的主要功能是負責處理I/O請求,其中大部分I/O請求是在派遣函數中處理的。

•使用者模式下所有對驅動程式的I/O請求,全部由作業系統轉換為IRP的資料結構,不同的IRP資料會被派遣到不同的派遣函數。 •IRP定義: •    在windows核心中,有一種資料結構叫做IRP(I/O Request Package),即輸入輸出請求包。它是與輸入輸出相關的重要資料結構,上層應用程式與底層驅動程式通訊時,應用程式會發出I/O請求,作業系統將I/O請求轉換為相應的IRP資料,不同類型的IRP會根據類型傳遞到不同的派遣函數中。  (六)驅動的同步處理:和windows應用程式多線程同步類似,核心也有訊號量,互斥,自旋鎖,事件等同步機制,而這些同步機制 的函數就是在應用程式的函數前面加一個ke,比如對於事件來說:SetEvent對於KeSetEvent,WaitForSingleObject對應 KeWaitForSingleObject。我們知道應用程式多線程怎麼同步,驅動程式內部怎麼同步,那麼驅動程式和應用程式之間如果同步呢,有一種方法,在應用程式中調用DeviceIoControl傳遞一個Event控制代碼給驅動程式,在驅動程式中鎖定這個控制代碼,然後在驅動中調用KeSetEvent,在應用程式中通過WaitForSingleObject就可以同步了。其實對於DDK和WDK裡面提供的函數也是這樣操作的;下面在講解下DeviceIoControl的流程: DeviceIoControl 分為同步和非同步作業2種,主要是看最後一個參數,這個參數和CreateFile中一個參數配合使用,就可以實現同步操作和非同步作業,對於DeviceIoControl同步操作而言,當應用程式調用DeviceIoControl時,其實裡面會有一個等待的函數,當驅動程式通過 IoCompleteRequest 完成對應的這個Irp時,其實他就是發送一個訊號給應用程式,基本原理和上面講的應用程式和驅動程式同步類似。 同理當DeviceIoControl 非同步呼叫時,也是類似的。  (七)在驅動程式中有分層的概念,比如說過濾驅動程式,在Ndis驅動中,過濾驅動是很重要的,比如你要實現一個防火牆或殺毒軟體,最可靠的方法就是實現一個Ndis中介層驅動程式,在多層驅動程式架構下,RP請求一般會被傳送到裝置棧的最頂層的裝置對象,頂層的裝置對象可以選擇直接結束IRP(IoCompleteRequest),也可以選擇將IRP請求向下層的裝置對象轉寄(IoCallDriver),如果是向下層裝置對象轉寄IRP請求,IRP結束時,IRP會順著裝置棧的反方向原路返回。當得知下層驅動程式已經結束IRP請求時,本層裝置對象可以選擇繼續講IRP向上返回,或者選擇將IRP再次傳遞給底層裝置驅動。 這樣防火牆原理就是做一個過濾驅動,將惡意程式過濾掉,不然它提交給驅動程式;殺毒軟體也類似,在核心就講病毒識別出來,在殺掉!   (八)Pnp隨插即用•隨插即用體繫結構的主要目標是不需要使用者介入,而直接對裝置安裝、拆除操作進行自動設定。 •(1)系統能夠檢測到新裝置的插入,也能檢測到裝置被拔出; •(2)如果匯流排介面容許,裝置可以實現熱插拔,並保證系統可以正常工作,如usb裝置,當裝置插入時,系統會自動載入其驅動,並且保證usb匯流排上其它裝置能正常工作,另外當系統運行時,拔掉usb裝置不會引起系統的崩潰。•狀態轉換圖: •1)當一個裝置被添加到系統時,Windows尋找正確的驅動程式,並調用它的DriverEntry常式; •2)Pnp管理器然後調用驅動程式的AddDevice常式,告訴它要添加一個新裝置,此時驅動程式建立自己的裝置對象;即FDO。 •3)在處理的過程中,驅動程式會收到IRP_MN_START_DEVICE的IRP,開始與硬體進行合適的對話; •4)如果一個裝置要被拔出,Windows使用IRP_MN_REMOVE的IRP查詢驅動程式裝置。如果驅動程式不希望裝置被刪除,它將拒絕刪除請求,然後發送IRP_MN_CANCEL_REMOVE的IRP,使它回到開始狀態;•5)如果使用者突然拔掉一個裝置,在Windows中會發送IRP_MN_SUPPRISE_REMOVE的IRP,驅動必須處理好中斷了的傳輸。   (九)電源管理 (省略) 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.