Author: tkreuzer
Date: Wed Apr 18 13:39:19 2012
New Revision: 56357

URL: http://svn.reactos.org/svn/reactos?rev=56357&view=rev
Log:
[NTOSKRNL]
- Implement saving / restoring debug registers on traps
- Replace the loop in KeContextToTrapFrame with something less ridiculous
- fixes a number of ntdd exception winetests

Modified:
    trunk/reactos/ntoskrnl/include/internal/i386/ke.h
    trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h
    trunk/reactos/ntoskrnl/ke/i386/exp.c
    trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
    trunk/reactos/ntoskrnl/ke/i386/v86vdm.c

Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/i386/ke.h?rev=56357&r1=56356&r2=56357&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] Wed Apr 18 
13:39:19 2012
@@ -540,28 +540,6 @@
 }
 
 //
-// Gets a DR register from a CONTEXT structure
-//
-FORCEINLINE
-PVOID
-KiDrFromContext(IN ULONG Dr,
-                IN PCONTEXT Context)
-{
-    return *(PVOID*)((ULONG_PTR)Context + KiDebugRegisterContextOffsets[Dr]);
-}
-
-//
-// Gets a DR register from a KTRAP_FRAME structure
-//
-FORCEINLINE
-PVOID*
-KiDrFromTrapFrame(IN ULONG Dr,
-                  IN PKTRAP_FRAME TrapFrame)
-{
-    return (PVOID*)((ULONG_PTR)TrapFrame + KiDebugRegisterTrapOffsets[Dr]);
-}
-
-//
 // Sanitizes a Debug Register
 //
 FORCEINLINE

Modified: trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h?rev=56357&r1=56356&r2=56357&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h [iso-8859-1] 
(original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/trap_x.h [iso-8859-1] Wed Apr 
18 13:39:19 2012
@@ -95,18 +95,37 @@
     TrapFrame->PreviousPreviousMode = -1;
 }
 
