Caveats of VME (when CR4.VME=1)
VME is wonderful for reducing the complexity of the OS, but isn't without
its caveats. Some of the quirks are natural extensions of VME or the underlying
architecture, while others might not make any sense.
- While an Ev86 task is running, the IF-sensitive flags commit fakery
to fool the Ev86 task into thinking that it is actually setting and clearing
the IF flag. When a fault occurs to the monitor, the monitor sees the actual
values of VIF, VIP and IF unfiltered. This gives the monitor direct control
over virtual interrupts, and hardware interrupts.
- Software-generated exceptions are not influenced by the IR bit map.
INT1,[1] INT3, INTO, and BOUND[2]
are not subject to the IR bit map. Instead, these opcodes will always invoke
the protected mode exception handler.[3]
- VIF will never transition from 0 to 1 while a virtual interrupt is
pending when IOPL<3. This condition will always cause a general protection
fault (#GP(0)) before VIF is set. This can best be described as follows:
while the Ev86 task is in an uninterruptible state (VIF=0), a timer tick
occurs, and causes a transition to the protected mode interrupt handler.
The timer-tick routine sets VIP on the stack frame, and returns to the
Ev86 task. The Ev86 task performs an STI instruction, which will put the
program into an interruptible state. Before VIF is actually set, the #GP
occurs. (This behavior can be observed by inspecting the EFLAGS image on
the CPL-0 stack frame.) This behavioral characteristic is the basis for
Intel's British Patent application which claims "if the VIP bit is
in its 'pending' state, then the STI instruction can be executed and an
awaiting interrupt serviced by using the emulation software without first
changing the VIF bit from its CLI state to its STI state."
- VIP functions in IOPL=3 in a strange manner. When IOPL<3, and VIP=1,
any transition from VIF=0 to VIF=1 will cause a general protection fault
before VIF is actually set. When IOPL=3, this behavior is different. VIF
must actually be set before the #GP occurs.
- PUSHFD, POPFD, and IRETD will all generate a general protection fault
in an Ev86 task when IOPL<3.
- The behavior of POPF and IRET is inconsistent in how it handles the
trap flag (TF) from the flags image on the stack. When POPF is invoked
with TF=1 on the stack image, a general protection fault occurs. When IRET
is invoked under the same condition, the general protection fault does
not occur.
- IRET is no longer IOPL-sensitive when CR4.VME=1. Consider that the
Ev86 task is running and an interrupt's associated IR bit is set. When
this interrupt is invoked, it will cause a fault to the monitor, or the
protected mode interrupt will be invoked (depending on IOPL). The interrupt
is then reflected back to the Ev86 task. When IOPL=3, the behavior of the
fault and subsequent IRET matches non-Ev86 behavior. When IOPL<3, the
subsequent IRET from the interrupt service routine doesn't cause a fault
back to the monitor, as IRET is no longer IOPL-sensitive. This behavior
is inconsistent with its non-Ev86 counterpart.
- When IOPL=3, the CPU never updates VIF, though software can manipulate
it in CPL-0. This can lead to the next caveat...
- The CPU will generate a general protection fault (#GP(0)) whenever
VIF=1, and VIP=1 and running in CPL-3. This is regardless of whether or
not the code is an Ev86 task.
- In CPL-0, IRETD has the ability to set VIF and VIP, but POPFD does
not.
Endnotes
- An undocumented opcode which generates an INT-1
exception. Also known as ICEBP.
- Opcodes 0xF1, 0xCC, 0xCE, 0x62 respectively.
- Assuming that all other protection attributes will
permit the transition to occur.
Back to article Virtual Mode
Extensions on the Pentium Processor
Back to Books and Articles home page