虛擬設(shè)備驅(qū)動(dòng)程序的設(shè)計(jì)與完成
發(fā)表時(shí)間:2023-08-02 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]陳國(guó)友 由于Windows對(duì)系統(tǒng)底層操作采取了屏蔽的策略,因而對(duì)用戶而言,系統(tǒng)變得更為安全,但這卻給眾多的硬件或者系統(tǒng)軟件開發(fā)人員帶來了不小的困難,因?yàn)橹灰獞?yīng)用中涉及到底層的操作,開發(fā)人員就不得...
陳國(guó)友
由于Windows對(duì)系統(tǒng)底層操作采取了屏蔽的策略,因而對(duì)用戶而言,系統(tǒng)變得更為安全,但這卻給眾多的硬件或者系統(tǒng)軟件開發(fā)人員帶來了不小的困難,因?yàn)橹灰獞?yīng)用中涉及到底層的操作,開發(fā)人員就不得不深入到Windows的內(nèi)核去編寫屬于系統(tǒng)級(jí)的虛擬設(shè)備驅(qū)動(dòng)程序。Win 98與Win 95設(shè)備驅(qū)動(dòng)程序的機(jī)理不盡相同,Win 98不僅支持與Windows NT 5.0兼容的WDM(Win32 Driver Mode)模式驅(qū)動(dòng)程序,而且還支持與Win 95兼容的虛擬設(shè)備驅(qū)動(dòng)程序VxD(Virtual Device Driver)。下面介紹了基于Windows 9x平臺(tái)的虛擬環(huán)境、虛擬設(shè)備驅(qū)動(dòng)程序VxD的基本原理和設(shè)計(jì)方法,并結(jié)合開發(fā)工具VToolsD給出了一個(gè)為可視電話音頻卡配套的虛擬設(shè)備驅(qū)動(dòng)程序VxD的設(shè)計(jì)實(shí)例。
1.Windows 9x的虛擬環(huán)境
Windows 9x作為一個(gè)完整的32位多任務(wù)操作系統(tǒng),它不像Window 3.x那樣依賴于MS-DOS,但為了保證軟件的兼容性,Windows 9x除了支持Win16應(yīng)用程序和Win32應(yīng)用程序之外,還得支持MS-DOS應(yīng)用程序的運(yùn)行。Windows 9x是通過虛擬機(jī)VM(Virtual Machine)環(huán)境來確保其兼容和多任務(wù)特性的。
所謂Windows虛擬機(jī)(通常簡(jiǎn)稱為Windows VM)就是指執(zhí)行應(yīng)用程序的虛擬環(huán)境,它包括MS-DOS VM和System VM兩種虛擬機(jī)環(huán)境。在每一個(gè)MS-DOS VM中都只運(yùn)行一個(gè)MS-DOS進(jìn)程,而System VM能為所有的Windows應(yīng)用程序和動(dòng)態(tài)鏈接庫(kù)DLL(Dynamic Link Libraries)提供運(yùn)行環(huán)境。每個(gè)虛擬機(jī)都有獨(dú)立的地址空間、寄存器狀態(tài)、堆棧、局部描述符表、中斷表狀態(tài)和執(zhí)行優(yōu)先權(quán)。雖然Win16、Win32應(yīng)用程序都運(yùn)行在System VM環(huán)境下,但Win16應(yīng)用程序共享同一地址空間,而Win32應(yīng)用程序卻有自己獨(dú)立的地址空間。
在編寫應(yīng)用程序時(shí),編程人員經(jīng)常忽略虛擬環(huán)境和實(shí)環(huán)境之間的差異,一般認(rèn)為虛擬環(huán)境也就是實(shí)環(huán)境。但是,在編寫虛擬設(shè)備驅(qū)動(dòng)程序VxD時(shí)卻不能這樣做,因?yàn)閂xD的工作是向應(yīng)用程序代碼提供一個(gè)與硬件接口的環(huán)境,為每一個(gè)客戶虛擬機(jī)管理虛設(shè)備的狀態(tài),透明地仲裁多個(gè)應(yīng)用程序,同時(shí)對(duì)底層硬件進(jìn)行訪問。這就是所謂虛擬化的概念。
VxD在虛擬機(jī)管理器VMM(Virtual Machine Manager)的監(jiān)控下運(yùn)行,而VMM實(shí)際上是一個(gè)特殊的VxD。VMM執(zhí)行與系統(tǒng)資源有關(guān)的工作,提供虛擬機(jī)環(huán)境(能產(chǎn)生、調(diào)度、卸載VM)、負(fù)責(zé)調(diào)度多線程占先時(shí)間片及管理虛擬內(nèi)存等工作。VxD與VMM運(yùn)行在其他任何虛擬機(jī)之外,VxD事實(shí)上就是實(shí)現(xiàn)虛擬機(jī)的軟件的一部分。
與大多數(shù)操作系統(tǒng)一樣,Windows也是采用層次式體系結(jié)構(gòu)。VMM和VxDs構(gòu)成了Win 95的ring0級(jí)的系統(tǒng)核心(應(yīng)用程序運(yùn)行在ring3級(jí),ring1、ring2級(jí)未被使用),具有系統(tǒng)的最高優(yōu)先權(quán)。Windows還提供一些以"drv"為后綴名的驅(qū)動(dòng)程序,主要是指串行口的通信程序和并行口的打印機(jī)程序。這些程序與VxD不同,它們是運(yùn)行在ring3級(jí)上的。圖1可以使你更好地理解Windows的虛擬環(huán)境。
圖
2.深入理解VMM和VxD
如前所述,VxD是Virtual Device Driver的縮寫,但有人將它理解為虛擬任何驅(qū)動(dòng)程序。實(shí)際上,VxD并非僅指那些虛擬化的某一具體硬件的設(shè)備驅(qū)動(dòng)程序。比如某些VxD能夠虛擬化設(shè)備,而某些VxD作為設(shè)備驅(qū)動(dòng)程序卻并不虛擬化設(shè)備,還有些VxD與設(shè)備并沒有什么關(guān)系,它僅向其他的VxD或是應(yīng)用程序提供服務(wù)。
VxD可以隨VMM一起靜態(tài)加載,也可以根據(jù)需要?jiǎng)討B(tài)加載或卸載。正是由于VxD與VMM之間的緊密協(xié)作,才使得VxD具有了應(yīng)用程序所不具備的能力,諸如可以不受限制地訪問硬件設(shè)備、任意查看操作系統(tǒng)數(shù)據(jù)結(jié)構(gòu)(如描述符表、頁(yè)表等)、訪問任何內(nèi)存區(qū)域、捕獲軟件中斷、捕獲I/O端口操作和內(nèi)存訪問等,甚至還可以截取硬件中斷。
盡管VxD使用32位平面存儲(chǔ)模式(flat memory model),但它的代碼和數(shù)據(jù)仍使用分段管理,段有六種類型,即實(shí)模式初始化、保護(hù)模式初始化、可分頁(yè)、不可分頁(yè)、靜態(tài)和只調(diào)試(debug only),每種類型又有代碼段和數(shù)據(jù)段之分,所以VxD共有12個(gè)段。實(shí)模式代碼段和數(shù)據(jù)段為16位(分段模式),其他段則是32位(平面模式)。“實(shí)模式初始化”段包含了在Windows初始化過程的最初階段VMM變?yōu)楸Wo(hù)模式之前要執(zhí)行的代碼。靜態(tài)加載的VxD此時(shí)可以查看Windows啟動(dòng)前的實(shí)模式環(huán)境,決定是否繼續(xù)加載,并通知VMM。加載完畢后,VMM進(jìn)入保護(hù)模式并執(zhí)行保護(hù)模式初始化代碼,同樣將執(zhí)行結(jié)果再通知VMM。初始化完成后,“實(shí)模式初始化”段和“保護(hù)模式初始化”段即被遺棄。VxD的大部分代碼都在其他的某一段中,“可分頁(yè)”段允許虛擬存儲(chǔ)管理器(Virtual Memory Manager)進(jìn)行分頁(yè)管理,大多數(shù)的VxD代碼都應(yīng)當(dāng)在“可分頁(yè)”段!安豢煞猪(yè)”段的內(nèi)容主要包括:VxD的主入口點(diǎn)、硬件中斷處理函數(shù)、所訪問的數(shù)據(jù)以及能被另一個(gè)VxD中斷處理函數(shù)調(diào)用的異步服務(wù)。“靜態(tài)”段僅用于可以動(dòng)態(tài)加載的VxD,當(dāng)VxD卸載后,靜態(tài)代碼段和數(shù)據(jù)段都保留在內(nèi)存中。“只調(diào)試”段只是VMM在Soft-ICE for Win 95等調(diào)試環(huán)境下才將其載入。
VMM是通過VxD的設(shè)備描述符塊DDB(Device Descriptor Block)來識(shí)別的。DDB向VMM提供了VxD的主入口點(diǎn),還向應(yīng)用程序和其他的VxD提供了入口點(diǎn)。VMM利用這個(gè)主入口點(diǎn)將VM及Windows自身的狀態(tài)通知給VxD,然后VxD通過相應(yīng)的工作來響應(yīng)這些事件。由于VxD不僅僅服務(wù)于一個(gè)物理設(shè)備(比如多個(gè)串口)或僅與一個(gè)VM發(fā)生聯(lián)系,所以VxD需要產(chǎn)生自己支持的數(shù)據(jù)結(jié)構(gòu)(Supporting Data Structures)來保存每一個(gè)設(shè)備、每一個(gè)VM的配置和狀態(tài)信息。VxD用一個(gè)或多個(gè)設(shè)備上下文結(jié)構(gòu)來保存設(shè)備信息,如I/O端口基地址、中斷向量等,VxD將自己的每個(gè)VM的狀態(tài)信息保存在VMM的VM控制塊中。
VMM提供的服務(wù)包括:事件服務(wù)、內(nèi)存管理服務(wù)、兼容執(zhí)行和保護(hù)模式執(zhí)行的服務(wù)、登錄表服務(wù)、調(diào)度程序服務(wù)、同步服務(wù)、調(diào)試服務(wù)、I/O捕獲服務(wù)、處理錯(cuò)誤和中斷服務(wù)、VM中斷和回調(diào)服務(wù)、配置管理程序服務(wù)以及其他雜項(xiàng)服務(wù)。
以上內(nèi)容僅涉及到VxD設(shè)計(jì)的一小部分,作為VxD的開發(fā)人員必須掌握更多的知識(shí)。首先是操作系統(tǒng)的知識(shí),如地址空間、執(zhí)行上下文、資源加鎖、進(jìn)程間通信和異步事件處理等方面的知識(shí);其次,對(duì)Intel處理器應(yīng)有較深入的理解,包括寄存器、機(jī)器指令集、保護(hù)機(jī)制、分頁(yè)機(jī)制,以及虛擬8086模式;最后,還必須熟悉VMM提供的各類服務(wù)和接口,熟悉Windows其他的系統(tǒng)VxD。
3.開發(fā)工具VToolsD簡(jiǎn)介
VToolsD是專門用于開發(fā)VxD程序的一種工具軟件,它包括VxD框架代碼生成器QuickVxD、C運(yùn)行庫(kù)、VMM/VxD服務(wù)庫(kù)、VxD的C++類庫(kù)、VxDLoad和VxDView等實(shí)用工具以及大量的C、C++例程。由VC++、BC++的32位編譯器編譯生成的VxD程序可以脫離VToolsD環(huán)境運(yùn)行。
利用QuickVxD可以方便、快捷地生成VxD的框架,即生成后綴名為h、cpp和mak的三個(gè)文件。源文件包含了運(yùn)行VxD的基本組件,其中包含控制消息處理、API入口點(diǎn)、以及VxD服務(wù)等函數(shù)框架,并且還定義了標(biāo)志,設(shè)置了編譯參數(shù),聲明了類,然后在C++環(huán)境下,向生成的各個(gè)處理函數(shù)體內(nèi)添加自己的代碼,最后使用編譯器NMAKE生成標(biāo)準(zhǔn)的VxD程序。
由于VxD運(yùn)行在ring0級(jí),所以調(diào)試程序相當(dāng)困難。我使用的調(diào)試工具是Soft-ICE for Win 95。
目前VToolsD的最新版本為3.0,它支持設(shè)備訪問體系結(jié)構(gòu)DAA(Device Access Architecture),所編寫的程序代碼將可以在所有Windows平臺(tái)(包括Win 95、Win 98以及Windows NT)上共享。當(dāng)然也可以使用Microsoft公司的DDK(Device Developer Kit)來開發(fā)VxD,但DDK不能像VToolsD那樣通過屏蔽系統(tǒng)及VxD的底層技術(shù)細(xì)節(jié)提供豐富的C運(yùn)行庫(kù)和C++類庫(kù),而是讓開發(fā)人員充分享用面向?qū)ο缶幊谭椒ǖ姆奖闩c快捷,因此僅就該點(diǎn)而言,使用DDK是不方便的。
4.VxD程序設(shè)計(jì)實(shí)例
我在開發(fā)可視電話音頻卡的設(shè)計(jì)過程中,用VToolsD 2.03、VC++ 5.0為自制的PC/XT總線擴(kuò)展卡開發(fā)了虛擬設(shè)備驅(qū)動(dòng)程序Audcard.vxd。該卡每20ms申請(qǐng)一次中斷,中斷由應(yīng)用程序動(dòng)態(tài)載入系統(tǒng)的Audcard.vxd響應(yīng)并加以處理。中斷服務(wù)程序ISR(Interrupt Service Routine)結(jié)束后,調(diào)用函數(shù)Shell_PostMessage( )向應(yīng)用程序窗口發(fā)送自定義消息。應(yīng)用程序接受消息后,再通過函數(shù)DeviceIoControl( )與VxD的接口函數(shù)OnW32DeviceIoControl( )互傳緩沖區(qū)數(shù)據(jù)。程序結(jié)束即可動(dòng)態(tài)卸載VxD。下圖表示在Win 95下VxD對(duì)硬件中斷的處理過程。
圖Win95下硬件中斷的處理過程
當(dāng)中斷發(fā)生時(shí),處理器轉(zhuǎn)換為ring0級(jí)保護(hù)模式。Windows系統(tǒng)并不像DOS那樣通過中斷描述符表IDT(Interrupt Descriptor Table)直接指向中斷處理過程,而是由IDT入口指向VMM中的程序。該程序?qū)⑴袛嗍欠駷橹袛嗾{(diào)用,如果是,則把中斷控制權(quán)交給虛擬可編程中斷控制器VPICD(Virtual Programmable Interrupt Controller Device),VPICD實(shí)際上是一個(gè)重要的VxD。VPICD再將其交給另一個(gè)注冊(cè)了該中斷的VxD(如Audcard.vxd)來處理。VxD程序是通過調(diào)用VPICD服務(wù)VPICD_Virtualize_IRQ來注冊(cè)中斷的。
虛擬設(shè)備驅(qū)動(dòng)程序Audcard.vxd的部分源代碼Audcard.h和Audcard.cpp在網(wǎng)上,網(wǎng)址為:www.pccomputing.com.cn。此應(yīng)用程序使用了下列函數(shù):CreateFile()動(dòng)態(tài)加載VxD、CloseHandle()并動(dòng)態(tài)卸載VxD、PreTranslateMessage()截獲消息、DeviceIoControl()與VxD互傳緩沖區(qū)數(shù)據(jù)。虛擬設(shè)備驅(qū)動(dòng)程序Audcard.vxd經(jīng)調(diào)試后工作正常,未發(fā)生過任何丟失數(shù)據(jù)或死機(jī)的現(xiàn)象。
下面是虛擬設(shè)備驅(qū)動(dòng)程序Audcard.vxd的部分源代碼Audcard.h和Audcard.cpp,限于篇幅,由QuickVxD自動(dòng)生成的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號(hào)中斷
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 DWORD OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams);
MyHwInt* pMyIRQ;
};
class AudcardVM : public VVirtualMachine
{
public:
AudcardVM(VMHANDLE hVM);
};
class AudcardThread : public VThread
{
public:
AudcardThread(THREADHANDLE hThread);
};
、贏udcard.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() //動(dòng)態(tài)加載時(shí)初始化
{
......//硬件初始化
pMyIRQ=new MyHwInt();
if(pMyIRQ&&pMyIRQ->hook()) //掛接中斷
{
pMyIRQ->physicalUnmask(); //允許中斷
return TRUE;
}
else return FALSE;
}
BOOL AudcardDevice::OnSysDynamicDeviceExit()
//動(dòng)態(tài)卸載過程
{
delete pMyIRQ;
return TRUE;
}
DWORD AudcardDevice::OnW32DeviceIoControl(PIOCTLPARAMS pDIOCParams)
//與Win32應(yīng)用程序的接口函數(shù)
{
......
}
VOID MyHwInt::OnHardwareInt(VMHANDLE hVM)
{
...... // 中斷處理
SHELL_PostMessage(AppWnd,WM_USER_POSTVXD ,0,0,0,NULL);
//向應(yīng)用程序窗口發(fā)送消息
sendPhysicalEOI(); //通知VPICD中斷結(jié)束
}
(作者地址:南京通信工程學(xué)院98信箱 210016 收稿日期:1998.12.03)