+#define DR7_RESERVED_READ_AS_1 0x400
+
+#define CheckDr(DrNumner, ExpectedValue) \
+    { \
+        ULONG DrValue = __readdr(DrNumner); \
+        if (DrValue != (ExpectedValue)) \
+        { \
+            DbgPrint("Dr%ld: expected %.8lx, got %.8lx\n", \
+                    DrNumner, ExpectedValue, DrValue); \
+            __debugbreak(); \
+        } \
+    }
+
+extern BOOLEAN StopChecking;
+
 VOID
 FORCEINLINE
 KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame,
                       IN BOOLEAN SkipPreviousMode)
 {
+    /* Don't check recursively */
+    if (StopChecking) return;
+    StopChecking = TRUE;
+
     /* Make sure interrupts are disabled */
     if (__readeflags() & EFLAGS_INTERRUPT_MASK)
     {
         DbgPrint("Exiting with interrupts enabled: %lx\n", __readeflags());
         __debugbreak();
     }
-    
+
     /* Make sure this is a real trap frame */
     if (TrapFrame->DbgArgMark != 0xBADB0D00)
     {
@@ -114,34 +133,61 @@
         KiDumpTrapFrame(TrapFrame);
         __debugbreak();
     }
-    
+
     /* Make sure we're not in user-mode or something */
     if (Ke386GetFs() != KGDT_R0_PCR)
     {
         DbgPrint("Exiting with an invalid FS: %lx\n", Ke386GetFs());
         __debugbreak();
     }
-    
+
     /* Make sure we have a valid SEH chain */
     if (KeGetPcr()->NtTib.ExceptionList == 0)
     {
         DbgPrint("Exiting with NULL exception chain: %p\n", 
KeGetPcr()->NtTib.ExceptionList);
         __debugbreak();
     }
-    
+
     /* Make sure we're restoring a valid SEH chain */
     if (TrapFrame->ExceptionList == 0)
     {
         DbgPrint("Entered a trap with a NULL exception chain: %p\n", 
TrapFrame->ExceptionList);
         __debugbreak();
     }
-    
+
     /* If we're ignoring previous mode, make sure caller doesn't actually want 
it */
     if (SkipPreviousMode && (TrapFrame->PreviousPreviousMode != -1))
     {
         DbgPrint("Exiting a trap witout restoring previous mode, yet previous 
mode seems valid: %lx\n", TrapFrame->PreviousPreviousMode);
         __debugbreak();
     }
+
+    /* Check DR values */
+    if (TrapFrame->SegCs & MODE_MASK)
+    {
+        /* Check for active debugging */
+        if (KeGetCurrentThread()->Header.DebugActive)
+        {
+            if ((TrapFrame->Dr7 & ~DR7_RESERVED_MASK) == 0) __debugbreak();
+
+            CheckDr(0, TrapFrame->Dr0);
+            CheckDr(1, TrapFrame->Dr1);
+            CheckDr(2, TrapFrame->Dr2);
+            CheckDr(3, TrapFrame->Dr3);
+            CheckDr(7, TrapFrame->Dr7 | DR7_RESERVED_READ_AS_1);
+        }
+    }
+    else
+    {
+        PKPRCB Prcb = KeGetCurrentPrcb();
+        CheckDr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
+        CheckDr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
+        CheckDr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
+        CheckDr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
+        //CheckDr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7);
+    }
+
+    StopChecking = FALSE;
 }
 
 VOID
@@ -150,7 +196,7 @@
                             IN PKTRAP_FRAME TrapFrame)
 {
     KIRQL OldIrql;
-    
+
     /* Check if this was a user call */
     if (KiUserTrap(TrapFrame))
     {
@@ -161,7 +207,7 @@
             /* Forcibly put us in a sane state */
             KeGetPcr()->Irql = PASSIVE_LEVEL;
             _disable();
-            
+
             /* Fail */
             KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
                          SystemCall,
@@ -209,6 +255,53 @@
 extern PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
 
 //
+// Save user mode debug registers and restore kernel values
+//
+VOID
+FORCEINLINE
+KiHandleDebugRegistersOnTrapEntry(
+    IN PKTRAP_FRAME TrapFrame)
+{
+    PKPRCB Prcb = KeGetCurrentPrcb();
+
+    /* Save all debug registers in the trap frame */
+    TrapFrame->Dr0 = __readdr(0);
+    TrapFrame->Dr1 = __readdr(1);
+    TrapFrame->Dr2 = __readdr(2);
+    TrapFrame->Dr3 = __readdr(3);
+    TrapFrame->Dr6 = __readdr(6);
+    TrapFrame->Dr7 = __readdr(7);
+
+    /* Disable all active debugging */
+    __writedr(7, 0);
+
+    /* Restore kernel values */
+    __writedr(0, Prcb->ProcessorState.SpecialRegisters.KernelDr0);
+    __writedr(1, Prcb->ProcessorState.SpecialRegisters.KernelDr1);
+    __writedr(2, Prcb->ProcessorState.SpecialRegisters.KernelDr2);
+    __writedr(3, Prcb->ProcessorState.SpecialRegisters.KernelDr3);
+    __writedr(6, Prcb->ProcessorState.SpecialRegisters.KernelDr6);
+    __writedr(7, Prcb->ProcessorState.SpecialRegisters.KernelDr7);
+}
+
+VOID
+FORCEINLINE
+KiHandleDebugRegistersOnTrapExit(
+    PKTRAP_FRAME TrapFrame)
+{
+    /* Disable all active debugging */
+    __writedr(7, 0);
+
+    /* Load all debug registers from the trap frame */
+    __writedr(0, TrapFrame->Dr0);
+    __writedr(1, TrapFrame->Dr1);
+    __writedr(2, TrapFrame->Dr2);
+    __writedr(3, TrapFrame->Dr3);
+    __writedr(6, TrapFrame->Dr6);
+    __writedr(7, TrapFrame->Dr7);
+}
+
+//
 // Virtual 8086 Mode Optimized Trap Exit
 //
 VOID
@@ -218,7 +311,7 @@
 {
     PKTHREAD Thread;
     KIRQL OldIrql;
-    
+
     /* Get the thread */
     Thread = KeGetCurrentThread();
     while (TRUE)
@@ -243,15 +336,14 @@
         KfLowerIrql(OldIrql);
         _disable();
     }
-     
+
     /* If we got here, we're still in a valid V8086 context, so quit it */
     if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
     {
-        /* Not handled yet */
-        DbgPrint("Need Hardware Breakpoint Support!\n");
-        while (TRUE);
-    }
-     
+        /* Restore debug registers from the trap frame */
+        KiHandleDebugRegistersOnTrapExit(TrapFrame);
+    }
+
     /* Return from interrupt */
     KiTrapReturnNoSegments(TrapFrame);
 }
