[NTOS]: Enable V8086 Fast-V86 Trap mode for Trap 6 (Invalid Opcode). Because we are now taking zero traps during V8086 mode, we can't do the "BOP lookahead", so the only trap we do get is when we hit the BOP/invalid opcode itself.
[NTOS]: Multiple fixes to V8086 opcode emulation code that I noticed while looking through the source. Also multiple fixes to VDM code.
This change will only impact real hardware and VMWare, since QEMU does not support VME. On VMWare, performance increased up to 400% during bootup (80 million cycles instead of 300 million, in one test).
svn path=/trunk/; revision=45282
VOID
FASTCALL
DECLSPEC_NORETURN
-KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
+KiTrap06Handler(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG EFlags)
{
PUCHAR Instruction;
ULONG i;
+ KIRQL OldIrql;
+ /* Check for V86 GPF */
+ if (__builtin_expect(EFlags & EFLAGS_V86_MASK, 1))
+ {
+ /* Enter V86 trap */
+ KiEnterV86Trap(TrapFrame);
+
+ /* Must be a VDM process */
+ if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
+ {
+ /* Enable interrupts */
+ _enable();
+
+ /* Setup illegal instruction fault */
+ KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
+ TrapFrame->Eip,
+ TrapFrame);
+ }
+
+ /* Go to APC level */
+ OldIrql = KfRaiseIrql(APC_LEVEL);
+ _enable();
+
+ /* Check for BOP */
+ if (!VdmDispatchBop(TrapFrame))
+ {
+ /* Should only happen in VDM mode */
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+
+ /* Bring IRQL back */
+ KfLowerIrql(OldIrql);
+ _disable();
+
+ /* Do a quick V86 exit if possible */
+ if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame);
+
+ /* Exit trap the slow way */
+ KiEoiHelper(TrapFrame);
+ }
+
/* Save trap frame */
KiEnterTrap(TrapFrame);
- /* Check for VDM trap */
- ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
-
/* Enable interrupts */
Instruction = (PUCHAR)TrapFrame->Eip;
_enable();
KiTrap(KiTrap03, KI_PUSH_FAKE_ERROR_CODE);
KiTrap(KiTrap04, KI_PUSH_FAKE_ERROR_CODE);
KiTrap(KiTrap05, KI_PUSH_FAKE_ERROR_CODE);
-KiTrap(KiTrap06, KI_PUSH_FAKE_ERROR_CODE);
+KiTrap(KiTrap06, KI_PUSH_FAKE_ERROR_CODE | KI_FAST_V86_TRAP);
KiTrap(KiTrap07, KI_PUSH_FAKE_ERROR_CODE);
KiTrap(KiTrap08, 0);
KiTrap(KiTrap09, KI_PUSH_FAKE_ERROR_CODE);
{
ULONG Esp, V86EFlags, TrapEFlags;
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
/* Get current V8086 flags and mask out interrupt flag */
V86EFlags = *KiNtVdmState;
V86EFlags &= ~EFLAGS_INTERRUPT_MASK;
-
+
/* Get trap frame EFLags and leave only align, nested task and interrupt */
TrapEFlags = TrapFrame->EFlags;
- TrapEFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
-
+ V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
+
/* Add in those flags if they exist, and add in the IOPL flag */
V86EFlags |= TrapEFlags;
V86EFlags |= EFLAGS_IOPL;
/* Now leave only alignment, nested task and interrupt flag */
EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
- /* FIXME: Check for VME support */
-
+ /* Get trap EFlags */
+ TrapEFlags = TrapFrame->EFlags;
+
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
+
/* Add V86 and Interrupt flag */
V86EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
-
+
/* Update EFlags in trap frame */
- TrapEFlags = TrapFrame->EFlags;
- TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | V86EFlags;
-
+ TrapFrame->EFlags |= V86EFlags;
+
/* Check if ESP0 needs to be fixed up */
if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame);
/* Keep only alignment and interrupt flag from the V8086 state */
V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK);
- /* FIXME: Support VME */
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
/* Mask in the relevant V86 EFlags into the trap flags */
V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK);
EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP);
V86EFlags = EFlags;
- /* FIXME: Check for VME support */
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
/* Add V86 and Interrupt flag */
EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame,
IN ULONG Flags)
{
- /* FIXME: Support VME */
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
/* Disable interrupts */
KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame,
IN ULONG Flags)
{
- /* FIXME: Support VME */
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
/* Enable interrupts */
KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK);
ASSERT(*VdmState == 0);
ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);
- /* Get the VDM context and make sure it's an edited frame */
+ /* Check if VME is supported and V86 mode was enabled */
+ if ((KeI386VirtualIntExtensions) &&
+ (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
+ {
+ /* Check if interrupts are enabled */
+ if (Interrupts)
+ {
+ /* Set fake IF flag */
+ VdmTib->VdmContext.EFlags |= EFLAGS_VIF;
+ }
+ else
+ {
+ /* Remove fake IF flag, turn on real IF flag */
+ VdmTib->VdmContext.EFlags &= ~EFLAGS_VIF;
+ VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
+ }
+ }
+ else
+ {
+ /* Set interrupt state in the VDM State */
+ if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK)
+ {
+ /* Enable them as well */
+ InterlockedOr((PLONG)VdmState, EFLAGS_INTERRUPT_MASK);
+ }
+ else
+ {
+ /* Disable them */
+ InterlockedAnd((PLONG)VdmState, ~EFLAGS_INTERRUPT_MASK);
+ }
+
+ /* Enable the interrupt flag */
+ VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
+ }
+
+ /* Get the VDM context and make sure it's not an edited frame */
VdmContext = VdmTib->VdmContext;
if (!(VdmContext.SegCs & FRAME_EDITED))
{
KeLowerIrql(OldIrql);
return STATUS_INVALID_SYSTEM_SERVICE;
}
-
- /* FIXME: Support VME */
- ASSERT(VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK);
-
- /* Set interrupt state in the VDM State */
- if (VdmTib->VdmContext.EFlags & EFLAGS_INTERRUPT_MASK)
- {
- /* Enable them as well */
- InterlockedOr((PLONG)VdmState, EFLAGS_INTERRUPT_MASK);
- }
- else
- {
- /* Disable them */
- InterlockedAnd((PLONG)VdmState, ~EFLAGS_INTERRUPT_MASK);
- }
-
- /* Enable the interrupt flag */
- VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
-
+
/* Now do the VDM Swap */
VdmSwapContext(VdmFrame, &VdmTib->MonitorContext, &VdmContext);
VdmTib->MonitorContext.Eax = STATUS_SUCCESS;
/* Make a copy of the monitor context */
- RtlCopyMemory(&Context, &VdmTib->MonitorContext, sizeof(CONTEXT));
-
- /* Switch contexts */
- VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context);
-
- /* FIXME: Support VME */
+ Context = VdmTib->MonitorContext;
+
+ /* Check if V86 mode was enabled or the trap was edited */
+ if ((Context.EFlags & EFLAGS_V86_MASK) || (Context.SegCs & FRAME_EDITED))
+ {
+ /* Switch contexts */
+ VdmSwapContext(TrapFrame, &VdmTib->VdmContext, &Context);
- /* Set the EFLAGS */
- VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags &
- ~EFLAGS_INTERRUPT_MASK) |
- (*VdmState & EFLAGS_INTERRUPT_MASK);
+ /* Check if VME is supported and V86 mode was enabled */
+ if ((KeI386VirtualIntExtensions) &&
+ (VdmTib->VdmContext.EFlags & EFLAGS_V86_MASK))
+ {
+ /* Check for VIF (virtual interrupt) flag state */
+ if (VdmTib->VdmContext.EFlags & EFLAGS_VIF)
+ {
+ /* Set real IF flag */
+ VdmTib->VdmContext.EFlags |= EFLAGS_INTERRUPT_MASK;
+ }
+ else
+ {
+ /* Remove real IF flag */
+ VdmTib->VdmContext.EFlags &= ~EFLAGS_INTERRUPT_MASK;
+ }
+
+ /* Turn off VIP and VIF */
+ TrapFrame->EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
+ VdmTib->VdmContext.EFlags &= ~(EFLAGS_VIP | EFLAGS_VIF);
+ }
+ else
+ {
+ /* Set the EFLAGS based on our software copy of EFLAGS */
+ VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags & ~EFLAGS_INTERRUPT_MASK) |
+ (*VdmState & EFLAGS_INTERRUPT_MASK);
+ }
+ }
/* Lower IRQL and reutrn */
KeLowerIrql(OldIrql);
VOID
NTAPI
-Ki386VdmEnablePentiumExtentions(VOID)
+Ki386VdmEnablePentiumExtentions(IN BOOLEAN Enable)
{
- /* FIXME: Support this */
- DPRINT1("VME support detected but not yet taken advantage of\n");
+ ULONG EFlags, Cr4;
+
+ /* Save interrupt state and disable them */
+ EFlags = __readeflags();
+ _disable();
+
+ /* Enable or disable VME as required */
+ Cr4 = __readcr4();
+ __writecr4(Enable ? Cr4 | CR4_VME : Cr4 & ~CR4_VME);
+
+ /* Restore interrupt state */
+ __writeeflags(EFlags);
}
VOID
if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS)
{
/* Enable them. FIXME: Use IPI */
- Ki386VdmEnablePentiumExtentions();
+ Ki386VdmEnablePentiumExtentions(TRUE);
KeI386VirtualIntExtensions = TRUE;
}
}