Two key issues in the virtual device driver (VXD) design

zhaozj2021-02-11  240

Two key problems in the virtual device driver (VXD), Chen Guoyou in the design of virtual equipment driver (VXD), two especially critical, and more troublesome is VXD virtualization and VXD and applications. Communication mechanism. Below, it is discussed in detail on these two issues. First, VXD virtualization Since Windows allows multiple tasks to be run at the same time, there are multiple processes to simultaneously access the same physical device, if multiple applications passed the same DLL driver (note and virtual device driver VXD) Difference) Access device, do not need to be virtualized to the device, the driver is sequentially accessed; if multiple Windows applications are accessible to the same device, because they are running on the System VM (System Virtual Machine), there is no need to virtual The access will be detected by a driver (Windows Driver DLL) and makes serialization instead of relying on VXD; if multiple VMs attempt to access the same device, because the DOS application can directly manipulate hardware, it must be The device performs virtualization, and the VXD of a virtualization device is responsible for reliably detecting a number of VM attempts to access the same device and take arbitration strategy to solve this conflict. There may be the following solutions here: 1, allowing a VM to access the physical device while ignoring other VMs. This is the simplest form of virtualization. Such as VPD (Virtual Printer Device). 2. Allow a VM to access the physical device while other VM virtualization devices. If VKD (Virtual Keyboard Device is assigned to a VM and gives it accessible to the access rights of the physical keyboard, including keyboard interrupts). For other VMs, VKD only provides an empty keyboard buffer. 3, allowing multiple VMs to share the same physical device. Although there is an illusion, this method is the same as exclusive access from the viewpoint of VM. Such as VDD (Virtual Display Device) makes DOS VM in each Windows environment considers direct writing to memory, in fact, is only mapped to a buffer of a window by VDD. 4, VXDs Allows to access physical devices while allowing a VM to access virtual devices, which is the most complex virtualization form. Such as VCD (Virtual COM DEVICE), the VCD buffer receives serial data and transmits transparently transmitted to the corresponding VM, and the VM reads the serial port data register during the interrupt processing. The substance of these data is receiving the VCD buffer. The data. Like physical equipment, hardware interruptions must also virtualize many times, which is more complicated. Virtualization interrupts are substantially to map hardware generated to each VM that requires it (regardless of whether the VM is running), replacing VXD. Here we give several important callback processes for virtualized the VXD instance, and use the simplest arbitration strategy to resolve access conflicts (see programs 1).

typedef struct {IRQHANDLE IrqHandle; VMHANDLE VMOwner; Char DeviceName [8]; BOOL bVMIsServicing;} DEVICE_CONTEXT; void _stdcall MaskChangHandler (VMHANDLE hVM, IRQHANDLE hIRQ, BOOL bMasking) // When a VM or mask in the interrupt controller when interrupts are enabled HIRQ , VPICD calls the process {if (! Bmasking) // If you open the interrupt {if (! Device.vmowner) {device.vmowner = HVM; // If no VM has this interrupt, the ownership of the interrupt will be For the current VM} else {if (device.vmowner! = HVM) {device.vmowner = shell_resolve_content (Device.VMowner, HVM, Device.DeviceName); // If the VM has this interrupt, the user can pass the dialog box between them to make a choice}} VPICD_Physically_Unmask (hIRQ); // open the physical interrupt} else {device.VMOwner = 0; VPICD_Physically_Mask (hIRQ); // interrupt mask the physical}} BOOL _stdcall HwIntHandler (VMHANDLE hVM, IRQHANDLE hIRQ) // When the interrupt HIRQ occurs, VPICD immediately calls the process {if (device.vmowner &&! Device.bvmisservicing) // If there is a VM occupying the interrupt and is not in the last interrupt processing {vpicd_set_int_request (Device.VMowner, HIRQ); / / Please see the discussion after this routine } Else {...} Return True;} void _stdcall virtinthandler (VMHANDLE HVM, IRQHANDLE HIRQ) // When VPICD is interrupted each time, the process is called {device.bvmisservicing = true; // set interrupt Processing flag} void _stdcall ithandler (VMHANDLE HVM, IRQHANDLE HIRQ) // When the interrupt processing from VM is returned, the callback {Device.bvmisservicing = false; // Clear interrupt processing flag} (program 1) Since the interrupt is asynchronous , When VXD calls VPICD (Virtual Programmable Interrupt Controller) Service VPICD_SET_INT_REQUEST maps the interrupt to the VM, the VM should be in an execution state.

