[LT2013]
[reactos.git] / ntoskrnl / ke / i386 / traphdlr.c
index 41d367e..9bd9670 100644 (file)
@@ -42,10 +42,17 @@ UCHAR KiTrapIoTable[] =
     0xEE,                      /* OUT                                  */
     0xEF,                      /* OUT                                  */
     0x6E,                      /* OUTS                                 */
-    0x6F,                      /* OUTS                                 */    
+    0x6F,                      /* OUTS                                 */
 };
 
 PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
+#if DBG && !defined(_WINKD_)
+PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL;
+PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL;
+#endif
+#if TRAP_DEBUG
+BOOLEAN StopChecking = FALSE;
+#endif
 
 
 /* TRAP EXIT CODE *************************************************************/
@@ -78,16 +85,13 @@ KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame)
 
 VOID
 FORCEINLINE
-KiCommonExit(IN PKTRAP_FRAME TrapFrame, const ULONG Flags)
+KiCommonExit(IN PKTRAP_FRAME TrapFrame, BOOLEAN SkipPreviousMode)
 {
     /* Disable interrupts until we return */
     _disable();
-    
+
     /* Check for APC delivery */
     KiCheckForApcDelivery(TrapFrame);
-    
-    /* Debugging checks */
-    KiExitTrapDebugChecks(TrapFrame, Flags);
 
     /* Restore the SEH handler chain */
     KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
@@ -95,11 +99,17 @@ KiCommonExit(IN PKTRAP_FRAME TrapFrame, const ULONG Flags)
     /* Check if there are active debug registers */
     if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
     {
-        /* Not handled yet */
-        DbgPrint("Need Hardware Breakpoint Support!\n");
-        DbgBreakPoint();
-        while (TRUE);
+        /* Check if the frame was from user mode or v86 mode */
+        if ((TrapFrame->SegCs & MODE_MASK) ||
+            (TrapFrame->EFlags & EFLAGS_V86_MASK))
+        {
+            /* Handle debug registers */
+            KiHandleDebugRegistersOnTrapExit(TrapFrame);
+        }
     }
+
+    /* Debugging checks */
+    KiExitTrapDebugChecks(TrapFrame, SkipPreviousMode);
 }
 
 DECLSPEC_NORETURN
@@ -108,7 +118,7 @@ FASTCALL
 KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
 {
     /* Common trap exit code */
-    KiCommonExit(TrapFrame, 0);
+    KiCommonExit(TrapFrame, TRUE);
 
     /* Check if this was a V8086 trap */
     if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame);
@@ -136,10 +146,10 @@ KiServiceExit(IN PKTRAP_FRAME TrapFrame,
     TrapFrame->Eax = Status;
     
     /* Common trap exit code */
-    KiCommonExit(TrapFrame, 0);
+    KiCommonExit(TrapFrame, FALSE);
     
     /* Restore previous mode */
-    KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode;
+    KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode;
 
     /* Check for user mode exit */
     if (TrapFrame->SegCs & MODE_MASK)
@@ -167,10 +177,10 @@ FASTCALL
 KiServiceExit2(IN PKTRAP_FRAME TrapFrame)
 {
     /* Common trap exit code */
-    KiCommonExit(TrapFrame, 0);
+    KiCommonExit(TrapFrame, FALSE);
     
     /* Restore previous mode */
-    KeGetCurrentThread()->PreviousMode = TrapFrame->PreviousPreviousMode;
+    KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode;
     
     /* Check if this was a V8086 trap */
     if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame);
@@ -209,7 +219,7 @@ KiDebugHandler(IN PKTRAP_FRAME TrapFrame,
                                      Parameter1,
                                      Parameter2,
                                      Parameter3,
-                                     TrapFrame); 
+                                     TrapFrame);
 }
 
 DECLSPEC_NORETURN
@@ -287,27 +297,32 @@ KiNpxHandler(IN PKTRAP_FRAME TrapFrame,
     }
 
     /* Get legal exceptions that software should handle */
-    Error &= (FSW_INVALID_OPERATION |
-              FSW_DENORMAL |
-              FSW_ZERO_DIVIDE |
-              FSW_OVERFLOW |
-              FSW_UNDERFLOW |
-              FSW_PRECISION);
+    /* We do this by first masking off from the Mask the bits we need, */
+    /* This is done so we can keep the FSW_STACK_FAULT bit in Error. */
+    Mask &= (FSW_INVALID_OPERATION |
+             FSW_DENORMAL |
+             FSW_ZERO_DIVIDE |
+             FSW_OVERFLOW |
+             FSW_UNDERFLOW |
+             FSW_PRECISION);
     Error &= ~Mask;
