include vmm.inc
mov eax, PriorityBoost
mov ebx, Handle
mov ecx, Flags
mov edx, RefData
mov esi, OFFSET32 RestrictedProc
mov edi, Timeout
VMMCall Call_Restricted_Event
mov [EventHandle], esi
Combines the functionality of the Call_VM_Event, Call_When_VM_Ints_Enabled, Call_When_Not_Critical, and Adjust_Exec_Priority services into one service.
The service allows a VxD to specify flags which place restrictions on when the VMM can call the event callback function. Restrictions include such things as the event callback function can be called only when interrupts are enabled, only when the critical section is unowned, and so on.
As with all event services, this service can be called from an interrupt handler. This is an asynchronous service. Uses ESI and Flags.
Value | Meaning |
---|---|
Reserved_Low_Boost | Reserved for use by system. |
Low_Pri_Device_Boost | Use for operations that need timely processing but are not time critical. |
High_Pri_Device_Boost | Use for time-critical operations that should not circumvent the critical section boost. |
Critical_Section_Boost | Use to boost the priority of the virtual machine whenever it enters a critical section (calls Begin_Critical_Section). |
Time_Critical_Boost | Use for operations that require immediate processing, even when another virtual machine is in a critical section. For example, VPICD uses this when simulating hardware interrupts. |
Reserved_High_Boost | Reserved for use by system. |
For global events, the priority boost only goes into effect after restrictions have been met; that is, just before the VMM calls the event callback function. For VM events, the priority boost is originally applied to the whole VM, but will be moved to the thread that the event is called on unless Flags specifies the PEF_Dont_Unboost flag.
Forgetting to pass a priority value in the EAX register is a common error.
Value | Meaning |
---|---|
PEF_Always_Sched | Event is always scheduled, meaning the callback function is never called immediately. |
PEF_Dont_Unboost | Priority of the virtual machine or thread is not reduced after return from callback function. |
PEF_Thread_Event | Handle is the handle of the thread for which the event is requested. The callback function is called only in the context of the thread. |
PEF_Time_Out | The time-out value in the EDI register should be used. Available in Windows version 3.1 or later. |
PEF_Wait_For_STI | Callback function is not called until the virtual machine enables interrupts in all threads. |
PEF_Wait_Not_HW_Int | Callback function is not called while the VPICD is simulating a hardware interrupt. |
PEF_Wait_In_PM | Callback function is not called until the virtual machine or thread is executing in protected mode. Use this flag with caution — it may never happen for VM other than the system VM unless an MS-DOS Protected Mode Interface (DPMI) application is running. |
PEF_Wait_Not_Crit | Callback function is not called until the virtual machine is not in a critical section or time-critical operation. See remarks below. |
PEF_Wait_Not_Nested_Exec | Callback function is not called while the virtual machine is in a nested execution block. |
PEF_Wait_For_Thread_STI | Callback function is not called until interrupts are enabled at ring 3 in the current thread. |
PEF_Ring0_Event | Callback function completes at ring 0. See remarks below. |
PEF_Wait_Crit | Callback function is not called until (1) the critical section is free, or (2) the critical section is owned by the current thread. See remarks below. |
PEF_Wait_Crit_VM | Callback function is called when critical section not owned by other thread in VM. See remarks below. |
PEF_Process_Last | See description below. |
All other values are reserved.
If a timeout occurs before the restrictions are met, the event callback will be called with carry set.
A VxD uses the Call_Restricted_Event service for purposes that include the following:
Global restricted events can happen in any VM that meets the restriction. VM-restricted events can only happen in the specified VM; and now that multiple threads are supported in the system VM, restricted thread events can be specified to only happen in the one thread context (although specifying that interrupts must be enabled for a thread event will only happen when interrupts are enabled in all threads of that VM.)
The PEF_Wait_Not_Crit flag will delay the processing of the event until the critical section is free and the priority of the current thread or virtual machine is less than Critical_Section_Boost. One should be careful not to pass too large a PriorityBoost when this flag is set. (In particular, passing a PriorityBoost greater than or equal to Critical_Section_Boost will prevent the event from ever satisfying its own restrictions.)
The PEF_Wait_For_Thread_STI flag differs from the PEF_Wait_For_STI flag in that the former checks the status of only the current thread, whereas the latter checks the status of all threads in the virtual machine. The two flags may not be combined.
The PEF_Ring0_Event flag indicates that the event can complete entirely at ring 0 without faulting. The requirements for 'ring 0' events are very strict, and apply to the event callback procedure and anything it calls, directly or indirectly. Although some rules in the system are relaxed if 32-bit disk access is enabled, these rules remain in full force. Ring 0 events must restrict memory accesses to locked code and locked data. They must not call Begin_Nest_Exec, Resume_Exec, Exec_VxD_Int, Exec_Int, or any service or procedure that in turn calls one of those services. They must not block on any synchronization objects. They must not adjust any thread's execution priority. In brief, they must guarantee that they will carry out their work to completion without running any code at ring 3, and without causing a task switch. In exchange for these guarantees, ring 0 events can be processed even if a thread has specifically requested that events not be processed. Ring 0 events are very dangerous. It is strongly recommended that they be avoided entirely. The flag is listed here for completeness.
The PEF_Wait_Crit flag indicates that the event may be processed only if the current thread owns the critical section, or if the critical section is unowned. This restriction may be applied only to global events (Handle = 0). The event callback can then be assured that it can call Begin_Critical_Section without blocking. PEF_Wait_Crit events allow you to ensure that a section of code be executed as soon as possible under the protection of the critical section. In Windows 3.1, this was done by a chain of events which repeatedly determine the critical section owner, then either perform the requested action or reschedule the same event for the current critical section owner and trying again. Since the ownership of the critical section can change between the time the event is scheduled and the time the event is processed, this chain of events may continue for several iterations before finally completing. (If you draw a picture, you can see why this is informally known as 'chasing the critical section'.) Starting with Windows 95, the PEF_Wait_Crit flag is the recommended way of accomplishing this.
The PEF_Wait_Crit_VM flag may be set only if Handle is equal to the System VM handle. It indicates that the event may be processed when the current thread is a thread in the System VM, and one of the following conditions is also met: (1) The critical section is unowned. (2) The critical section is owned by the current thread. (3) The critical section is owned by a thread not in the System VM. Writers of virtual device drivers should not normally have need for this flag. It is documented here for completeness.
The PEF_Process_Last allows a limited degree of control over the order in which events are processed. Normally, global events are processed first, then VM events, then thread events. This flag causes the event to be removed from consideration during the initial check for processable events. If the initial check fails to find any events, then a second pass is made during which this event can be selected. The only time this flag should be set is on a VM event (Handle is a valid VM handle), to indicate that the current thread should have no thread events when the VM event is processed. It does not add the event to the end of a list. Writers of virtual device drivers should not normally have need for this flag. It is documented here for completeness.
Adjust_Exec_Priority, Begin_Critical_Section, Call_VM_Event, Call_When_Not_Critical, Call_When_VM_Ints_Enabled, Cancel_Restricted_Event, RestrictedEventCallback