Two key issues in the virtual device driver (VXD) design
Chen Guoyou
In the design of the virtual device driver (VXD), two are especially critical, and the problem is that the problem is VXD virtualization and the communication mechanism between VXD and the application. Below, it is discussed in detail on these two issues.
First, VXD virtualization
Since Windows allows multiple tasks to be run, there is a case where multiple processes attempts to access the same physical device simultaneously, if multiple applications access the device through the same DLL driver (note and virtual device driver VXD) access device, no The device is required to virtualize, the driver is enabled; if multiple Windows applications are accessible at the same time, they do not need virtualization because they are running on the System VM (System Virtual Machine), and their access will A driver (Windows Driver DLL) detects and makes serialization instead of relying on VXD; if multiple VMs are trying to access the same device, because the DOS application can directly manipulate hardware, the device must be virtualized, one The VXD of the virtualization device is responsible for reliably detecting the situation of multiple VMs attempt to access the same device and take arbitration strategies to solve this conflict. There may be the following solutions here:
1. Allow 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 shields or opens the interrupt HIRQ in the interrupt controller, the VPICD calls the process.
{
If (! bmasking) // If you open the interrupt
{
IF (! device.vmowner)
{
Device.vmowner = HVM; // If there is no VM occupies the interrupt, set the ownership of the interrupt to the current VM
}
Else
{
IF (Device.VMowner! = HVM)
{
Device.vmowner = shell_resolve_content (Device.Vmowner, HVM, Device.DeviceName);
// If you already have the interrupt, the user can make a selection between the two through the dialog.
}
}
Vpicd_physically_unmask (hirq); // Open the physical interrupt
}
Else
{
Device.vmowner = 0;
Vpicd_physically_mask (hirq); // Shielded the physical interrupt
}
}
Bool _stdcall HwinTrandler (VmHandle HVM, Irqhandle Hirq)
/ / When the interrupt HIRQ occurs, VPICD is called immediately.
{
If (device.vmowner &&! device.bvmionservicing) // If you have a VM occupy this interrupt and is not in the last interrupt process
{
Vpicd_set_int_request (device.vmowner, hiRQ); // Please see the discussion after this routine
}
Else
{
......
}
Return True;
}
Void _stdcall Virtintrandler (VMHANDLE HVM, IRQHANDLE HIRQ)
// Call the process when VPICD is interrupted each time
{
Device.bvmisservicing = true; // Setting the interrupt processing flag
}
Void _stddcall IretHandler (Vmhandle HVM, Irqhandle Hirq)
/ / When the interrupt processing from the VM is returned, the callback is executed.
{
Device.bvmisservicing = false; // Clear Interrupt Processing Sign
}
(Program 1)
Since the interrupt is asynchronously generated, the VM should be in the execution state when the VXD call VPICD (Virtual Programmable Interrupt Controller) service VPICD_SET_INT_REQUEST maps the interrupt to the VM.
(1) In the first step of the mapping, 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) Then VPICD adjusts 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) When VPICD returns from the callback, and the VMM changes back to the V86 mode, the VM immediately performs an interrupt process that has been registered to the 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
Since VXD does not only process hardware, 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 interface functions with Win32 applications
{
DWORD RC;
Swirch (P-> dwiocontrolcode)
{
Case Dioc_open: // System Definition Source Number: Equipment Open
RC = 0;
Break;
Case Dioc_closeHandle: // Device is closed
BclientRegistered = false;
RC = 0;
Break;
Case eventvxd_register: // Customize the function number
HWIN32EVENT = P-> lpvinbuffer;
* ((DWORD *) (P-> lpvoutbuffer) = (dword) & globalVminfo;
* ((DWORD *) (P-> LPCBBYTESRETURNED) = sizeof (dword);
BclientRegistered = True;
RC = 0;
Break;
DEFAULT:
Rc = 0xfffffff;
}
Return rc; // If you return 0, it is successful.
}
Bool ONVMINIT (VMHANDLE HVM) / / Once VM is initialized
{
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, PRIORITYVENTTHUNK, 0);
// Make the System VM as the current operational state, and the RING0 level event handle is used as the parameter of the callback process.
}
Return True;
}
Void ONVMTERMINATE (VMHANDLE HVM) // Once VM is ended,
{
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, PRIORITYVENTTHUNK, 0);
}
}
Void_stdcall PriorityEventHandler (VMHandle HVM, PVOID REFDATA, CRS * PREGS)
{
Handle hwin32event = refdata;
_Vwin32_setwin32event (hwin32event); // activate the event object
}
In the Win32 application;
Void Main (int AC, char * av [])
{
HEVENTRING3 = CreateEvent (0, False, False, Null); // Generate RING3 event handle
IF (! HEVENTRING3)
{
Printf ("Cannot Create Ring3 Event / N);
Exit (1);
}
Hkernel32dll = loadingLibrary ("kernel32.dll");
IF (! hkernel32dll)
{
Printf ("Cannot Load Kernel32.dll / N");
Exit (1);
}
PfopenvxdHandle = (Handle (WinApi *) (Handle)
GetProcadDress (kernel32dll, "openvxdhandle");
IF (! Pfopenvxdhandle)
{
Printf ("Cannot Get Addr of OpenVxDHandle / N");
Exit (1);
}
HEVENTRING0 = (* pfopenvxdhandle) (HEVENTRING3); // convert the RING3 event handle to RING0 level 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 load VXD
IF (! hdevice)
{
Printf ("Cannot Load Vxd Error =% x / n", getLastError ());
Exit (1);
}
IF (! DeviceioControl (HDevice, Eventvxd_register, heventring0, sizeof (heventring0), & pvminfo, sizeof (pvminfo), & cbbytestReturned, 0))
/ / Win32 program with VXD interface functions, incoming Ring0 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": "destroyed");
// Show VMs being creted or destroyed
}
Return 0;
}
(Program 2)
Third, conclude
Although VXD design also involves many other aspects, the details of the above key issues will play a very important role in programming of VXD. I hope this article can bring some help to you.
(Author Address: Nanjing Communication Engineering College Graduate Second Team 210016 Received: 1999.2.2)