虛擬裝置驅動程式的設計與實現 (轉)

gugu99發表於2008-05-19
虛擬裝置驅動程式的設計與實現 (轉)[@more@] 虛擬裝置的設計與實現
  由於對底層操作採取了遮蔽的策略,因而對而言,系統變得更為,但這卻給眾多的或者系統開發人員帶來了不小的困難,因為只要應用中涉及到底層的操作,開發人員就不得不深入到Windows的核心去編寫屬於系統級的虛擬裝置驅動程式。Win
  98與Win 95裝置驅動程式的機理不盡相同,Win 98不僅支援與 5.0相容的WDM(
  Mode)驅動程式,而且還支援與Win 95相容的虛擬裝置驅動程式VxD(Virtual Device
  Driver)。下面介紹了基於Windows
  9x平臺的虛擬環境、虛擬裝置驅動程式VxD的基本原理和設計方法,並結合開發工具VToolsD給出了一個為可視電話卡配套的虛擬裝置驅動程式VxD的設計例項。
 
  1.Windows 9x的虛擬環境
  Windows 9x作為一個完整的32位多工,它不像Window
  3.x那樣依賴於MS-DOS,但為了保證軟體的相容性,Windows
  9x除了支援Win16應用程式和Win32應用程式之外,還得支援MS-DOS應用程式的執行。Windows 9x是透過虛擬機器VM(Virtual
  Machine)環境來確保其相容和多工特性的。
  所謂Windows虛擬機器(通常簡稱為Windows
  VM)就是指應用程式的虛擬環境,它包括MS-DVM和System VM兩種虛擬機器環境。在每一個MS-DOS
  VM中都只執行一個MS-DOS程式,而System VM能為所有的Windows應用程式和動態連結庫DLL(Dynamic Link
  Libraries)提供執行環境。每個虛擬機器都有獨立的地址空間、暫存器狀態、堆疊、區域性描述符表、中斷表狀態和執行優先權。雖然Win16、Win32應用程式都執行在System
  VM環境下,但Win16應用程式共享同一地址空間,而Win32應用程式卻有自己獨立的地址空間。
 
  在編寫應用程式時,人員經常忽略虛擬環境和實環境之間的差異,一般認為虛擬環境也就是實環境。但是,在編寫虛擬裝置驅動程式VxD時卻不能這樣做,因為VxD的工作是嚮應用程式程式碼提供一個與硬體介面的環境,為每一個客戶虛擬機器管理虛裝置的狀態,透明地仲裁多個應用程式,同時對底層硬體進行訪問。這就是所謂虛擬化的概念。
 
  VxD在虛擬機器管理器VMM(Virtual Machine
  Manager)的下執行,而VMM實際上是一個特殊的VxD。VMM執行與系統資源有關的工作,提供虛擬機器環境(能產生、排程、解除安裝VM)、負責排程多執行緒佔先時間片及管理虛擬等工作。VxD與VMM執行在其他任何虛擬機器之外,VxD事實上就是實現虛擬機器的軟體的一部分。
 
  與大多數作業系統一樣,Windows也是採用層次式體系結構。VMM和VxDs構成了Win
  95的ring0級的系統核心(應用程式執行在ring3級,ring1、ring2級未被使用),具有系統的最高優先權。Windows還提供一些以"drv"為字尾名的驅動程式,主要是指口的通訊程式和並行口的印表機程式。這些程式與VxD不同,它們是執行在ring3級上的。圖1可以使你更好地理解Windows的虛擬環境。
 
  圖
  2.深入理解VMM和VxD
  如前所述,VxD是Virtual Device
  Driver的縮寫,但有人將它理解為虛擬任何驅動程式。實際上,VxD並非僅指那些虛擬化的某一具體硬體的裝置驅動程式。比如某些VxD能夠虛擬化裝置,而某些VxD作為裝置驅動程式卻並不虛擬化裝置,還有些VxD與裝置並沒有什麼關係,它僅向其他的VxD或是應用程式提供服務。
 
  VxD可以隨VMM一起靜態載入,也可以根據需要動態載入或解除安裝。正是由於VxD與VMM之間的緊密協作,才使得VxD具有了應用程式所不具備的能力,諸如可以不受限制地訪問硬體裝置、任意檢視作業系統資料結構(如描述符表、頁表等)、訪問任何記憶體區域、捕獲軟體中斷、捕獲I/O埠操作和記憶體訪問等,甚至還可以擷取硬體中斷。
 
  儘管VxD使用32位平面模式(flat memory
  model),但它的程式碼和資料仍使用分段管理,段有六種型別,即真實模式初始化、保護模式初始化、可分頁、不可分頁、靜態和只(de
  only),每種型別又有程式碼段和資料段之分,所以VxD共有12個段。真實模式程式碼段和資料段為16位(分段模式),其他段則是32位(平面模式)。“真實模式初始化”段包含了在Windows初始化過程的最初階段VMM變為保護模式之前要執行的程式碼。靜態載入的VxD此時可以檢視Windows啟動前的真實模式環境,決定是否繼續載入,並通知VMM。載入完畢後,VMM進入保護模式並執行保護模式初始化程式碼,同樣將執行結果再通知VMM。初始化完成後,“真實模式初始化”段和“保護模式初始化”段即被遺棄。VxD的大部分程式碼都在其他的某一段中,“可分頁”段允許虛擬儲存管理器(Virtual
  Memory
  Manager)進行分頁管理,大多數的VxD程式碼都應當在“可分頁”段。“不可分頁”段的內容主要包括:VxD的主入口點、硬體中斷處理、所訪問的資料以及能被另一個VxD中斷處理函式的非同步服務。“靜態”段僅用於可以動態載入的VxD,當VxD解除安裝後,靜態程式碼段和資料段都保留在記憶體中。“只除錯”段只是VMM在Soft-ICE
  for Win 95等除錯環境下才將其載入。
  VMM是透過VxD的裝置描述符塊D(Device Descriptor
  Block)來識別的。DDB向VMM提供了VxD的主入口點,還向應用程式和其他的VxD提供了入口點。VMM利用這個主入口點將VM及Windows自身的狀態通知給VxD,然後VxD透過相應的工作來響應這些事件。由於VxD不僅僅服務於一個物理裝置(比如多個串列埠)或僅與一個VM發生聯絡,所以VxD需要產生自己支援的資料結構(Supporting
  Data
  Structures)來儲存每一個裝置、每一個VM的和狀態資訊。VxD用一個或多個裝置上下文結構來儲存裝置資訊,如I/O埠基地址、中斷向量等,VxD將自己的每個VM的狀態資訊儲存在VMM的VM控制塊中。
 
  VMM提供的服務包括:事件服務、記憶體管理服務、相容執行和保護模式執行的服務、登入表服務、排程程式服務、同步服務、除錯服務、I/O捕獲服務、處理錯誤和中斷服務、VM中斷和回撥服務、配置管理程式服務以及其他雜項服務。
 
  以上內容僅涉及到VxD設計的一小部分,作為VxD的開發人員必須掌握更多的知識。首先是作業系統的知識,如地址空間、執行上下文、資源加鎖、程式間通訊和非同步事件處理等方面的知識;其次,對應有較深入的理解,包括暫存器、機器指令集、保護機制、分頁機制,以及虛擬8086模式;最後,還必須熟悉VMM提供的各類服務和介面,熟悉Windows其他的系統VxD。
 
  3.開發工具VToolsD簡介
 
  VToolsD是專門用於開發VxD程式的一種工具軟體,它包括VxD程式碼生成器QuickVxD、C執行庫、VMM/VxD服務庫、VxD的C++類庫、VxDLoad和VxDView等實用工具以及大量的C、C++例程。由VC++、BC++的32位編譯生成的VxD程式可以脫離VToolsD環境執行。
 
  利用QuickVxD可以方便、快捷地生成VxD的框架,即生成字尾名為h、cpp和mak的三個。原始檔包含了執行VxD的基本,其中包含控制訊息處理、入口點、以及VxD服務等函式框架,並且還定義了標誌,設定了編譯引數,宣告瞭類,然後在C++環境下,向生成的各個處理函式體內新增自己的程式碼,最後使用編譯器NMAKE生成標準的VxD程式。
 
  由於VxD執行在ring0級,所以除錯程式相當困難。我使用的除錯工具是Soft-ICE for Win 95。
 
  目前VToolsD的最新版本為3.0,它支援裝置訪問體系結構DAA(Device Access
  Architecture),所編寫的程式程式碼將可以在所有Windows平臺(包括Win 95、Win 98以及Windows
  NT)上共享。當然也可以使用公司的DDK(Device Developer
  Kit)來開發VxD,但DDK不能像VToolsD那樣透過遮蔽系統及VxD的底層技術細節提供豐富的C執行庫和C++類庫,而是讓開發人員充分享用面向程式設計方法的方便與快捷,因此僅就該點而言,使用DDK是不方便的。
 
  4.VxD例項
  我在開發可視電話音訊卡的設計過程中,用VToolsD 2.03、VC++
  5.0為自制的PC/XT匯流排擴充套件卡開發了虛擬裝置驅動程式Audcard.vxd。該卡每20ms申請一次中斷,中斷由應用程式動態載入系統的Audcard.vxd響應並加以處理。中斷服務程式ISR(Interrupt
  Service Routine)結束後,呼叫函式_PostMessage(
  )嚮應用程式視窗傳送自定義訊息。應用程式接受訊息後,再透過函式DeviceIoControl(
  )與VxD的介面函式OnW32DeviceIoControl( )互傳緩衝區資料。程式結束即可動態解除安裝VxD。下圖表示在Win
  95下VxD對硬體中斷的處理過程。
  圖Win95下硬體中斷的處理過程
 
  當中斷髮生時,處理器轉換為ring0級保護模式。Windows系統並不像DOS那樣透過中斷描述符表IDT(Interrupt
  Descriptor
  Table)直接指向中斷處理過程,而是由IDT入口指向VMM中的程式。該程式將判斷是否為中斷呼叫,如果是,則把中斷控制權交給虛擬可程式設計中斷控制器VPICD(Virtual
  Programmable Interrupt Controller
  Device),VPICD實際上是一個重要的VxD。VPICD再將其交給另一個註冊了該中斷的VxD(如Audcard.vxd)來處理。VxD程式是透過呼叫VPICD服務VPICD_Virtualize_IRQ來註冊中斷的。
 
  虛擬裝置驅動程式Audcard.vxd的部分Audcard.h和Audcard.cpp在網上,網址為:。此應用程式使用了下列函式:CreateFile()動態載入VxD、CloseHandle()並動態解除安裝VxD、PreTranslateMessage()截獲訊息、DeviceIoControl()與VxD互傳緩衝區資料。虛擬裝置驅動程式Audcard.vxd經除錯後工作正常,未發生過任何丟失資料或當機的現象。
 
  下面是虛擬裝置驅動程式Audcard.vxd的部分原始碼Audcard.h和Audcard.cpp,限於篇幅,由QuickVxD自動生成的Audcard.mak未列出。
 
  ①Audcard.h
  //AUDCARD.h - include file for VxD AUDCARD
 
  #include
  #define DEVICE_CLASS AudcardDevice
  #define
  AUDCARD_DeviceID UNDEFINED_DEVICE_ID
  #define AUDCARD_Init_Order
  UNDEFINED_INIT_ORDER#define AUDCARD_Major
  #define AUDCARD_Minor 0
 
  #define MY_IRQ 5 //定義5號中斷
  class MyHwInt:public VHardwareInt
 
  {
  public:
   MyHwInt():VHardwareInt(MY_IRQ,0,0,0){}
  
  virtual VOID OnHardwareInt(VMHANDLE);
  };
  class AudcardDevice :
  public VDevice
  {
  public:
   virtual BOOL
  OnSysDynamicDeviceInit();
   virtual BOOL OnSysDynamicDeviceExit();
 
   virtual D OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams);
 
   MyHwInt* pMyIRQ;
  };
  class AudcardVM : public
  VVirtualMachine
  {
  public:
   AudcardVM(VMHANDLE hVM);
 
  };
  class AudcardThread : public VThread
  {
   public:
 
   AudcardThread(THREADHANDLE hThread);
  };
  
 
  ②Audcard.cpp
  //AUDCARD.cpp - main module for VxD AUDCARD
 
  #define DEVICE_MAIN
  #include "audcard.h"
 
  Declare_Virtual_Device(AUDCARD)
  #define WM_USER_POSTVXD
  0x1000
  //自定義訊息
  #undef DEVICE_MAIN
 
  AudcardVM::AudcardVM(VMHANDLE hVM) : VVirtualMachine(hVM) {}
 
  AudcardThread::AudcardThread(THREADHANDLE hThread) :
  VThread(hThread) {}
  BOOL AudcardDevice::OnSysDynamicDeviceInit()
  //動態載入時初始化
  {
   ......//硬體初始化
   pMyIRQ=new MyHwInt();
 
  if(pMyIRQ&&pMyIRQ->hook()) //掛接中斷
  {
  
  pMyIRQ->physicalUnmask(); //允許中斷
   return TRUE;
   }
  
  else return FALSE;
  }
  BOOL
  AudcardDevice::OnSysDynamicDeviceExit()
  //動態解除安裝過程
  {
  
  delete pMyIRQ;
   return TRUE;
  }
  DWORD
  AudcardDevice::OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams)
 
  //與Win32應用程式的介面函式
  {
  ......
  }
  VOID
  MyHwInt::OnHardwareInt(VMHANDLE hVM)
  {
   ...... // 中斷處理
  
  SHELL_PostMessage(AppWnd,WM_USER_POSTVXD ,0,0,0,NULL);
  
  //嚮應用程式視窗傳送訊息
   sendPhysicalEOI(); //通知VPICD中斷結束
  }

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10748419/viewspace-1004278/,如需轉載,請註明出處,否則將追究法律責任。

相關文章