(1) In the first step of the map, VPICD enforces the desired VM by calling the VMM (Virtual Machine Manager) service call_priority_vm_event, use the highest priority (time_critical_boost); (2) VPICD provides a callback of the service, so When the VM is scheduled to run, the VMM can notify VPICD; (3) The VPICD is then adjusted to adjust the VM's operating environment by calling another VMM service Simulate_Int. This service presses the CS, IP and flag registers of the VM into the stack of the VM. Remove the new CS, IP and flag registers from the interrupt vector table IVT of the VM, and clear the interrupt flag; (4) Returns from the callback, and VMM When the V86 mode is changed back, the VM immediately performs an interrupt processing process that has been registered with VPICD. The VXD written in virtualization devices is very different from VXD written for non-virtualized devices. It is mainly to use a set of completely different VMM and VXD services. In fact, there are many VXDs written for new devices at all, because there is no DOS or Windows applications directly access these hardware. Second, the communication mechanism between VXD and the application is not only processed by the VXD, so VxD is also an interface to the application in most cases. Through this interface, the application can do things related to hardware. Windows 9X has a mechanism for VXD and application bidirectional communication. The application described below refers to the Win32 application. The communication mechanism for the application to the VXD is: VXD is not like the Win16 application interface to output a special API process (Protection Mode API Process, or the V86 Mode API process) to support the application, replaced by it is that its control process must be handable A special message: W32_Deviceiocontrol. The VMM replaces the application that calls the DeviceIocontrol function to send this message to VXD. Message parameters can determine the VXD message response function, enter the output buffer pointer and buffer size, and bind in the DiocParameters structure. Through this interface, it is not only possible to read and write equipment, but also mutual transmission between applications and VXDs, thereby achieving special applications. Sometimes you only need to call the interface between the application and VXD, you can get the required information and services in time. However, there are still special circumstances that must be notified by VXD asynchronous applications, which requires VXD to the application's communication mechanism. VXD to the application's interface relationship is much more complicated than the interface between the application to VXD. There are two ways to call: one is to use the PostMessage function. The application can be notified by calling this new service provided by the housing Vxd (Shell VXD); the other is to use special Win32 technology. The uniqueness of this technology is that the Win32 API supports multi-threaded. In Win32 technology, although the APC (Asynchronous Procedure Calls) asynchronous process call mechanism and Win32 event mechanism relies on a Win32 application thread, it is still slightly different. The simplest communication mechanism for VXD to the application is through the APC, which is relatively simple to applications and VXDs. The application first dynamically loads VXD (createfile) and transmits the address of the callback function to VxD with DeviceIOControl, and then the application executes Win32 calls Sleepex to set itself as "the Asleep Yet Alertable) state. When the application is "hang" status, VXD can call the callback function of the application via the QueueUSeraPC service providing application by VWIN32 VXD. Another more efficient method is to use the Win32 event mechanism.

If the application runs multiple threads, when the child thread waits to wake up it while the main thread can continue to do its own work. For example, when a sub-thread is waiting for VXD cache the received data, the main thread can simultaneously monitor the user's input. Once the buffer reaches the threshold, VXD will wake up the wait-like sub-thread. For the notification between the thread, VXD uses thread events, as the application's multi-thread mechanism is made. Under Windows 95, VXD can access some Win32 event APIs that are very identical to multi-threaded applications (provided by VWIN32 VXD). These VWIN32 event services include: _vwin32_resetwin32event, _vwin32_setwin32event, _vwin32_pulsewin32event, _vwin32_waitsingleObject, _vwin32_waitmultipleObjects. With these services, VXD can wake up a Win32 application thread or wait by a Win32 application thread to wake up. Unfortunately, VXD is not just by simply invoking the corresponding event service, you can get the handle of Win32 events. Therefore, in order to obtain a handle of Win32 events involve a complex process and an unpublished system call. The event is usually generated by the application (Win32 API CreateEvent), then uses unpublished Win32 API functions OpenVxDHandle to convert the event handle to the VXD event handle, then pass this Ring 0-level event handle to VXD through DeviceioControl, so Vxd It can be used as a parameter of the VWIN32 event function. Because Windows uses a message-based event drive mechanism, VXD does not provide messages that are sent directly to the application thread, so the message sent by PostMessage and other many messages are handled in the message loop of the main thread. Thus, when some interface operations are performed, a large number of messages occupy the message queue, the messages sent by VXD may not have the corresponding processing. To solve this problem, there are two methods that can be used in the actual design: the first is still adopted, but the flag is set in the application and VXD, and the determination message is processed and made accordingly. Such as retransmission data; the second is to use the WIN32 event mechanism to give one thread to wait for the Win32 event, while others are used for other processing. The partial routine of the Win32 application thread is activated by VXD (see Program 2). When generating or eliminates a VM, VxD notifies the registered application, and displays the corresponding information.