-    
-    if (Error & FSW_STACK_FAULT)
-    {
-        /* Issue stack check fault */
-        KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK,
-                                 ErrorOffset,
-                                 0,
-                                 DataOffset,
-                                 TrapFrame);
-    }
 
     /* Check for invalid operation */
     if (Error & FSW_INVALID_OPERATION)
     {
+        /* NOTE: Stack fault is handled differently than any other case. */
+        /* 1. It's only raised for invalid operation. */
+        /* 2. It's only raised if invalid operation is not masked. */
+        if (Error & FSW_STACK_FAULT)
+        {
+            /* Issue stack check fault */
+            KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK,
+                                     ErrorOffset,
+                                     0,
+                                     DataOffset,
+                                     TrapFrame);
+        }
+
         /* Issue fault */
         KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
                                  ErrorOffset,
@@ -459,7 +474,7 @@ KiTrap02(VOID)
     //
     // Note that in reality, we are already on the NMI tss -- we just need to
     // update the PCR to reflect this
-    //      
+    //
     PCR->TSS = NmiTss;
     __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK);
     TssGdt->HighWord.Bits.Dpl = 0;
@@ -523,7 +538,7 @@ KiTrap02(VOID)
     // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
     // totally changed things.
     //
-    // We have to make sure we're still in our original NMI -- a nested NMI 
+    // We have to make sure we're still in our original NMI -- a nested NMI
     // will point back to the NMI TSS, and in that case we're hosed.
     //
     if (PCR->TSS->Backlink != KGDT_NMI_TSS)
@@ -647,8 +662,7 @@ KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
         if (!VdmDispatchBop(TrapFrame))
         {
             /* Should only happen in VDM mode */
-            UNIMPLEMENTED;
-            while (TRUE);   
+            UNIMPLEMENTED_FATAL();
         }
         
         /* Bring IRQL back */
@@ -719,8 +733,7 @@ KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
         if (SaveArea->Cr0NpxState & CR0_EM)
         {
             /* Not implemented */
-            UNIMPLEMENTED;
-            while (TRUE);
+            UNIMPLEMENTED_FATAL();
         }
     
         /* Save CR0 and check NPX state */
@@ -739,10 +752,11 @@ KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
                 NpxSaveArea = KiGetThreadNpxArea(NpxThread);
                 
                 /* Save FPU state */
+                DPRINT("FIXME: Save FPU state: %p\n", NpxSaveArea);
                 //Ke386SaveFpuState(NpxSaveArea);
 
                 /* Update NPX state */
-                Thread->NpxState = NPX_STATE_NOT_LOADED;
+                NpxThread->NpxState = NPX_STATE_NOT_LOADED;
            }
        
             /* Load FPU state */
@@ -836,7 +850,7 @@ KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame)
 
     /* Check for VDM trap */
     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
-    
+
     /* Kill the system */
     KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
 }
@@ -904,8 +918,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
         if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0))
         {
             /* Should only happen in VDM mode */
-            UNIMPLEMENTED;
-            while (TRUE);   
+            UNIMPLEMENTED_FATAL();
         }
         
         /* Bring IRQL back */
@@ -928,7 +941,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
         /* Enable interrupts and check error code */
         _enable();
         if (!TrapFrame->ErrCode)
-        {            
+        {
             /* FIXME: Use SEH */
             Instructions = (PUCHAR)TrapFrame->Eip;
             
@@ -965,6 +978,12 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
             }
             
             /* Check for privileged instructions */
+            DPRINT("Instruction (%d) at fault: %lx %lx %lx %lx\n",
+                    i,
+                    Instructions[i],
+                    Instructions[i + 1],
+                    Instructions[i + 2],
+                    Instructions[i + 3]);
             if (Instruction == 0xF4)                            // HLT
             {
                 /* HLT is privileged */
@@ -983,10 +1002,11 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
                     (Instructions[i + 1] == 0x08) ||               // INVD
                     (Instructions[i + 1] == 0x09) ||               // WBINVD
                     (Instructions[i + 1] == 0x35) ||               // SYSEXIT
-                    (Instructions[i + 1] == 0x26) ||               // MOV DR, XXX
+                    (Instructions[i + 1] == 0x21) ||               // MOV DR, XXX
                     (Instructions[i + 1] == 0x06) ||               // CLTS
                     (Instructions[i + 1] == 0x20) ||               // MOV CR, XXX
-                    (Instructions[i + 1] == 0x24) ||               // MOV YYY, DR
+                    (Instructions[i + 1] == 0x22) ||               // MOV XXX, CR
+                    (Instructions[i + 1] == 0x23) ||               // MOV YYY, DR
                     (Instructions[i + 1] == 0x30) ||               // WRMSR
                     (Instructions[i + 1] == 0x33))                 // RDPMC
                     // INVLPG, INVLPGA, SYSRET
@@ -1042,7 +1062,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
                                  TrapFrame);
     }
 