@@ -270,8 +362,8 @@
     TrapFrame->Dr7 = __readdr(7);
     if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
     {
-        DbgPrint("Need Hardware Breakpoint Support!\n");
-        while (TRUE);
+        /* Handle debug registers */
+        KiHandleDebugRegistersOnTrapEntry(TrapFrame);
     }
 }
 
@@ -286,14 +378,21 @@
     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
 
-    /* Flush DR7 and check for debugging */
+    /* Default to debugging disabled */
     TrapFrame->Dr7 = 0;
-    if (__builtin_expect(KeGetCurrentThread()->Header.DebugActive & 0xFF, 0))
-    {
-        DbgPrint("Need Hardware Breakpoint Support!\n");
-        while (TRUE);
-    }
-    
+
+    /* Check if the frame was from user mode or v86 mode */
+    if ((TrapFrame->SegCs & MODE_MASK) ||
+        (TrapFrame->EFlags & EFLAGS_V86_MASK))
+    {
+        /* Check for active debugging */
+        if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
+        {
+            /* Handle debug registers */
+            KiHandleDebugRegistersOnTrapEntry(TrapFrame);
+        }
+    }
+
     /* Set debug header */
     KiFillTrapFrameDebug(TrapFrame);
 }
@@ -307,15 +406,22 @@
 {
     /* Save exception list */
     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
-    
-    /* Flush DR7 and check for debugging */
+
+    /* Default to debugging disabled */
     TrapFrame->Dr7 = 0;
-    if (__builtin_expect(KeGetCurrentThread()->Header.DebugActive & 0xFF, 0))
-    {
-        DbgPrint("Need Hardware Breakpoint Support!\n");
-        while (TRUE);
-    }
-    
+
+    /* Check if the frame was from user mode or v86 mode */
+    if ((TrapFrame->SegCs & MODE_MASK) ||
+        (TrapFrame->EFlags & EFLAGS_V86_MASK))
+    {
+        /* Check for active debugging */
+        if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
+        {
+            /* Handle debug registers */
+            KiHandleDebugRegistersOnTrapEntry(TrapFrame);
+        }
+    }
+
     /* Set debug header */
     KiFillTrapFrameDebug(TrapFrame);
 }

Modified: trunk/reactos/ntoskrnl/ke/i386/exp.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/exp.c?rev=56357&r1=56356&r2=56357&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/exp.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/exp.c [iso-8859-1] Wed Apr 18 13:39:19 2012
@@ -14,35 +14,6 @@
 #define NDEBUG
 #include <debug.h>
 
