diff --git a/reactos/ntoskrnl/include/internal/i386/ke.h b/reactos/ntoskrnl/include/internal/i386/ke.h index bbcab28189d..c2c3dff2118 100644 --- a/reactos/ntoskrnl/include/internal/i386/ke.h +++ b/reactos/ntoskrnl/include/internal/i386/ke.h @@ -539,28 +539,6 @@ Ke386SanitizeFlags(IN ULONG Eflags, (EFLAGS_INTERRUPT_MASK | (Eflags & EFLAGS_USER_SANITIZE))); } -// -// 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 // diff --git a/reactos/ntoskrnl/include/internal/i386/trap_x.h b/reactos/ntoskrnl/include/internal/i386/trap_x.h index f7c75864ee5..d83276fb165 100644 --- a/reactos/ntoskrnl/include/internal/i386/trap_x.h +++ b/reactos/ntoskrnl/include/internal/i386/trap_x.h @@ -95,18 +95,37 @@ KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame) 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 @@ KiExitTrapDebugChecks(IN PKTRAP_FRAME TrapFrame, 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 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, IN PKTRAP_FRAME TrapFrame) { KIRQL OldIrql; - + /* Check if this was a user call */ if (KiUserTrap(TrapFrame)) { @@ -161,7 +207,7 @@ KiExitSystemCallDebugChecks(IN ULONG SystemCall, /* Forcibly put us in a sane state */ KeGetPcr()->Irql = PASSIVE_LEVEL; _disable(); - + /* Fail */ KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE, SystemCall, @@ -208,6 +254,53 @@ VOID 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 // @@ -218,7 +311,7 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) { PKTHREAD Thread; KIRQL OldIrql; - + /* Get the thread */ Thread = KeGetCurrentThread(); while (TRUE) @@ -243,15 +336,14 @@ KiExitV86Trap(IN PKTRAP_FRAME TrapFrame) 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 @@ KiEnterV86Trap(IN PKTRAP_FRAME TrapFrame) 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 @@ KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame) 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)) + + /* Check if the frame was from user mode or v86 mode */ + if ((TrapFrame->SegCs & MODE_MASK) || + (TrapFrame->EFlags & EFLAGS_V86_MASK)) { - DbgPrint("Need Hardware Breakpoint Support!\n"); - while (TRUE); + /* Check for active debugging */ + if (KeGetCurrentThread()->Header.DebugActive & 0xFF) + { + /* Handle debug registers */ + KiHandleDebugRegistersOnTrapEntry(TrapFrame); + } } - + /* Set debug header */ KiFillTrapFrameDebug(TrapFrame); } @@ -307,15 +406,22 @@ KiEnterTrap(IN PKTRAP_FRAME TrapFrame) { /* 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)) + + /* Check if the frame was from user mode or v86 mode */ + if ((TrapFrame->SegCs & MODE_MASK) || + (TrapFrame->EFlags & EFLAGS_V86_MASK)) { - DbgPrint("Need Hardware Breakpoint Support!\n"); - while (TRUE); + /* Check for active debugging */ + if (KeGetCurrentThread()->Header.DebugActive & 0xFF) + { + /* Handle debug registers */ + KiHandleDebugRegistersOnTrapEntry(TrapFrame); + } } - + /* Set debug header */ KiFillTrapFrameDebug(TrapFrame); } diff --git a/reactos/ntoskrnl/ke/i386/exp.c b/reactos/ntoskrnl/ke/i386/exp.c index fdf6a8fed54..a9c2e00dd9b 100644 --- a/reactos/ntoskrnl/ke/i386/exp.c +++ b/reactos/ntoskrnl/ke/i386/exp.c @@ -14,35 +14,6 @@ #define NDEBUG #include -/* 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 @@ KiRecordDr7(OUT PULONG Dr7Ptr, if (Mask != NewMask) { /* Update it */ - KeGetCurrentThread()->Header.DebugActive = - (BOOLEAN)NewMask; + KeGetCurrentThread()->Header.DebugActive = (UCHAR)NewMask; } } @@ -312,11 +282,11 @@ Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame) 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 @@ Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame) 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 @@ KeContextToTrapFrame(IN PCONTEXT Context, BOOLEAN V86Switch = FALSE; KIRQL OldIrql; ULONG DrMask = 0; - PVOID SafeDr; /* Do this at APC_LEVEL */ OldIrql = KeGetCurrentIrql(); @@ -584,26 +553,35 @@ KeContextToTrapFrame(IN PCONTEXT Context, } /* Handle the Debug Registers */ - if (0 && (ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) + if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) { - /* Loop DR registers */ - for (i = 0; i < 4; i++) + /* 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) { - /* 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); + /* 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 save and sanitize DR6 */ + /* 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 @@ KeContextToTrapFrame(IN PCONTEXT Context, if (PreviousMode != KernelMode) { /* Save the mask */ - KeGetCurrentThread()->Header.DebugActive = (DrMask != 0); + KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask; } } @@ -962,7 +940,7 @@ KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, /* 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 @@ KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code, ExceptionRecord.ExceptionInformation[1] = Parameter2; ExceptionRecord.ExceptionInformation[2] = Parameter3; } - + /* Now go dispatch the exception */ KiDispatchException(&ExceptionRecord, NULL, diff --git a/reactos/ntoskrnl/ke/i386/traphdlr.c b/reactos/ntoskrnl/ke/i386/traphdlr.c index ae5aeb34bd7..1199a0566c2 100644 --- a/reactos/ntoskrnl/ke/i386/traphdlr.c +++ b/reactos/ntoskrnl/ke/i386/traphdlr.c @@ -50,6 +50,9 @@ PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler; PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL; PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL; #endif +#if TRAP_DEBUG +BOOLEAN StopChecking = FALSE; +#endif /* TRAP EXIT CODE *************************************************************/ @@ -86,12 +89,9 @@ KiCommonExit(IN PKTRAP_FRAME TrapFrame, BOOLEAN SkipPreviousMode) { /* Disable interrupts until we return */ _disable(); - + /* Check for APC delivery */ KiCheckForApcDelivery(TrapFrame); - - /* Debugging checks */ - KiExitTrapDebugChecks(TrapFrame, SkipPreviousMode); /* Restore the SEH handler chain */ KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList; @@ -99,11 +99,17 @@ KiCommonExit(IN PKTRAP_FRAME TrapFrame, BOOLEAN SkipPreviousMode) /* 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 @@ -841,7 +847,7 @@ KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame) /* Check for VDM trap */ ASSERT((KiVdmTrap(TrapFrame)) == FALSE); - + /* Kill the system */ KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame); } @@ -1068,7 +1074,7 @@ KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) UNIMPLEMENTED; while (TRUE); } - + /* * NOTE: The ASM trap exit code would restore segment registers by doing * a POP , which could cause an invalid segment if someone had messed @@ -1524,12 +1530,18 @@ KiSystemCall(IN PKTRAP_FRAME TrapFrame, 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)) + + /* 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 */ diff --git a/reactos/ntoskrnl/ke/i386/v86vdm.c b/reactos/ntoskrnl/ke/i386/v86vdm.c index c083bc4cac4..ec9c08d29db 100644 --- a/reactos/ntoskrnl/ke/i386/v86vdm.c +++ b/reactos/ntoskrnl/ke/i386/v86vdm.c @@ -528,10 +528,7 @@ KiEnterV86Mode(IN PKV8086_STACK_FRAME StackFrame) 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();