[NTOS]: Try to fix KiEnterInterrupt once and for all. Only set segments for V8086...
authorSir Richard <sir_richard@svn.reactos.org>
Mon, 1 Feb 2010 03:47:42 +0000 (03:47 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Mon, 1 Feb 2010 03:47:42 +0000 (03:47 +0000)
[NTOS]: Rework the way traps with possibly dirty DS/ES segments are handled. The FAST V86 hack is gone. Intead, created a "safe" version of IsTrapV86 and IsTrapUser that does an SS segment dereference (known good). The condition is then based on this, and the segments are saved and loaded safely. Note that for GCC 4.5 the ASM can be improved to directly branch or not to a label, instead of returning a boolean that is then further compared before branching.
This will fix certain exceptions that were seen in KeUpdateSystemTime, and might fix the sneaking HalpTrap0D while not in V86 mode (no promises).

svn path=/trunk/; revision=45367

reactos/ntoskrnl/include/internal/trap_x.h
reactos/ntoskrnl/ke/i386/traphdlr.c

index 435a129..b89989f 100644 (file)
@@ -406,6 +406,68 @@ KiIssueBop(VOID)
     asm volatile(".byte 0xC4\n.byte 0xC4\n");
 }
 
+//
+// Returns whether or not this is a V86 trap by checking the EFLAGS field.
+//
+// FIXME: GCC 4.5 Can Improve this with "goto labels"
+//
+BOOLEAN
+FORCEINLINE
+KiIsV8086TrapSafe(IN PKTRAP_FRAME TrapFrame)
+{
+    BOOLEAN Result;
+    
+    /*
+     * The check MUST be done this way, as we guarantee that no DS/ES/FS segment
+     * is used (since it might be garbage).
+     *
+     * Instead, we use the SS segment which is guaranteed to be correct. Because
+     * operate in 32-bit flat mode, this works just fine.
+     */
+     asm volatile
+     (
+        "testl $%c[f], %%ss:%1\n"
+        "setnz %0\n"
+        : "=a"(Result)
+        : "m"(TrapFrame->EFlags),
+          [f] "i"(EFLAGS_V86_MASK)
+     );
+    
+    /* If V86 flag was set */ 
+    return Result;
+}
+
+//
+// Returns whether or not this is a user-mode trap by checking the SegCs field.
+//
+// FIXME: GCC 4.5 Can Improve this with "goto labels"
+//
+BOOLEAN
+FORCEINLINE
+KiIsUserTrapSafe(IN PKTRAP_FRAME TrapFrame)
+{
+    BOOLEAN Result;
+    
+    /*
+     * The check MUST be done this way, as we guarantee that no DS/ES/FS segment
+     * is used (since it might be garbage).
+     *
+     * Instead, we use the SS segment which is guaranteed to be correct. Because
+     * operate in 32-bit flat mode, this works just fine.
+     */
+     asm volatile
+     (
+        "cmp $%c[f], %%ss:%1\n"
+        "setnz %0\n"
+        : "=a"(Result)
+        : "m"(TrapFrame->SegCs),
+          [f] "i"(KGDT_R0_CODE)
+     );
+    
+    /* If V86 flag was set */ 
+    return Result;
+}
+
 VOID
 FORCEINLINE
 KiUserSystemCall(IN PKTRAP_FRAME TrapFrame)
@@ -638,28 +700,39 @@ VOID
 FORCEINLINE
 KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
 {
+    ULONG Ds, Es;
+    
     /* Check for V86 mode, otherwise check for ring 3 code */
-    if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 0))
+    if (__builtin_expect(KiIsV8086TrapSafe(TrapFrame), 0))
     {
+        /* Set correct segments */
+        Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
+        Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
+        Ke386SetFs(KGDT_R0_PCR);
+
         /* Restore V8086 segments into Protected Mode segments */
         TrapFrame->SegFs = TrapFrame->V86Fs;
         TrapFrame->SegGs = TrapFrame->V86Gs;
         TrapFrame->SegDs = TrapFrame->V86Ds;
         TrapFrame->SegEs = TrapFrame->V86Es;
     }
-    else if (__builtin_expect(TrapFrame->SegCs != KGDT_R0_CODE, 1)) /* Ring 3 is more common */
+    else if (__builtin_expect(KiIsUserTrapSafe(TrapFrame), 1)) /* Ring 3 is more common */
     {
-        /* Save segments and then switch to correct ones */
+        /* Save DS/ES and load correct values */
+        Es = Ke386GetEs();
+        Ds = Ke386GetDs();
+        TrapFrame->SegDs = Ds;
+        TrapFrame->SegEs = Es;
+        Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
+        Ke386SetEs(KGDT_R3_DATA | RPL_MASK);
+        
+        /* Save FS/GS */
         TrapFrame->SegFs = Ke386GetFs();
         TrapFrame->SegGs = Ke386GetGs();
-        TrapFrame->SegDs = Ke386GetDs();
-        TrapFrame->SegEs = Ke386GetEs();
-    }
-    
-    /* Set correct segments */
-    Ke386SetFs(KGDT_R0_PCR);
-    Ke386SetDs(KGDT_R3_DATA | RPL_MASK);
-    Ke386SetEs(KGDT_R3_DATA | RPL_MASK);        
+        
+        /* Set correct FS */
+        Ke386SetFs(KGDT_R0_PCR);
+    }       
     
     /* Save exception list and terminate it */
     TrapFrame->ExceptionList = KeGetPcr()->Tib.ExceptionList;
