[NTOS/PERF]: Enable VME support. VME stands for Virtual 8086 Mode Extensions, and...
authorSir Richard <sir_richard@svn.reactos.org>
Wed, 27 Jan 2010 05:34:38 +0000 (05:34 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Wed, 27 Jan 2010 05:34:38 +0000 (05:34 +0000)
[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

reactos/ntoskrnl/ke/i386/traphdlr.c
reactos/ntoskrnl/ke/i386/v86vdm.c
reactos/ntoskrnl/vdm/vdmexec.c
reactos/ntoskrnl/vdm/vdmmain.c

index eb00b7f..b54a398 100644 (file)
@@ -533,17 +533,57 @@ KiTrap05Handler(IN PKTRAP_FRAME TrapFrame)
 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();
@@ -1557,7 +1597,7 @@ KiTrap(KiTrap01,         KI_PUSH_FAKE_ERROR_CODE);
 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);
index ab937ad..1771e58 100644 (file)
@@ -53,14 +53,17 @@ KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame,
 {
     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 @@ KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame,
     /* 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 @@ KiVdmOpcodeINTnn(IN PKTRAP_FRAME 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);
@@ -277,7 +284,8 @@ KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame,
     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 @@ FASTCALL
 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 @@ FASTCALL
 KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame,
                IN ULONG Flags)
 {
-    /* FIXME: Support VME */
+    /* Check for VME support */
+    ASSERT(KeI386VirtualIntExtensions == FALSE);
 
     /* Enable interrupts */
     KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK);
index 067c1cc..d305b3d 100644 (file)
@@ -196,7 +196,42 @@ VdmpStartExecution(VOID)
     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 @@ VdmpStartExecution(VOID)
         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 @@ VdmEndExecution(IN PKTRAP_FRAME TrapFrame,
     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);
index ff31403..c7aa0a2 100644 (file)
 
 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
@@ -63,7 +73,7 @@ KeI386VdmInitialize(VOID)
         if (KeGetPcr()->Prcb->FeatureBits & KF_V86_VIS)
         {
             /* Enable them. FIXME: Use IPI */
-            Ki386VdmEnablePentiumExtentions();
+            Ki386VdmEnablePentiumExtentions(TRUE);
             KeI386VirtualIntExtensions = TRUE;
         }
     }