Author: sir_richard
Date: Wed Jan 27 06:34:38 2010
New Revision: 45282
URL:
http://svn.reactos.org/svn/reactos?rev=45282&view=rev
Log:
[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and it's
an Intel optimization that makes changes to the IF bit in EFLAGS (CLI, STI, INT, IRETD,
PUSHF, POPF) completely transprent: instead of changing the real (protected) bit, which
requires the OS to trap and emulate the behavior, the CPU sets a "Fake" IF bit
instead. When you're dong in V8086 mode, you simply update your real flag with
whatever the fake flag says.
[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).
Modified:
trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
trunk/reactos/ntoskrnl/ke/i386/v86vdm.c
trunk/reactos/ntoskrnl/vdm/vdmexec.c
trunk/reactos/ntoskrnl/vdm/vdmmain.c
Modified: trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/traphdlr.…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] Wed Jan 27 06:34:38 2010
@@ -533,16 +533,56 @@
VOID
FASTCALL
DECLSPEC_NORETURN
-KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
+KiTrap06Handler(IN PKTRAP_FRAME TrapFrame,
+ IN ULONG EFlags)
{
PUCHAR Instruction;
ULONG i;
-
- /* Save trap frame */
- KiEnterTrap(TrapFrame);
-
- /* Check for VDM trap */
- ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
+ 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);
/* Enable interrupts */
Instruction = (PUCHAR)TrapFrame->Eip;
@@ -1557,7 +1597,7 @@
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);
Modified: trunk/reactos/ntoskrnl/ke/i386/v86vdm.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/v86vdm.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] Wed Jan 27 06:34:38 2010
@@ -53,14 +53,17 @@
{
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;
@@ -124,15 +127,18 @@
/* 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);
@@ -166,7 +172,8 @@
/* 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);
@@ -277,7 +284,8 @@
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;
@@ -314,7 +322,8 @@
KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame,
IN ULONG Flags)
{
- /* FIXME: Support VME */
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
/* Disable interrupts */
KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
@@ -331,7 +340,8 @@
KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame,
IN ULONG Flags)
{
- /* FIXME: Support VME */
+ /* Check for VME support */
+ ASSERT(KeI386VirtualIntExtensions == FALSE);
/* Enable interrupts */
KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK);
Modified: trunk/reactos/ntoskrnl/vdm/vdmexec.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/vdm/vdmexec.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/vdm/vdmexec.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/vdm/vdmexec.c [iso-8859-1] Wed Jan 27 06:34:38 2010
@@ -196,7 +196,42 @@
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))
{
@@ -204,25 +239,7 @@
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);
@@ -251,17 +268,41 @@
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 */
-
- /* Set the EFLAGS */
- VdmTib->VdmContext.EFlags = (VdmTib->VdmContext.EFlags &
- ~EFLAGS_INTERRUPT_MASK) |
- (*VdmState & EFLAGS_INTERRUPT_MASK);
+ 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);
+
+ /* 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);
Modified: trunk/reactos/ntoskrnl/vdm/vdmmain.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/vdm/vdmmain.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/vdm/vdmmain.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/vdm/vdmmain.c [iso-8859-1] Wed Jan 27 06:34:38 2010
@@ -20,10 +20,20 @@
VOID
NTAPI
-Ki386VdmEnablePentiumExtentions(VOID)
-{
- /* FIXME: Support this */
- DPRINT1("VME support detected but not yet taken advantage of\n");
+Ki386VdmEnablePentiumExtentions(IN BOOLEAN Enable)
+{
+ 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
@@ -63,7 +73,7 @@
if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS)
{
/* Enable them. FIXME: Use IPI */
- Ki386VdmEnablePentiumExtentions();
+ Ki386VdmEnablePentiumExtentions(TRUE);
KeI386VirtualIntExtensions = TRUE;
}
}