-    /* 
+    /*
      * Check for a fault during checking of the user instruction.
      *
      * Note that the SEH handler will catch invalid EIP, but we could be dealing
@@ -1053,10 +1073,9 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
         ((PVOID)TrapFrame->Eip < (PVOID)KiTrap0DHandler))
     {
         /* Not implemented */
-        UNIMPLEMENTED;
-        while (TRUE);   
+        UNIMPLEMENTED_FATAL();
     }
-    
+
     /*
      * NOTE: The ASM trap exit code would restore segment registers by doing
      * a POP <SEG>, which could cause an invalid segment if someone had messed
@@ -1095,7 +1114,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
     if (Instructions[0] == 0xCF)
     {
         /*
-         * Some evil shit is going on here -- this is not the SS:ESP you're 
+         * Some evil shit is going on here -- this is not the SS:ESP you're
          * looking for! Instead, this is actually CS:EIP you're looking at!
          * Why? Because part of the trap frame actually corresponds to the IRET
          * stack during the trap exit!
@@ -1109,15 +1128,14 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
         else
         {
             /* Otherwise, this is another kind of IRET fault */
-            UNIMPLEMENTED;
-            while (TRUE);
+            UNIMPLEMENTED_FATAL();
         }
     }
      
      /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
     if ((Instructions[0] == 0xF) &&            // 2-byte opcode
-        (((Instructions[1] >> 8) == 0x30) ||        // RDMSR
-         ((Instructions[2] >> 8) == 0x32)))         // WRMSR
+        ((Instructions[1] == 0x32) ||        // RDMSR
+         (Instructions[1] == 0x30)))         // WRMSR
     {
         /* Unknown CPU MSR, so raise an access violation */
         KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
@@ -1167,39 +1185,55 @@ KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
             FIELD_OFFSET(KTRAP_FRAME, EFlags))
         {
             /* The stack is somewhere in between frames, we need to fix it */
-            UNIMPLEMENTED;
-            while (TRUE);
+            UNIMPLEMENTED_FATAL();
         }
     }
-    
+
     /* Save CR2 */
     Cr2 = __readcr2();
-    
-    /* Check for Pentium LOCK errata */
-    if (KiI386PentiumLockErrataPresent)
+
+    /* Enable interupts */
+    _enable();
+
+    /* Check if we came in with interrupts disabled */
+    if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
     {
-        /* Not yet implemented */
-        UNIMPLEMENTED;
-        while (TRUE);
+        /* This is completely illegal, bugcheck the system */
+        KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
+                         Cr2,
+                         -1,
+                         TrapFrame->ErrCode & 2 ? TRUE : FALSE,
+                         TrapFrame->Eip,
+                         TrapFrame);
     }
-    
-    /* HACK: Check if interrupts are disabled and enable them */
-    if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
+
+    /* Check for S-LIST fault in kernel mode */
+    if (TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault)
     {
-        /* Enable interupts */
-        _enable();
-#ifdef HACK_ABOVE_FIXED
-        if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
+        PSLIST_HEADER SListHeader;
+
+        /* Sanity check that the assembly is correct:
+           This must be mov ebx, [eax]
+           Followed by cmpxchg8b [ebp] */
+        ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) &&
+               (((UCHAR*)TrapFrame->Eip)[1] == 0x18) &&
+               (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) &&
+               (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) &&
+               (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) &&
+               (((UCHAR*)TrapFrame->Eip)[5] == 0x00));
+
+        /* Get the pointer to the SLIST_HEADER */
+        SListHeader = (PSLIST_HEADER)TrapFrame->Ebp;
+
+        /* Check if the Next member of the SLIST_HEADER was changed */
+        if (SListHeader->Next.Next != (PSLIST_ENTRY)TrapFrame->Eax)
         {
-            /* This is illegal */
-            KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
-                             Cr2,
-                             -1,
-                             TrapFrame->ErrCode & 1,
-                             TrapFrame->Eip,
-                             TrapFrame);
+            /* Restart the operation */
+            TrapFrame->Eip = (ULONG_PTR)ExpInterlockedPopEntrySListResume;
+
+            /* Continue execution */
+            KiEoiHelper(TrapFrame);
         }
-#endif
     }
 
     /* Call the access fault handler */
@@ -1209,22 +1243,13 @@ KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
                            TrapFrame);
     if (NT_SUCCESS(Status)) KiEoiHelper(TrapFrame);
     
-    /* Check for S-LIST fault */
-    if (TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault)
-    {
-        /* Not yet implemented */
-        UNIMPLEMENTED;
-        while (TRUE);   
-    }
-    
     /* Check for syscall fault */
 #if 0
     if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
         (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
     {
         /* Not yet implemented */
-        UNIMPLEMENTED;
-        while (TRUE);
+        UNIMPLEMENTED_FATAL();
     }
 #endif
     /* Check for VDM trap */
@@ -1236,7 +1261,7 @@ KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
         /* This status code is repurposed so we can recognize it later */
         KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
                                  TrapFrame->Eip,
-                                 TrapFrame->ErrCode & 1,
+                                 TrapFrame->ErrCode & 2 ? TRUE : FALSE,
                                  Cr2,
                                  TrapFrame);
     }
