您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 管理学资料 > 虚拟设备驱动程序设计中的两个关键问题
虚拟设备驱动程序设计中的两个关键问题在虚拟设备驱动程序(VxD)的设计中,两个尤为关键,且又令人困扰的问题是VxD的虚拟化和VxD与应用程序间的通信机制。下面,对这两个问题作一详细的探讨。一、VxD的虚拟化由于Windows允许同时运行多个任务,所以出现多个进程试图同时访问同一物理设备的情况时,如果多个应用程序通过同一个DLL驱动程序(注意和虚拟设备驱动程序VxD的区别)访问设备,不需要对该设备虚拟化,驱动程序使之顺序访问;如果是多个Windows应用程序对相同设备同时访问,由于都运行于SystemVM(系统虚拟机),所以也不需要虚拟化,它们的访问将由一个驱动程序(WindowsdriverDLL)进行检测并使之串行化,而不是依靠VxD;如果多个VM试图访问同一设备,由于DOS应用程序能够直接操纵硬件,所以必须对该设备进行虚拟化,一个虚拟化设备的VxD负责可靠地检测多个VM试图访问同一设备的情况,并采取仲裁的策略来解决这种冲突。这里可能有以下几种解决方案:1、允许一个VM访问物理设备,同时忽略其它的VM。这是最简单的虚拟化形式。如VPD(VirtualPrinterDevice)。2、允许一个VM访问物理设备,同时为其它的VM虚拟化设备。如VKD(VirtualKeyboardDevice)分配给一个VM,并使之获得物理键盘的访问权(包括键盘中断在内),对其它的VM而言,VKD只向它们提供一个空的键盘缓冲区。3、允许多个VM共享同一物理设备。尽管存在假象,但从VM的观点来看,这种方法与独享访问一样。如VDD(VirtualDisplayDevice),使每一个Windows环境下的DOSVM认为是直接写入显存,其实只是被VDD映射到了一个窗口的缓冲区。4、VxD独立访问物理设备的同时,允许一个VM访问虚拟设备,这是最复杂的虚拟化形式。如VCD(VirtualComDevice),VCD缓冲区接收串行数据并通过映射中断透明地传给相应的一个VM,VM在中断处理过程中读取串口数据寄存器,这些数据的实质是VCD缓冲区已经接收的数据。与物理设备一样,硬件中断很多时候也必须虚拟化,这种情况更为复杂。虚拟化中断实质上就是将硬件产生的中断映射到需要它的每一个VM(不管该VM是否正在运行),替代VxD进行服务。在这里我们给出一个虚拟化中断的VxD实例的几个重要回调过程,并采用最简单的仲裁策略来解决访问冲突(见程序1)。typedefstruct{IRQHANDLEIrqHandle;VMHANDLEVMOwner;CharDeviceName[8];BOOLbVMIsServicing;}DEVICE_CONTEXT;void_stdcallMaskChangHandler(VMHANDLEhVM,IRQHANDLEhIRQ,BOOLbMasking)//当一个VM在中断控制器中屏蔽或打开中断hIRQ时,VPICD调用该过程{if(!bMasking)//若为打开中断{if(!device.VMOwner){device.VMOwner=hVM;//若无任何VM占有该中断,则将该中断的拥有权设为当前VM}else{if(device.VMOwner!=hVM){device.VMOwner=SHELL_Resolve_Contention(device.VMOwner,hVM,device.DeviceName);//若已有VM占有该中断,则用户可通过对话框在两者间作出选择}}VPICD_Physically_Unmask(hIRQ);//打开该物理中断}else{device.VMOwner=0;VPICD_Physically_Mask(hIRQ);//屏蔽该物理中断}}BOOL_stdcallHwIntHandler(VMHANDLEhVM,IRQHANDLEhIRQ)//当中断hIRQ发生,VPICD立即调用该过程{if(device.VMOwner&&!device.bVMIsServicing)//若有VM占有该中断并且不在上一次的中断处理中{VPICD_Set_Int_Request(device.VMOwner,hIRQ);//请见本例程后的讨论}else{......}returnTRUE;}void_stdcallVirtIntHandler(VMHANDLEhVM,IRQHANDLEhIRQ)//当VPICD每次向VM模拟中断时,调用该过程{device.bVMIsServicing=TRUE;//设置中断处理标志}void_stdcallIRETHandler(VMHANDLEhVM,IRQHANDLEhIRQ)//当从VM的中断处理返回,执行该回调{device.bVMIsServicing=FALSE;//清除中断处理标志}(程序1)由于中断是异步产生的,所以当VxD调用VPICD(虚拟可编程中断控制器)服务VPICD_Set_Int_Request将该中断映射到VM时,该VM应处于执行状态。(1)在映射的第一步,VPICD通过调用VMM(虚拟机管理器)服务Call_Priority_VM_Event强制调度所希望的VM,使用最高的优先权(Time_Critical_Boost);(2)VPICD提供一个该服务的回调,所以当VM被调度运行时,VMM即可通知VPICD;(3)然后VPICD通过调用另一个VMM服务Simulate_Int来调整VM的运行环境。该服务将VM的CS、IP和标志寄存器压入VM的堆栈,从VM的中断向量表IVT取出新的CS、IP和标志寄存器,并且清除中断标志;(4)当VPICD从回调返回,并且VMM变回V86模式时,VM便立即执行已向VPICD注册的中断处理过程。编写虚拟化设备的VxD与编写非虚拟化设备的VxD有很大的不同,主要是它要用到一组完全不同的VMM和VxD服务。实际上,现在很多为新设备所编写的VxD根本就不再虚拟化,因为并没有DOS或Windows应用程序直接访问这些硬件。二、VxD与应用程序间的通信机制由于VxD并不仅仅处理硬件,所以在大多数情形下,VxD还向应用程序提供一个接口。通过该接口,应用程序就能够做与硬件有关的事情了。Windows9x具有VxD与应用程序双向通信的机制。下面叙述的应用程序均指Win32应用程序。应用程序到VxD的通信机制是:VxD并不象Win16应用程序接口那样输出一个特殊的API过程(保护模式API过程或V86模式API过程)来支持应用程序,取而代之的是它的控制过程必须能够处理一个特殊的消息:W32_DEVICEIOCONTROL。VMM代替调用DeviceIoControl函数的应用程序向VxD发送此消息。消息参数可确定VxD消息响应函数、输入输出缓冲区指针及缓冲区大小,并绑定在DIOCPARAMETERS结构中。通过这一接口,不仅仅可以读写设备,而且还能在应用程序和VxD之间互传指针,从而达到特殊应用的目的。有时只需调用应用程序与VxD间的接口,便能及时获得所需信息和服务。但还有一些特殊情况,必须由VxD异步通知应用程序,这就需要用到VxD到应用程序的通信机制。VxD到应用程序的接口关系要比应用程序到VxD的接口关系复杂得多。其间有两种调用方法:一种是使用PostMessage函数。通过调用这一由外壳VxD(SHELLVxD)提供的新服务,便可通知应用程序;另一种是使用特殊的Win32技术。这种技术的独到之处在于Win32API支持多线程。在Win32技术中,尽管采用的APC(AsynchronousProcedureCalls)异步过程调用机制和Win32事件机制都依赖于唤醒一个Win32应用程序线程,但仍略有不同。VxD到应用程序最简单的通信机制就是通过APC,这种方法对应用程序和VxD相对要简单一些。应用程序首先动态加载VxD(CreateFile),并用DeviceIoControl将回调函数的地址传给VxD,然后应用程序执行Win32调用SleepEx将其自身置为“挂起”(asleepyetalertable)状态时。当应用程序处于“挂起”状态,VxD能够通过VWIN32VxD提供的QueueUserApc服务调用应用程序的回调函数。另一种更有效的方法是使用Win32事件机制。如果应用程序运行多个线程,当子线程等待着VxD来唤醒它的同时,主线程能够继续做自己的工作。例如,当一个子线程在等待VxD缓存接收的数据时,主线程可同时监控用户的输入。一旦缓冲区达到门限,VxD将唤醒等待的子线程。对于线程间的通知,VxD使用线程事件,就象应用程序的多线程机制所做的那样。在Windows95下,VxD可访问与多线程应用程序非常相同的一些Win32事件API(由VWIN32VxD提供)。这些VWIN32事件服务包括:_VWIN32_ResetWin32Event、_VWIN32_SetWin32Event、_VWIN32_PulseWin32Event、_VWIN32_WaitSingleObject、_VWIN32_WaitMultipleObjects。利用这些服务,VxD可唤醒一个等待的Win32应用程序线程,或是等待被一个Win32应用程序线程唤醒。不幸的是VxD不只是通过简单调用相应的事件服务,就能够获得Win32事件的句柄。因此,为获得Win32事件的句柄要涉及到一个复杂的过程和一个未公布的系统调用。事件通常是由应用程序产生(Win32APICreateEvent),然后使用未公布的Win32API函数OpenVxDHandle将获得的事件句柄转换为VxD事件句柄,再通过DeviceIoControl将这一ring0级事件句柄传给VxD,于是VxD便可将其作为VWIN32事件函数的参数来使用。因为Windows采用基于消息的事件驱动机制,而VxD并不提供直接发往应用程序线程的消息,所以PostMessage所发消息与其它众多的消息都在主线程的消息循环中处理。这样,当执行一些界面操作时,大量的消息占据了消息队列,VxD所发送的消息就有可能得不到相应的处理。为解决这一问题,在实际设计中可采用的方法有两种:第一种是仍采用PostMessage,但在应用程序和VxD中需设置标志位,判断消息是否被处理并作了相应的工作(如重传数据);第二种是使用Win32事件机制,将一个线程专用于等待响应Win32事件,而另一些线程用于其它处理。下面给出VxD利用Win32事件机制激活Win32应用程序线程的部分例程(见程序2)。当生成或消除(destroy)一个VM,VxD便通知注册的应用程序,并显示出相应的信息。在VxD中,DWORDOnW32Deviceiocontrol(PDIOCPARAMETERSp)//VxD与Win32应用程序的接口函数{DWORDrc;swirch(p-dwIoControlCode){caseDIOC_OPEN://系统定义功能号:设备打开rc=0;break;caseDIOC_CLOSEHANDLE://设备关闭bClientRegistered=FALSE;rc=0;break;caseEVENTVXD_REGISTER://自定义功能号hWin32Event=p-lpvInBuffer;*((DWORD*)(p-lpvOutBuffer))=(DWORD)&GlobalVMInfo;*((DWORD*)(p-lpcbBytesReturned))=sizeof(DWORD);bClientRegistered=TRUE;rc=0;break;default:rc=0xffffffff;}returnrc;//若返回0表示成功}BOOLOnVmInit(VMHANDLEhVM)//一旦有VM被初始化便执行{if(bClientRegistered){GlobalVMInfo.hVM=hVM;GlobalVMInfo.bVmCreated=TRUE;Call_Priority_VM_Event(LOW_PRI_
本文标题:虚拟设备驱动程序设计中的两个关键问题
链接地址:https://www.777doc.com/doc-1315251 .html