-/* GLOBALS *******************************************************************/
-
-/* DR Registers in the CONTEXT structure */
-UCHAR KiDebugRegisterContextOffsets[9] =
-{
-    FIELD_OFFSET(CONTEXT, Dr0),
-    FIELD_OFFSET(CONTEXT, Dr1),
-    FIELD_OFFSET(CONTEXT, Dr2),
-    FIELD_OFFSET(CONTEXT, Dr3),
-    0,
-    0,
-    FIELD_OFFSET(CONTEXT, Dr6),
-    FIELD_OFFSET(CONTEXT, Dr7),
-    0,
-};
-
-/* DR Registers in the KTRAP_FRAME structure */
-UCHAR KiDebugRegisterTrapOffsets[9] =
-{
-    FIELD_OFFSET(KTRAP_FRAME, Dr0),
-    FIELD_OFFSET(KTRAP_FRAME, Dr1),
-    FIELD_OFFSET(KTRAP_FRAME, Dr2),
-    FIELD_OFFSET(KTRAP_FRAME, Dr3),
-    0,
-    0,
-    FIELD_OFFSET(KTRAP_FRAME, Dr6),
-    FIELD_OFFSET(KTRAP_FRAME, Dr7),
-    0,
-};
 
 /* FUNCTIONS *****************************************************************/
 
@@ -153,8 +124,7 @@
         if (Mask != NewMask)
         {
             /* Update it */
-            KeGetCurrentThread()->Header.DebugActive =
-                (BOOLEAN)NewMask;
+            KeGetCurrentThread()->Header.DebugActive = (UCHAR)NewMask;
         }
     }
 
@@ -312,11 +282,11 @@
     PKTHREAD Thread;
     ULONG_PTR Stack;
     ULONG EFlags;
-    
+
     /* Get the current thread's stack */
     Thread = KeGetCurrentThread();
     Stack = (ULONG_PTR)Thread->InitialStack;
-    
+
     /* Check if we are in V8086 mode */
     if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
     {
@@ -324,17 +294,17 @@
         Stack -= (FIELD_OFFSET(KTRAP_FRAME, V86Gs) -
                   FIELD_OFFSET(KTRAP_FRAME, HardwareSegSs));
     }
-    
+
     /* Bias the stack for the FPU area */
     Stack -= sizeof(FX_SAVE_AREA);
-    
+
     /* Disable interrupts */
     EFlags = __readeflags();
     _disable();
-    
+
     /* Set new ESP0 value in the TSS */
     KeGetPcr()->TSS->Esp0 = Stack;
-    
+
     /* Restore old interrupt state */
     __writeeflags(EFlags);
 }
@@ -352,7 +322,6 @@
     BOOLEAN V86Switch = FALSE;
     KIRQL OldIrql;
     ULONG DrMask = 0;
-    PVOID SafeDr;
 
     /* Do this at APC_LEVEL */
     OldIrql = KeGetCurrentIrql();
@@ -584,26 +553,35 @@
     }
 
     /* Handle the Debug Registers */