@@ -1246,7 +1271,7 @@ KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
         /* These faults only have two parameters */
         KiDispatchException2Args(Status,
                                  TrapFrame->Eip,
-                                 TrapFrame->ErrCode & 1,
+                                 TrapFrame->ErrCode & 2 ? TRUE : FALSE,
                                  Cr2,
                                  TrapFrame);
     }
@@ -1255,7 +1280,7 @@ KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
     KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
                                      TrapFrame->Eip,
                                      3,
-                                     TrapFrame->ErrCode & 1,
+                                     TrapFrame->ErrCode & 2 ? TRUE : FALSE,
                                      Cr2,
                                      Status,
                                      TrapFrame);
@@ -1406,16 +1431,14 @@ VOID
 FASTCALL
 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
 {
-    UNIMPLEMENTED;
-    while (TRUE);
+    UNIMPLEMENTED_DBGBREAK();
 }
 
 VOID
 FASTCALL
 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
 {
-    UNIMPLEMENTED;
-    while (TRUE);
+    UNIMPLEMENTED_DBGBREAK();
 }
 
 DECLSPEC_NORETURN
@@ -1450,6 +1473,28 @@ KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
     KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
 }
 
+
+FORCEINLINE
+VOID
+KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments)
+{
+#if DBG && !defined(_WINKD_)
+    if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook)
+        KeWin32PreServiceHook(SystemCallNumber, Arguments);
+#endif
+}
+
+FORCEINLINE
+ULONG_PTR
+KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
+{
+#if DBG && !defined(_WINKD_)
+    if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook)
+        return KeWin32PostServiceHook(SystemCallNumber, Result);
+#endif
+    return Result;
+}
+
 DECLSPEC_NORETURN
 VOID
 FORCEINLINE
@@ -1477,16 +1522,22 @@ KiSystemCall(IN PKTRAP_FRAME TrapFrame,
     /* Save previous mode */
     TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
 
-    /* Save the SEH chain and terminate it for now */    
+    /* Save the SEH chain and terminate it for now */
     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
 
-    /* Clear DR7 and check for debugging */
+    /* Default to debugging disabled */
     TrapFrame->Dr7 = 0;
-    if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0))
+
+    /* Check if the frame was from user mode */
+    if (TrapFrame->SegCs & MODE_MASK)
     {
-        UNIMPLEMENTED;
-        while (TRUE);
+        /* Check for active debugging */
+        if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
+        {
+            /* Handle debug registers */
+            KiHandleDebugRegistersOnTrapEntry(TrapFrame);
+        }
     }
 
     /* Set thread fields */
@@ -1514,19 +1565,20 @@ KiSystemCall(IN PKTRAP_FRAME TrapFrame,
             goto ExitCall;
         }
 
-        /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */        
+        /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
         Result = KiConvertToGuiThread();
+
+        /* Reload trap frame and descriptor table pointer from new stack */
+        TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
+        DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
+
         if (!NT_SUCCESS(Result))
         {
             /* Set the last error and fail */
             //SetLastWin32Error(RtlNtStatusToDosError(Result));
             goto ExitCall;
         }
-            
-        /* Reload trap frame and descriptor table pointer from new stack */
-        TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
-        DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
-        
+
         /* Validate the system call number again */
         if (Id >= DescriptorTable->Limit)
         {
@@ -1556,14 +1608,19 @@ KiSystemCall(IN PKTRAP_FRAME TrapFrame,
     if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
     {
         /* Access violation */
-        UNIMPLEMENTED;
-        while (TRUE);
+        UNIMPLEMENTED_FATAL();
     }
     
+    /* Call pre-service debug hook */
+    KiDbgPreServiceHook(SystemCallNumber, Arguments);
+
     /* Get the handler and make the system call */
     Handler = (PVOID)DescriptorTable->Base[Id];
     Result = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
     
+    /* Call post-service debug hook */
+    Result = KiDbgPostServiceHook(SystemCallNumber, Result);
+
     /* Make sure we're exiting correctly */
     KiExitSystemCallDebugChecks(Id, TrapFrame);
     
@@ -1615,8 +1672,7 @@ NTAPI
 Kei386EoiHelper(VOID)
 {
     /* We should never see this call happening */
-    DPRINT1("Mismatched NT/HAL version");
-    while (TRUE);
+    ERROR_FATAL("Mismatched NT/HAL version");
 }
 
 /* EOF */