In VXD, DWORD ONW32DEVICEIOCONTROL (PDIOCPARETERS P) // vxd with Win32 application interface functions {dword rc; swirch (p-> dwiocontrolcode) {copy dioc_open: // system definition function number: The device opens RC = 0; Break; Case Dioc_closeHandle: // Device Turn bclientRegistered = false; rc = 0; break; Case Eventvxd_register: // Custom Function No. HWIN32Event = P-> LPVINBUFFER; * ((DWORD *) (p-> lpvoutbuffer) = (dword) & GlobalVminfo; * (P-> lpcbbytesreturned) = sizeof (dword); bclientregistered = true; rc = 0; Break; default: rc = 0xfffffffff;} return rc; // Return 0 means success} BOOL OnVmInit (VMHANDLE hVM) // Once initialized VM executes {if (bClientRegistered) {GlobalVMInfo.hVM = hVM; GlobalVMInfo.bVmCreated = TRUE; Call_Priority_VM_Event (LOW_PRI_DEVICE_BOOST, Get_Sys_VM_Handle (), PEF_WAIT_FOR_STI PEF_WAIT_NOT_CRIT, hWin32Event, PriorityEventThunk, 0 ); // Make the System VM as the current operational state, the RING0 level event handle as the parameter of the callback process} Return True;} Voi D OnVmTerminate (VMHANDLE hVM) // is terminated once a VM executes {if (bClientRegistered) {GlobalVMInfo.hVM = hVM; GlobalVMInfo.bVmCreated = FALSE; Call_Priority_VM_Event (LOW_PRI_DEVICE_BOOST, Get_Sys_VM_Handle (), PEF_WAIT_FOR_STI PEF_WAIT_NOT_CRIT, hWin32Event, PriorityEventThunk, 0 );}} VOID _stdcall PriorityEventHandler (VMHANDLE hVM, PVOID Refdata, CRS * pRegs) {HANDLE hWin32Event = Refdata; _VWIN32_SetWin32Event (hWin32Event); //} activation event objects in the Win32 application; VOID main (int ac, char * av []) {Heventring3 = CreateEvent (0, False, False, Null);

/ / Generate RING3 event handle if (! "}" "CanNot Create Ring3 Event / N); EXIT (1);} hkernel32dll = loadingLibrary (" kernel32.dll "); if (! Hkernel32dll) {printf "CanNot Load Kernel32.dll / N"); exit (1);} pfopenvxdhandle = (Handle (WinApi *) (kernel32dll, "openvxdhandhandle"); if (! Pfopenvxdhandle) {Printf ("Cannot Get Addr Of openvxdhandle / n "); exit (1);} heventring0 = (* pfopenvxdhandle) (HeventRing3); // convert RING3 event handle to Ring0 event handle if (! HEVENTRING0) {Printf (" Cannot Create Ring0 Event / N "); exit (1);} hdevice = createfile (vxdname, 0, 0, 0, create_new, file_flag_delete_on_close, 0); // Dynamically loaded VXD if (! HDevice) {Printf (" cannot loading vxd error =% x / N ", getLastError ()); exit (1);} if (! DeviceioControl (HDevice, Eventvxd_register, heventring0, limitedof (heventring0), & PV MINFO, SIZEOF (PVMINFO), & CBBYTESTRETURNED, 0) / / Win32 program with VXD interface functions, passing RING0 level event handle into VXD, from VXD to the GlobalVminfo structure pointer {Printf ("Deviceiocontrol Register FaileD / N") Exit (1);} Createthread (0, 0x1000, Secondthread, HeventRing3, 0, & Tid); // Create thread printf ("press any key to exit ..."); getCh (); closehandle (hdevice);} DWORD WINAPI Secondthread (Pvoid ​​HEVENTRING3) {While (True) {WaitForsingleObject ((Handle) HeventRing3, Infinite; // Waiting for the corresponding event PrINTF ("VM% 081X WAS% X", PVMINFO-> HVM, PVMINFO-> bcreated? " Created "

转载请注明原文地址:https://www.9cbs.com/read-4076.html

New Post(0)