詳解Windows 2000/XP Class/Port/Miniport驅動模型(http://webcrazy.yeah.net)

來源:互聯網
上載者:User
詳解Windows 2000/XP Class/Port/Miniport驅動模型
            WebCrazy(http://webcrazy.yeah.net)

    對於軟體複用,Microsoft Windows在使用者層提供了COM(Component Object Model),其實現了二進位層級的相容,使Windows開發進入了組件時代。COM的概念之一進程內組件,在使用者態使用動態聯結庫作為載體。所以不管在COM之前或是之後,DLL都是Windows下實現軟體複用的一個最主要的途徑。只是單純的DLL並未實現COM一樣的二進位相容的目的。但對於驅動開發人員而言,不同於使用者態的代碼,2000/XP並未有相應的像COM一樣的機制,實現核心態的二進位相容方式。實際上對於核心態也沒有必要提供一個像ole32.dll在使用者態實現的COM Library這樣的複雜機制(使用者態COM組件遵循的簡單的規則主要隱藏在COM Library的複雜之下)。

    傳統的DLL複用模式同樣的適用於核心態代碼的開發,加上為了簡化同一類型裝置開發工作等目的,Windows 2000/XP形成了Class/Port/Miniport這樣的概念。我們知道對於Driver其提供的.sys檔案實際與dll沒有什麼實質上的變化。我們首先討論一下Class/Port/Miniport的概念與這種機制帶來的益處:
 
    1、我們知道PC機硬體通常可分成許多大類,如儲存類裝置等等。各大類又分成許多小類。如儲存類裝置又可分為Cdrom、Tape、Harddisk等等。對於每一類裝置,提供一個class driver。這樣的driver實現某一類型裝置Driver與裝置無關的公用的功能集合。對於Driver開發人員而言,有了class driver的介入,僅僅需要實現一部分需要針對特定裝置的功能,IO管理器需要的功能要不由class driver直接完成,要不就由class driver通過調用底層的模組來實現。class driver通常由Microsoft提供,通常實現的是裝置無關的部分,這裡的與裝置無關主要是指不直接操作裝置硬體。而這底層的模組通常稱為miniport driver,後者由port driver提供服務(port driver類似於使用者態DLL,不過她還實現一些簡化裝置驅動編寫的功能,例如隱藏對IRP的繁瑣操作等等)。Class driver調用miniport driver的方式主要有Device IOCTL,class driver匯出的常式(就是DLL的概念)或是通過回呼函數等等。這樣分離出共有的部分,即可以實現所謂的複用,既減少了系統資源的佔用,又減輕了開發工作量。例如對於儲存類裝置Microsoft分別提供了供了cdrom.sys,tape.sys與disk.sys三個class driver。這三個driver之中當然也存在一定的共同點,畢竟他們都屬於儲存類裝置(底層硬體的區別通過miniport driver來區分)。Windows提供了classpnp.sys,三個driver將一些通用的常式置於這個sys中。這才更像是文章開頭介紹的DLL複用技術,而不是這裡介紹的class/port或是miniport driver。我在此段開頭定義class實際上特別提出了與裝置無關的共有功能的集合。即class driver實現的是與裝置硬體無關的部分,這樣做的好處是對於使用者態的客戶程式來說,不管對於scsi還是ide的裝置,我們都可以使用一樣的io操作來進行讀寫等操作,這裡面的主要不同由class driver分發不同的請求至相應的port/miniport driver來實現對使用者的透明。這才是最主要的class driver的目的。Microsoft還提供了一個miniclass的概念,在本文未加以敘述(具體請自行參考相關文檔)。

    2、那麼class driver內部通常是如何工作的呢?class driver主要將系統定義的一些標準IO操作如IRP_MJ_READ等轉化成特定類別裝置的私人IOCTL,然後調用相應的miniport driver。如對於SCSI匯流排上的cdrom,cdrom會將IRP_MJ_READ轉化成一個SCSI命令調用系統提供的miniport driver,我底下會用一個具體的例子說明。既然class driver只是調用miniport driver,那為什麼又要引入port driver的概念呢?我們知道scsi匯流排控制器的類別很多,而如果每種控制器都從頭開始設計一個driver,那麼實現這樣的一個driver則將是一個多麼困難的事情。所以Microsoft引入了port driver的概念。例如由SCSI port driver來實現所有SCSI共同的內容,miniport只實現特定的SCSI控制器或是SCSI裝置等內容,共有的部分只要調用port driver提供的服務即可。如miniport driver aha154x.sys實現Adaptec AHA-154x系列SCSI控制器。而她的任務只是處理SRB((SCSI request block,含有Command descriptor block,即CDB,具體請參閱SCSI標準),其他的細節問題(如同步等等均由port driver scsiport.sys完成)。class/port/miniport模型在2000/XP中處處存在,如disk.sys是磁碟類driver,而pciidex.sys是IDE系統的port driver等等。miniport通過調用port driver匯出的函數等來實現其功能的,這兒其實又有dll複用的內容了。

    需要指出的是class/port/miniport不是嚴格上的獨立體,也就是說並不都意味著這些有嚴格的區分,嚴格的由三個.sys來分別實現相應的功能。如atapi.sys則集合了port與miniport的功能,她用來服務基於ATAPI(使用SCSI命令)的IDE裝置。2000/XP中的網路裝置、網路通訊協定等網路驅動程式從嚴格的意義上講也可以說是class/port/miniport的驅動模型,雖然她們有一套自己的術語,如NDIS Intermediate Drivers、NDIS Protocol Drivers與NDIS Miniport Drivers等等(用於實現OSI的7層模型)。我更願意將ndis.sys理解成class/port的集合,而其餘NDIS Miniport Drivers則是miniport driver。

    學習class/port/miniport最好的途徑就是通過學習原始碼。上面提到的disk.sys/cdrom.sys/tape.sys/classpnp.sys/aha154x.sys在DDK中Microsoft都提供了原始碼。class driver通常通過IOCTL調用miniport driver。port driver通常通過Driver相關的一塊記憶體地區來維護其對miniport driver的資訊的(如建立的DEVICE_OBJECT等等)。這塊記憶體地區是port driver相關的(也即同一子類的class裝置如disk.sys/cdrom.sys/tape.sys互不干擾),這兒我借用TLS(Thread Local Storage)的概念,TLS是線程相關的。在《 解讀Windows 2000/XP分層驅動模型》中我介紹了使客戶(這裡是miniport)可以使用IoAllocateDriverObjectExtension分配一塊記憶體,由目的driver(這裡是scsiport.sys)的DRIVER_OBJECT的DriverExtenion的ClientDriverExtension指向。不管是scsiport.sys或是ndis.sys都這樣來組織miniport專有資訊。

    既然文頭提到COM,我這兒插入一個題外話,COM使用CoInitialize(Ex)來初始化COM Execute Context(Apartment),實際上CoInitialize(Ex)也使用TEB(線程環境塊)的ReservedForOle欄位指向在堆中分配的一塊記憶體用於支援COM執行環境。在XP SP1中這個欄位的位移值為0xf80。這樣的概念與IoAllocateDriverObjectExtension分配driver相關的記憶體應該是一樣的,只不過前者使用FS寄存器查當然線程的TEB中的Ole資訊,而後者則使用IoGetDriverObjectExtension來擷取DRIVER_OBJECT中的DriverExtenion資訊的ClientDriverExtension而已。

    說了這麼多class/port/miniport的概念,實在仍是非常的抽象。我們通過一個例子來說明可能會更好的理解。這裡要用虛擬光碟機這一類別的工具來說明,我們知道虛擬光碟機軟體通常使用SCSI Miniport來實現,我們這兒通過cdrom.sys/scsiport.sys/fakecd.sys這樣一個class/port/miniport模型來學習。其中class driver與port driver都是由OS提供的。fakecd.sys是我實現的一個SCSI miniport driver。具體請參閱《FakeCD For Windows 2000/XP》。《FakeCD For Windows 2000/XP》介紹的Copystar FANTOM DVDROM、 Daemon Tools、Virtual CD與fakecd.sys都一樣,都是SCSI miniport port,都通過port driver scsiport.sys提供服務的。

    下面我以我機子上(同時裝有一個物理光碟機、FakeCD與Daemon Tools)的情況來觀察:

    kd> !devstack cdrom0
      !DevObj   !DrvObj            !DevExt   ObjectName
      ffaa5020  /Driver/redbook    ffaa50d8  
    > ffaa69e0  /Driver/Cdrom      ffaa6a98  CdRom0
      81340d78  /Driver/ACPI       8135d978  00000063
      813418e8  /Driver/atapi      813419a0  IdeDeviceP1T0L0-e
    !DevNode 812fd700 :
      DeviceInst is "IDE/CdRomMITSUMI_CD-ROM_SR243T___________________L02G____/5&18b54618&0&0.0.0"
      ServiceName is "cdrom"
    kd> !devstack cdrom1
      !DevObj   !DrvObj            !DevExt   ObjectName
      ff8bfa60  /Driver/redbook    ff8bfb18  
    > ff8bf030  /Driver/Cdrom      ff8bf0e8  CdRom1
      8133b030  /Driver/Stlth317   8133b0e8  Stlth3171Port0Path0Target0Lun0
    !DevNode 8133b850 :
      DeviceInst is "SCSI/CdRom&Ven_V386&Prod_STEALTH_DVD&Rev_1.0h/1&2afd7d61&0&000"
      ServiceName is "cdrom"
    kd> !devstack cdrom6
      !DevObj   !DrvObj            !DevExt   ObjectName
    > ff5fbac8  /Driver/Cdrom      ff5fbb80  CdRom6
      ff4c9a38  /Driver/FakeCD     ff4c9af0  FakeCD1Port3Path0Target0Lun0
    !DevNode ff9c68a0 :
      DeviceInst is "SCSI/CdRom&Ven_WebCrazy&Prod_WebCrazy_FakeCD&Rev_1.00/1&1843ccbc&0&000"
      ServiceName is "cdrom"

    這裡windbg列出Cdrom0、Cdrom1與Cdrom6分別用於服務物理光碟機與Daemon Tools與FakeCD的虛擬光碟機。他們都是由/Driver/Cdrom(即class driver cdrom.sys)驅動建立的對象,且位於驅動棧的頂層(redbook只是一個Filter driver用於實現有關Audio的功能,這裡不加以考慮),這樣層現給IO管理器的只是一個“CDROM”,而不管底層具體是物理光碟機(位於IDE匯流排上),還是虛擬光碟機(位於虛擬SCSI匯流排上)。這即是class driver的作用,實際上這兒與檔案系統的互動也由class driver實現,所以FakeCD也不用考慮File System,也就是說對於ISO檔案等的格式我在FakeCD中沒有一行代碼。這點很多朋友來信詢問,在此一併予以回答。

    共同實現port/miniport功能的atapi.sys的Cdrom0用於服務物理光碟機(ATAPI IDE),這裡也就比較容易理解了。對於虛擬SCSI匯流排的光碟機如Cdrom1,Cdrom6,裝置棧底層的miniport driver,由port driver scsiport.sys的提供服務,換句話說這兒port driver只是提供一個環境(正像ole32.dll的作用對於COM一樣)。cdrom.sys轉換標準IRP為SCSI的SRB(CDB)然後使用IOCTL調用下層的Miniport完成IO請求。實際上miniport一般調用port driver提供的常式來產生Device對象,如scsiport.sys提供ScsiPortInitialize、所以port driver總知道自己管理的裝置資訊。實際上port driver在2000/XP下一般都會向miniport driver開發人員隱藏使用Device Object,IRP等。而由miniport driver提供callback函數來完成操作,簡化開發人員的工作。

    讓我們繼續看看Fakecd.sys驅動對象的內容:

    kd> !drvobj fakecd 2
    Driver object (ff3d5208) is for:
     /Driver/FakeCD
    DriverEntry:   f9a50466
    DriverStartIo: f94930c4 SCSIPORT!ScsiPortStartIo
    DriverUnload:  f949d3e0 SCSIPORT!ScsiPortUnload

    Dispatch routines:
    [00] IRP_MJ_CREATE                      f9490436 SCSIPORT!ScsiPortGlobalDispatch
    [01] IRP_MJ_CREATE_NAMED_PIPE           804f986f nt!IopInvalidDeviceRequest
    [02] IRP_MJ_CLOSE                       f9490436 SCSIPORT!ScsiPortGlobalDispatch
    [03] IRP_MJ_READ                        804f986f nt!IopInvalidDeviceRequest
    [04] IRP_MJ_WRITE                       804f986f nt!IopInvalidDeviceRequest
    [05] IRP_MJ_QUERY_INFORMATION           804f986f nt!IopInvalidDeviceRequest
    [06] IRP_MJ_SET_INFORMATION             804f986f nt!IopInvalidDeviceRequest
    [07] IRP_MJ_QUERY_EA                    804f986f nt!IopInvalidDeviceRequest
    [08] IRP_MJ_SET_EA                      804f986f nt!IopInvalidDeviceRequest
    [09] IRP_MJ_FLUSH_BUFFERS               804f986f nt!IopInvalidDeviceRequest
    [0a] IRP_MJ_QUERY_VOLUME_INFORMATION    804f986f nt!IopInvalidDeviceRequest
    [0b] IRP_MJ_SET_VOLUME_INFORMATION      804f986f nt!IopInvalidDeviceRequest
    [0c] IRP_MJ_DIRECTORY_CONTROL           804f986f nt!IopInvalidDeviceRequest
    [0d] IRP_MJ_FILE_SYSTEM_CONTROL         804f986f nt!IopInvalidDeviceRequest
    [0e] IRP_MJ_DEVICE_CONTROL              f9490436 SCSIPORT!ScsiPortGlobalDispatch
    [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     ffa408e8 +0xffa408e8
    [10] IRP_MJ_SHUTDOWN                    804f986f nt!IopInvalidDeviceRequest
    [11] IRP_MJ_LOCK_CONTROL                804f986f nt!IopInvalidDeviceRequest
    [12] IRP_MJ_CLEANUP                     804f986f nt!IopInvalidDeviceRequest
    [13] IRP_MJ_CREATE_MAILSLOT             804f986f nt!IopInvalidDeviceRequest
    [14] IRP_MJ_QUERY_SECURITY              804f986f nt!IopInvalidDeviceRequest
    [15] IRP_MJ_SET_SECURITY                804f986f nt!IopInvalidDeviceRequest
    [16] IRP_MJ_POWER                       f9490436 SCSIPORT!ScsiPortGlobalDispatch
    [17] IRP_MJ_SYSTEM_CONTROL              f9490436 SCSIPORT!ScsiPortGlobalDispatch
    [18] IRP_MJ_DEVICE_CHANGE               804f986f nt!IopInvalidDeviceRequest
    [19] IRP_MJ_QUERY_QUOTA                 804f986f nt!IopInvalidDeviceRequest
    [1a] IRP_MJ_SET_QUOTA                   804f986f nt!IopInvalidDeviceRequest
    [1b] IRP_MJ_PNP                         f9a503ba fakecd!FakeCDPnp

    非常明顯對於SCSI miniport提供的driver入口,不管是StartIo,Unload還是IRP Dispatch函數都是由scsiport.sys提供的(為了提供充分的靈活,IRP_MJ_PNP入口被fakecd.sys miniport driver替換了用於實現動態實現CDROM個數的增減)。

    本文只是從應用的角度討論了class/port/miniport的模型,對於這個模型的理解以及如何?類似的機制實際上只是一個最最為基礎的軟體複用的概念(當然加入了編寫裝置驅動的一些特色,如與硬體裝置的耦合考慮等)。這樣一個模型相對於使用者態的COM實現二進位層級的複用技術相對簡單的多。只是因為他們位於核心態,編寫容易Blue Screen,才被大家認識的不夠,本文只是希望為你做一個引導而已,在我看來,實在是沒有什麼特別的內容。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.