@@ -743,7 +816,7 @@ KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
 // Generates a Trap Prolog Stub for the given name
 //
 #define KI_PUSH_FAKE_ERROR_CODE 0x1
-#define KI_FAST_V86_TRAP        0x2
+#define KI_UNUSED               0x2
 #define KI_NONVOLATILES_ONLY    0x4
 #define KI_FAST_SYSTEM_CALL     0x8
 #define KI_SOFTWARE_TRAP        0x10
@@ -836,20 +909,13 @@ KiTrapStub(IN ULONG Flags,
     /* Now go ahead and make space for this frame */
     __asm__ __volatile__ ("subl $%c[e],%%esp\n":: [e] "i"(FrameSize) : "%esp");
     __asm__ __volatile__ ("subl $%c[e],%%ecx\n":: [e] "i"(FrameSize) : "%ecx");
-       
-    /* For Fast-V86 traps, set parameter 2 (EDX) to hold EFlags */   
-    if (Flags & KI_FAST_V86_TRAP) __asm__ __volatile__
-    (
-        "movl %c[f](%%esp), %%edx\n"
-        :
-        : [f] "i"(FIELD_OFFSET(KTRAP_FRAME, EFlags))
-    );
-    else if (Flags & KI_HARDWARE_INT) __asm__ __volatile__
+
+    /*
+     * For hardware interrupts, set parameter 2 (EDX) to hold KINTERRUPT.
+     * This code will be dynamically patched when an interrupt is registered!
+     */  
+    if (Flags & KI_HARDWARE_INT) __asm__ __volatile__
     (
-        /*
-         * For hardware interrupts, set parameter 2 (EDX) to hold KINTERRUPT.
-         * This code will be dynamically patched when an interrupt is registered!
-         */
         ".globl _KiInterruptTemplate2ndDispatch\n_KiInterruptTemplate2ndDispatch:\n"
         "movl $0, %%edx\n"
         ".globl _KiInterruptTemplateObject\n_KiInterruptTemplateObject:\n"
index 9e0c29c..a6d8052 100644 (file)
@@ -533,15 +533,14 @@ KiTrap05Handler(IN PKTRAP_FRAME TrapFrame)
 VOID
 FASTCALL
 DECLSPEC_NORETURN
-KiTrap06Handler(IN PKTRAP_FRAME TrapFrame,
-                IN ULONG EFlags)
+KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
 {
     PUCHAR Instruction;
     ULONG i;
     KIRQL OldIrql;
     
     /* Check for V86 GPF */
-    if (__builtin_expect(EFlags & EFLAGS_V86_MASK, 1))
+    if (__builtin_expect(KiIsV8086TrapSafe(TrapFrame), 1))
     {
         /* Enter V86 trap */
         KiEnterV86Trap(TrapFrame);
@@ -792,8 +791,7 @@ KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame)
 VOID
 FASTCALL
 DECLSPEC_NORETURN
-KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame,
-                IN ULONG EFlags)
+KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
 {
     ULONG i, j, Iopl;
     BOOLEAN Privileged = FALSE;
@@ -802,7 +800,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame,
     KIRQL OldIrql;
     
     /* Check for V86 GPF */
-    if (__builtin_expect(EFlags & EFLAGS_V86_MASK, 1))
+    if (__builtin_expect(KiIsV8086TrapSafe(TrapFrame), 1))
     {
         /* Enter V86 trap */
         KiEnterV86Trap(TrapFrame);
@@ -1581,14 +1579,14 @@ 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 | KI_FAST_V86_TRAP);
+KiTrap(KiTrap06,         KI_PUSH_FAKE_ERROR_CODE);
 KiTrap(KiTrap07,         KI_PUSH_FAKE_ERROR_CODE);
 KiTrap(KiTrap08,         0);
 KiTrap(KiTrap09,         KI_PUSH_FAKE_ERROR_CODE);
 KiTrap(KiTrap0A,         0);
 KiTrap(KiTrap0B,         0);
 KiTrap(KiTrap0C,         0);
-KiTrap(KiTrap0D,         KI_FAST_V86_TRAP);
+KiTrap(KiTrap0D,         0);
 KiTrap(KiTrap0E,         0);
 KiTrap(KiTrap0F,         KI_PUSH_FAKE_ERROR_CODE);
 KiTrap(KiTrap10,         KI_PUSH_FAKE_ERROR_CODE);