-    if (0 && (ContextFlags & CONTEXT_DEBUG_REGISTERS) == 
CONTEXT_DEBUG_REGISTERS)
-    {
-        /* Loop DR registers */
-        for (i = 0; i < 4; i++)
-        {
-            /* Sanitize the context DR Address */
-            SafeDr = Ke386SanitizeDr(KiDrFromContext(i, Context), 
PreviousMode);
-
-            /* Save it in the trap frame */
-            *KiDrFromTrapFrame(i, TrapFrame) = SafeDr;
-
-            /* Check if this DR address is active and add it in the DR mask */
-            if (SafeDr) DrMask |= DR_MASK(i);
-        }
-
-        /* Now save and sanitize DR6 */
+    if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
+    {
+        /* Copy Dr0 - Dr4 */
+        TrapFrame->Dr0 = Context->Dr0;
+        TrapFrame->Dr1 = Context->Dr1;
+        TrapFrame->Dr2 = Context->Dr2;
+        TrapFrame->Dr3 = Context->Dr3;
+
+        /* If we're in user-mode */
+        if (PreviousMode != KernelMode)
+        {
+            /* Make sure, no Dr address is above user space */
+            if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0;
+            if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0;
+            if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0;
+            if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0;
+        }
+
+        /* Now sanitize and save DR6 */
         TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
+
+        /* Update the Dr active mask */
+        if (TrapFrame->Dr0) DrMask |= DR_MASK(0);
+        if (TrapFrame->Dr1) DrMask |= DR_MASK(1);
+        if (TrapFrame->Dr2) DrMask |= DR_MASK(2);
+        if (TrapFrame->Dr3) DrMask |= DR_MASK(3);
         if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
 
-        /* Save and sanitize DR7 */
+        /* Sanitize and save DR7 */
         TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
         KiRecordDr7(&TrapFrame->Dr7, &DrMask);
 
@@ -611,7 +589,7 @@
         if (PreviousMode != KernelMode)
         {
             /* Save the mask */
-            KeGetCurrentThread()->Header.DebugActive = (DrMask != 0);
+            KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask;
         }
     }
 
@@ -962,7 +940,7 @@
         /* User mode exception, was it first-chance? */
         if (FirstChance)
         {
-            /* 
+            /*
              * Break into the kernel debugger unless a user mode debugger
              * is present or user mode exceptions are ignored, except if this
              * is a debug service which we must always pass to KD
@@ -1132,7 +1110,7 @@
         ExceptionRecord.ExceptionInformation[1] = Parameter2;
         ExceptionRecord.ExceptionInformation[2] = Parameter3;
     }
-    
+
     /* Now go dispatch the exception */
     KiDispatchException(&ExceptionRecord,
                         NULL,

Modified: trunk/reactos/ntoskrnl/ke/i386/traphdlr.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/traphdlr.c?rev=56357&r1=56356&r2=56357&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/traphdlr.c [iso-8859-1] Wed Apr 18 13:39:19 
2012
@@ -50,6 +50,9 @@
 PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL;
 PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL;
 #endif
+#if TRAP_DEBUG
+BOOLEAN StopChecking = FALSE;
+#endif
 
 
 /* TRAP EXIT CODE 
*************************************************************/
@@ -86,24 +89,27 @@
 {
     /* Disable interrupts until we return */
     _disable();
-    
+
     /* Check for APC delivery */
     KiCheckForApcDelivery(TrapFrame);
-    
+
+    /* Restore the SEH handler chain */
+    KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
+
+    /* Check if there are active debug registers */
+    if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
+    {
+        /* 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);
-
-    /* Restore the SEH handler chain */
-    KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
-
-    /* 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);
-    }
 }
 
 DECLSPEC_NORETURN
@@ -841,7 +847,7 @@
 
     /* Check for VDM trap */
     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
-    
+
     /* Kill the system */
     KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
 }
@@ -1068,7 +1074,7 @@
         UNIMPLEMENTED;
         while (TRUE);
     }
-    
+
     /*
      * 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
@@ -1524,12 +1530,18 @@
     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->Header.DebugActive & 0xFF, 0))
-    {
-        UNIMPLEMENTED;
-        while (TRUE);
+
+    /* Check if the frame was from user mode */
+    if (TrapFrame->SegCs & MODE_MASK)
+    {
+        /* Check for active debugging */
+        if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
+        {
+            /* Handle debug registers */
+            KiHandleDebugRegistersOnTrapEntry(TrapFrame);
+        }
     }
 
     /* Set thread fields */

Modified: trunk/reactos/ntoskrnl/ke/i386/v86vdm.c
URL: 
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/v86vdm.c?rev=56357&r1=56356&r2=56357&view=diff
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] Wed Apr 18 13:39:19 
2012
@@ -528,10 +528,7 @@
     TrapFrame->Dr7 = 0;
 
     /* Set some debug fields if trap debugging is enabled */
-#if TRAP_DEBUG
-    TrapFrame->DbgArgMark = 0xBADB0D00;
-    TrapFrame->PreviousPreviousMode = -1;
-#endif
+    KiFillTrapFrameDebug(TrapFrame);
     
     /* Disable interrupts */
     _disable();


Reply via email to