[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
index 9328de8..ebc327f 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/ke/i386/exp.c
- * PURPOSE:         Exception Support Code
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ * PURPOSE:         Exception Dispatching and Context<->Trap Frame Conversion
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Gregor Anich
- *                  David Welch (welch@cwcom.net)
  *                  Skywing (skywing@valhallalegends.com)
  */
 
-/*
- * FIXMES:
- *  - Clean up file (remove all stack functions and use RtlWalkFrameChain/RtlCaptureStackBacktrace)
- *  - Sanitize some context fields.
- *  - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
- *  - Forward exceptions to user-mode debugger.
- */
-
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
-
 #define NDEBUG
-#include <internal/debug.h>
-
-#if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, KeInitExceptions)
-#endif
+#include <debug.h>
 
-#define SIZE_OF_FX_REGISTERS 32
+/* GLOBALS *******************************************************************/
 
-VOID
-NTAPI
-Ki386AdjustEsp0(
-    IN PKTRAP_FRAME TrapFrame
-);
+/* 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 *****************************************************************/
 
 VOID
+INIT_FUNCTION
 NTAPI
-KiFlushNPXState(
-    IN FLOATING_SAVE_AREA *SaveArea
-);
-
-extern KIDTENTRY KiIdt[];
-
-/* GLOBALS *****************************************************************/
-
-#define FLAG_IF (1<<9)
-
-#define _STR(x) #x
-#define STR(x) _STR(x)
-
-#ifndef ARRAY_SIZE
-# define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
-#endif
-
-extern ULONG init_stack;
-extern ULONG init_stack_top;
-
-extern BOOLEAN Ke386NoExecute;
-
-static char *ExceptionTypeStrings[] =
-  {
-    "Divide Error",
-    "Debug Trap",
-    "NMI",
-    "Breakpoint",
-    "Overflow",
-    "BOUND range exceeded",
-    "Invalid Opcode",
-    "No Math Coprocessor",
-    "Double Fault",
-    "Unknown(9)",
-    "Invalid TSS",
-    "Segment Not Present",
-    "Stack Segment Fault",
-    "General Protection",
-    "Page Fault",
-    "Reserved(15)",
-    "Math Fault",
-    "Alignment Check",
-    "Machine Check",
-    "SIMD Fault"
-  };
-
-NTSTATUS ExceptionToNtStatus[] =
-  {
-    STATUS_INTEGER_DIVIDE_BY_ZERO,
-    STATUS_SINGLE_STEP,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_BREAKPOINT,
-    STATUS_INTEGER_OVERFLOW,
-    STATUS_ARRAY_BOUNDS_EXCEEDED,
-    STATUS_ILLEGAL_INSTRUCTION,
-    STATUS_FLOAT_INVALID_OPERATION,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_STACK_OVERFLOW,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_ACCESS_VIOLATION, /* RESERVED */
-    STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
-    STATUS_DATATYPE_MISALIGNMENT,
-    STATUS_ACCESS_VIOLATION,
-    STATUS_FLOAT_MULTIPLE_TRAPS,
-  };
-
-/* FUNCTIONS ****************************************************************/
-
-BOOLEAN STDCALL
-KiRosPrintAddress(PVOID address)
+KeInitExceptions(VOID)
 {
-   PLIST_ENTRY current_entry;
-   PLDR_DATA_TABLE_ENTRY current;
-   extern LIST_ENTRY ModuleListHead;
-   ULONG_PTR RelativeAddress;
-   ULONG i = 0;
-
-   do
-   {
-     current_entry = ModuleListHead.Flink;
-
-     while (current_entry != &ModuleListHead)
-       {
-          current =
-            CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
-
-          if (address >= (PVOID)current->DllBase &&
-              address < (PVOID)((ULONG_PTR)current->DllBase + current->SizeOfImage))
-            {
-              RelativeAddress = (ULONG_PTR) address - (ULONG_PTR) current->DllBase;
-              DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
-              return(TRUE);
-            }
-          current_entry = current_entry->Flink;
-       }
+    ULONG i;
+    USHORT FlippedSelector;
 
-     address = (PVOID)((ULONG_PTR)address & ~(ULONG_PTR)MmSystemRangeStart);
-   } while(++i <= 1);
+    /* Loop the IDT */
+    for (i = 0; i <= MAXIMUM_IDTVECTOR; i++)
+    {
+        /* Save the current Selector */
+        FlippedSelector = KiIdt[i].Selector;
 
-   return(FALSE);
+        /* Flip Selector and Extended Offset */
+        KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
+        KiIdt[i].ExtendedOffset = FlippedSelector;
+    }
 }
 
-VOID
-NTAPI
-KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
+ULONG
+FASTCALL
+KiUpdateDr7(IN ULONG Dr7)
 {
-  ULONG cr3_;
-  ULONG StackLimit;
-  ULONG Esp0;
-  ULONG ExceptionNr = (ULONG)Tf->DbgArgMark;
-  ULONG cr2 = (ULONG)Tf->DbgArgPointer;
-
-  Esp0 = (ULONG)Tf;
-
-   /*
-    * Print out the CPU registers
-    */
-   if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
-     {
-       DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
-                ExceptionNr, Tf->ErrCode&0xffff);
-     }
-   else
-     {
-       DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrCode&0xffff);
-     }
-   DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
-           Tf->SegCs&0xffff, Tf->Eip);
-   KeRosPrintAddress((PVOID)Tf->Eip);
-   DbgPrint("\n");
-   Ke386GetPageTableDirectory(cr3_);
-   DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
-   DbgPrint("Proc: %x ",PsGetCurrentProcess());
-   if (PsGetCurrentProcess() != NULL)
-     {
-       DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
-       DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
-     }
-   if (PsGetCurrentThread() != NULL)
-     {
-       DbgPrint("Thrd: %x Tid: %x",
-                PsGetCurrentThread(),
-                PsGetCurrentThread()->Cid.UniqueThread);
-     }
-   DbgPrint("\n");
-   DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->SegDs&0xffff, Tf->SegEs&0xffff,
-           Tf->SegFs&0xffff, Tf->SegGs&0xfff);
-   DbgPrint("EAX: %.8x   EBX: %.8x   ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
-   DbgPrint("EDX: %.8x   EBP: %.8x   ESI: %.8x   ESP: %.8x\n", Tf->Edx,
-           Tf->Ebp, Tf->Esi, Esp0);
-   DbgPrint("EDI: %.8x   EFLAGS: %.8x ", Tf->Edi, Tf->EFlags);
-   if ((Tf->SegCs&0xffff) == KGDT_R0_CODE)
-     {
-       DbgPrint("kESP %.8x ", Esp0);
-       if (PsGetCurrentThread() != NULL)
-         {
-            DbgPrint("kernel stack base %x\n",
-                     PsGetCurrentThread()->Tcb.StackLimit);
-
-         }
-     }
-
-   if (PsGetCurrentThread() != NULL)
-     {
-       StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
-     }
-   else
-     {
-       StackLimit = (ULONG)init_stack_top;
-     }
-
-   /*
-    * Dump the stack frames
-    */
-   KeDumpStackFrames((PULONG)Tf->Ebp);
+    ULONG DebugMask = KeGetCurrentThread()->DispatcherHeader.DebugActive;
+
+    /* Check if debugging is enabled */
+    if (DebugMask & DR_MASK(DR7_OVERRIDE_V))
+    {
+        /* Sanity checks */
+        ASSERT((DebugMask & DR_REG_MASK) != 0);
+        ASSERT((Dr7 & ~DR7_RESERVED_MASK) == DR7_OVERRIDE_MASK);
+        return 0;
+    }
+
+    /* Return DR7 itself */
+    return Dr7;
 }
 
-ULONG
-KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
-/*
- * FUNCTION: Called by the lowlevel execption handlers to print an amusing
- * message and halt the computer
- * ARGUMENTS:
- *        Complete CPU context
- */
+BOOLEAN
+FASTCALL
+KiRecordDr7(OUT PULONG Dr7Ptr,
+            OUT PULONG DrMask)
 {
-   ULONG_PTR cr2;
-   ASSERT(ExceptionNr == 13 || ExceptionNr == 6);
-
-   /* Get CR2 */
-   cr2 = Ke386GetCr2();
-   Tf->DbgArgPointer = cr2;
-
-   /*
-    * If this was a V86 mode exception then handle it specially
-    */
-   if (Tf->EFlags & (1 << 17))
-     {
-       DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->EFlags, Tf->Eip, ExceptionNr);
-       return(KeV86Exception(ExceptionNr, Tf, cr2));
-     }
-   return 0;
+    ULONG NewMask, Mask;
+    UCHAR Result;
+
+    /* Check if the caller gave us a mask */
+    if (!DrMask)
+    {
+        /* He didn't, use the one from the thread */
+        Mask = KeGetCurrentThread()->DispatcherHeader.DebugActive;
+    }
+    else
+    {
+        /* He did, read it */
+        Mask = *DrMask;
+    }
+
+    /* Sanity check */
+    ASSERT((*Dr7Ptr & DR7_RESERVED_MASK) == 0);
+
+    /* Check if DR7 is empty */
+    NewMask = Mask;
+    if (!(*Dr7Ptr))
+    {
+        /* Assume failure */
+        Result = FALSE;
+
+        /* Check the DR mask */
+        NewMask &= ~(DR_MASK(7));
+        if (NewMask & DR_REG_MASK)
+        {
+            /* Set the active mask */
+            NewMask |= DR_MASK(DR7_OVERRIDE_V);
+
+            /* Set DR7 override */
+            *Dr7Ptr |= DR7_OVERRIDE_MASK;
+        }
+        else
+        {
+            /* Sanity check */
+            ASSERT(NewMask == 0);
+        }
+    }
+    else
+    {
+        /* Check if we have a mask or not */
+        Result = NewMask ? TRUE: FALSE;
+
+        /* Update the mask to disable debugging */
+        NewMask &= ~(DR_MASK(DR7_OVERRIDE_V));
+        NewMask |= DR_MASK(7);
+    }
+
+    /* Check if caller wants the new mask */
+    if (DrMask)
+    {
+        /* Update it */
+        *DrMask = NewMask;
+    }
+    else
+    {
+        /* Check if the mask changed */
+        if (Mask != NewMask)
+        {
+            /* Update it */
+            KeGetCurrentThread()->DispatcherHeader.DebugActive =
+                (BOOLEAN)NewMask;
+        }
+    }
+
+    /* Return the result */
+    return Result;
 }
 
 ULONG
@@ -278,10 +194,19 @@ NTAPI
 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
                  IN ULONG Esp)
 {
-    ULONG Previous = KiEspFromTrapFrame(TrapFrame);
+    KIRQL OldIrql;
+    ULONG Previous;
+
+    /* Raise to APC_LEVEL if needed */
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+
+    /* Get the old ESP */
+    Previous = KiEspFromTrapFrame(TrapFrame);
 
     /* Check if this is user-mode or V86 */
-    if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
+    if ((TrapFrame->SegCs & MODE_MASK) ||
+        (TrapFrame->EFlags & EFLAGS_V86_MASK))
     {
         /* Write it directly */
         TrapFrame->HardwareEsp = Esp;
@@ -289,7 +214,11 @@ KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
     else
     {
         /* Don't allow ESP to be lowered, this is illegal */
-        if (Esp < Previous) KeBugCheck(SET_OF_INVALID_CONTEXT);
+        if (Esp < Previous) KeBugCheckEx(SET_OF_INVALID_CONTEXT,
+                                         Esp,
+                                         Previous,
+                                         (ULONG_PTR)TrapFrame,
+                                         0);
 
         /* Create an edit frame, check if it was alrady */
         if (!(TrapFrame->SegCs & FRAME_EDITED))
@@ -311,13 +240,16 @@ KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
             }
         }
     }
+
+    /* Restore IRQL */
+    if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
 }
 
 ULONG
 NTAPI
 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
 {
-    /* If this was V86 Mode */
+    /* Check if this was V86 Mode */
     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
     {
         /* Just return it */
@@ -325,7 +257,7 @@ KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
     }
     else if (TrapFrame->SegCs & MODE_MASK)
     {
-        /* Usermode, return the User SS */
+        /* User mode, return the User SS */
         return TrapFrame->HardwareSegSs | RPL_MASK;
     }
     else
@@ -360,9 +292,9 @@ USHORT
 NTAPI
 KiTagWordFnsaveToFxsave(USHORT TagWord)
 {
-    INT FxTagWord = ~TagWord; 
+    INT FxTagWord = ~TagWord;
 
-    /* 
+    /*
      * Empty is now 00, any 2 bits containing 1 mean valid
      * Now convert the rest (11->0 and the rest to 1)
      */
@@ -373,6 +305,40 @@ KiTagWordFnsaveToFxsave(USHORT TagWord)
     return FxTagWord;
 }
 
+VOID
+NTAPI
+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))
+    {
+        /* Bias the stack for the V86 segments */
+        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);
+}
+
 VOID
 NTAPI
 KeContextToTrapFrame(IN PCONTEXT Context,
@@ -384,10 +350,13 @@ KeContextToTrapFrame(IN PCONTEXT Context,
     PFX_SAVE_AREA FxSaveArea;
     ULONG i;
     BOOLEAN V86Switch = FALSE;
-    KIRQL OldIrql = APC_LEVEL;
+    KIRQL OldIrql;
+    ULONG DrMask = 0;
+    PVOID SafeDr;
 
     /* Do this at APC_LEVEL */
-    if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
 
     /* Start with the basic Registers */
     if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
@@ -400,8 +369,8 @@ KeContextToTrapFrame(IN PCONTEXT Context,
             V86Switch = TRUE;
         }
 
-        /* Copy EFLAGS. FIXME: Needs to be sanitized */
-        TrapFrame->EFlags = Context->EFlags;
+        /* Copy EFLAGS and sanitize them*/
+        TrapFrame->EFlags = Ke386SanitizeFlags(Context->EFlags, PreviousMode);
 
         /* Copy EBP and EIP */
         TrapFrame->Ebp = Context->Ebp;
@@ -415,14 +384,14 @@ KeContextToTrapFrame(IN PCONTEXT Context,
         }
         else
         {
-            /* We weren't in V86, so sanitize the CS (FIXME!) */
-            TrapFrame->SegCs = Context->SegCs;
+            /* We weren't in V86, so sanitize the CS */
+            TrapFrame->SegCs = Ke386SanitizeSeg(Context->SegCs, PreviousMode);
 
             /* Don't let it under 8, that's invalid */
             if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
             {
                 /* Force it to User CS */
-                TrapFrame->SegCs = (KGDT_R3_CODE | RPL_MASK);
+                TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
             }
         }
 
@@ -454,7 +423,7 @@ KeContextToTrapFrame(IN PCONTEXT Context,
         /* Check if we were in V86 Mode */
         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
         {
-            /* Copy the V86 Segments directlry */
+            /* Copy the V86 Segments directly */
             TrapFrame->V86Ds = Context->SegDs;
             TrapFrame->V86Es = Context->SegEs;
             TrapFrame->V86Fs = Context->SegFs;
@@ -465,12 +434,12 @@ KeContextToTrapFrame(IN PCONTEXT Context,
             /* For kernel mode, write the standard values */
             TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
             TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
-            TrapFrame->SegFs = Context->SegFs;
+            TrapFrame->SegFs = Ke386SanitizeSeg(Context->SegFs, PreviousMode);
             TrapFrame->SegGs = 0;
         }
         else
         {
-            /* For user mode, return the values directlry */
+            /* For user mode, return the values directly */
             TrapFrame->SegDs = Context->SegDs;
             TrapFrame->SegEs = Context->SegEs;
             TrapFrame->SegFs = Context->SegFs;
@@ -508,12 +477,18 @@ KeContextToTrapFrame(IN PCONTEXT Context,
                           MAXIMUM_SUPPORTED_EXTENSION);
 
             /* Remove reserved bits from MXCSR */
-            FxSaveArea->U.FxArea.MXCsr &= ~0xFFBF;
+            FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask;
 
             /* Mask out any invalid flags */
             FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
 
-            /* FIXME: Check if this is a VDM app */
+            /* Check if this is a VDM app */
+            if (PsGetCurrentProcess()->VdmObjects)
+            {
+                /* Allow the EM flag */
+                FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
+                                           (CR0_EM | CR0_MP);
+            }
         }
     }
 
@@ -566,44 +541,83 @@ KeContextToTrapFrame(IN PCONTEXT Context,
             }
             else
             {
-                /* Just dump the Fn state in */
-                RtlCopyMemory(&FxSaveArea->U.FnArea,
-                              &Context->FloatSave,
-                              sizeof(FNSAVE_FORMAT));
+                /* Copy the structure */
+                FxSaveArea->U.FnArea.ControlWord = Context->FloatSave.
+                                                   ControlWord;
+                FxSaveArea->U.FnArea.StatusWord = Context->FloatSave.
+                                                  StatusWord;
+                FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord;
+                FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave.
+                                                   ErrorOffset;
+                FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave.
+                                                     ErrorSelector;
+                FxSaveArea->U.FnArea.DataOffset = Context->FloatSave.
+                                                  DataOffset;
+                FxSaveArea->U.FnArea.DataSelector = Context->FloatSave.
+                                                    DataSelector;
+
+                /* Loop registers */
+                for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
+                {
+                    /* Copy registers */
+                    FxSaveArea->U.FnArea.RegisterArea[i] =
+                        Context->FloatSave.RegisterArea[i];
+                }
             }
 
             /* Mask out any invalid flags */
             FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
 
-            /* FIXME: Check if this is a VDM app */
+            /* Check if this is a VDM app */
+            if (PsGetCurrentProcess()->VdmObjects)
+            {
+                /* Allow the EM flag */
+                FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
+                    (CR0_EM | CR0_MP);
+            }
         }
         else
         {
             /* FIXME: Handle FPU Emulation */
-            ASSERT(FALSE);
+            //ASSERT(FALSE);
         }
     }
 
     /* Handle the Debug Registers */
-    if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
+    if (0 && (ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
     {
-        /* FIXME: All these should be sanitized */
-        TrapFrame->Dr0 = Context->Dr0;
-        TrapFrame->Dr1 = Context->Dr1;
-        TrapFrame->Dr2 = Context->Dr2;
-        TrapFrame->Dr3 = Context->Dr3;
-        TrapFrame->Dr6 = Context->Dr6;
-        TrapFrame->Dr7 = Context->Dr7;
-
-        /* Check if usermode */
+        /* 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 */
+        TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
+        if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
+
+        /* Save and sanitize DR7 */
+        TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
+        KiRecordDr7(&TrapFrame->Dr7, &DrMask);
+
+        /* If we're in user-mode */
         if (PreviousMode != KernelMode)
         {
-            /* Set the Debug Flag */
-            KeGetCurrentThread()->DispatcherHeader.DebugActive =
-                (Context->Dr7 & DR7_ACTIVE);
+            /* Save the mask */
+            KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
         }
     }
 
+    /* Check if thread has IOPL and force it enabled if so */
+    if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
+
     /* Restore IRQL */
     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
 }
@@ -621,10 +635,12 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
         FLOATING_SAVE_AREA UnalignedArea;
     } FloatSaveBuffer;
     FLOATING_SAVE_AREA *FloatSaveArea;
-    KIRQL OldIrql = APC_LEVEL;
+    KIRQL OldIrql;
+    ULONG i;
 
     /* Do this at APC_LEVEL */
-    if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
 
     /* Start with the Control flags */
     if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
@@ -743,10 +759,23 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
                 KiFlushNPXState(NULL);
             }
 
-            /* Copy into the Context */
-            RtlCopyMemory(&Context->FloatSave,
-                          FloatSaveArea,
-                          sizeof(FNSAVE_FORMAT));
+            /* Copy structure */
+            Context->FloatSave.ControlWord = FloatSaveArea->ControlWord;
+            Context->FloatSave.StatusWord = FloatSaveArea->StatusWord;
+            Context->FloatSave.TagWord = FloatSaveArea->TagWord;
+            Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset;
+            Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector;
+            Context->FloatSave.DataOffset = FloatSaveArea->DataOffset;
+            Context->FloatSave.DataSelector = FloatSaveArea->DataSelector;
+            Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState;
+
+            /* Loop registers */
+            for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
+            {
+                /* Copy them */
+                Context->FloatSave.RegisterArea[i] =
+                    FloatSaveArea->RegisterArea[i];
+            }
          }
          else
          {
@@ -759,24 +788,27 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
     if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
         CONTEXT_DEBUG_REGISTERS)
     {
-        /* Copy the debug registers */
-        Context->Dr0 = TrapFrame->Dr0;
-        Context->Dr1 = TrapFrame->Dr1;
-        Context->Dr2 = TrapFrame->Dr2;
-        Context->Dr3 = TrapFrame->Dr3;
-        Context->Dr6 = TrapFrame->Dr6;
-
-        /* For user-mode, only set DR7 if a debugger is active */
-        if (((TrapFrame->SegCs & MODE_MASK) ||
-            (TrapFrame->EFlags & EFLAGS_V86_MASK)) &&
-            (KeGetCurrentThread()->DispatcherHeader.DebugActive))
+        /* Make sure DR7 is valid */
+        if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK)
         {
-            /* Copy it over */
-            Context->Dr7 = TrapFrame->Dr7;
+            /* Copy the debug registers */
+            Context->Dr0 = TrapFrame->Dr0;
+            Context->Dr1 = TrapFrame->Dr1;
+            Context->Dr2 = TrapFrame->Dr2;
+            Context->Dr3 = TrapFrame->Dr3;
+            Context->Dr6 = TrapFrame->Dr6;
+
+            /* Update DR7 */
+            Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
         }
         else
         {
-            /* Clear it */
+            /* Otherwise clear DR registers */
+            Context->Dr0 =
+            Context->Dr1 =
+            Context->Dr2 =
+            Context->Dr3 =
+            Context->Dr6 =
             Context->Dr7 = 0;
         }
     }
@@ -785,191 +817,55 @@ KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
 }
 
-VOID
-NTAPI
-KeDumpStackFrames(PULONG Frame)
+BOOLEAN
+FASTCALL
+KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)
 {
-       PULONG StackBase, StackEnd;
-       MEMORY_BASIC_INFORMATION mbi;
-       ULONG ResultLength = sizeof(mbi);
-       NTSTATUS Status;
-
-       DbgPrint("Frames:\n");
-       _SEH_TRY
-       {
-               Status = MiQueryVirtualMemory (
-                       (HANDLE)-1,
-                       Frame,
-                       MemoryBasicInformation,
-                       &mbi,
-                       sizeof(mbi),
-                       &ResultLength );
-               if ( !NT_SUCCESS(Status) )
-               {
-                       DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
-                       return;
-               }
-
-               StackBase = Frame;
-               StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
-
-               while ( Frame >= StackBase && Frame < StackEnd )
-               {
-                       ULONG Addr = Frame[1];
-                       if (!KeRosPrintAddress((PVOID)Addr))
-                               DbgPrint("<%X>", Addr);
-                       if ( Addr == 0 || Addr == 0xDEADBEEF )
-                               break;
-                       StackBase = Frame;
-                       Frame = (PULONG)Frame[0];
-                       DbgPrint("\n");
-               }
-       }
-       _SEH_HANDLE
-       {
-       }
-       _SEH_END;
-       DbgPrint("\n");
-}
+    ULONG Eip;
+    PKTRAP_FRAME TrapFrame = TrapInformation;
+    VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
 
-VOID STDCALL
-KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
-{
-       ULONG i=0;
-       PULONG StackBase, StackEnd;
-       MEMORY_BASIC_INFORMATION mbi;
-       ULONG ResultLength = sizeof(mbi);
-       NTSTATUS Status;
-
-       DbgPrint("Frames: ");
-       _SEH_TRY
-       {
-               if ( !Frame )
-               {
-#if defined __GNUC__
-                       __asm__("mov %%ebp, %0" : "=r" (Frame) : );
-#elif defined(_MSC_VER)
-                       __asm mov [Frame], ebp
-#endif
-                       //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
-               }
-
-               Status = MiQueryVirtualMemory (
-                       (HANDLE)-1,
-                       Frame,
-                       MemoryBasicInformation,
-                       &mbi,
-                       sizeof(mbi),
-                       &ResultLength );
-               if ( !NT_SUCCESS(Status) )
-               {
-                       DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
-                       return;
-               }
-
-               StackBase = Frame;
-               StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
-
-               while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
-               {
-                       ULONG Addr = Frame[1];
-                       if (!KeRosPrintAddress((PVOID)Addr))
-                               DbgPrint("<%X>", Addr);
-                       if ( Addr == 0 || Addr == 0xDEADBEEF )
-                               break;
-                       StackBase = Frame;
-                       Frame = (PULONG)Frame[0];
-                       DbgPrint(" ");
-               }
-       }
-       _SEH_HANDLE
-       {
-       }
-       _SEH_END;
-       DbgPrint("\n");
-}
+    /* Don't do anything if we didn't get a trap frame */
+    if (!TrapInformation) return FALSE;
 
-ULONG STDCALL
-KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
-{
-       ULONG Count = 0;
-       PULONG StackBase, StackEnd, Frame;
-       MEMORY_BASIC_INFORMATION mbi;
-       ULONG ResultLength = sizeof(mbi);
-       NTSTATUS Status;
-
-       _SEH_TRY
-       {
-#if defined __GNUC__
-               __asm__("mov %%ebp, %0" : "=r" (Frame) : );
-#elif defined(_MSC_VER)
-               __asm mov [Frame], ebp
-#endif
-
-               Status = MiQueryVirtualMemory (
-                       (HANDLE)-1,
-                       Frame,
-                       MemoryBasicInformation,
-                       &mbi,
-                       sizeof(mbi),
-                       &ResultLength );
-               if ( !NT_SUCCESS(Status) )
-               {
-                       DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
-                       return 0;
-               }
-
-               StackBase = Frame;
-               StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
-
-               while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
-               {
-                       Frames[Count++] = Frame[1];
-                       StackBase = Frame;
-                       Frame = (PULONG)Frame[0];
-               }
-       }
-       _SEH_HANDLE
-       {
-       }
-       _SEH_END;
-       return Count;
-}
+    /* Check where we came from */
+    switch (TrapFrame->SegCs)
+    {
+        /* Kernel mode */
+        case KGDT_R0_CODE:
 
-VOID
-INIT_FUNCTION
-NTAPI
-KeInitExceptions(VOID)
-{
-    ULONG i;
-    USHORT FlippedSelector;
+            /* Allow S-LIST Routine to fail */
+            Eip = (ULONG)&ExpInterlockedPopEntrySListFault;
+            break;
 
-    /* Loop the IDT */
-    for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
-    {
-        /* Save the current Selector */
-        FlippedSelector = KiIdt[i].Selector;
+        /* User code */
+        case KGDT_R3_CODE | RPL_MASK:
 
-        /* Flip Selector and Extended Offset */
-        KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
-        KiIdt[i].ExtendedOffset = FlippedSelector;
+            /* Allow S-LIST Routine to fail */
+            //Eip = (ULONG)KeUserPopEntrySListFault;
+            Eip = 0;
+            break;
+
+        default:
+
+            /* Anything else gets a bugcheck */
+            Eip = 0;
     }
+
+    /* Return TRUE if we want to keep the system up */
+    return (TrapFrame->Eip == Eip) ? TRUE : FALSE;
 }
 
 VOID
 NTAPI
-KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
-                    PKEXCEPTION_FRAME ExceptionFrame,
-                    PKTRAP_FRAME TrapFrame,
-                    KPROCESSOR_MODE PreviousMode,
-                    BOOLEAN FirstChance)
+KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
+                    IN PKEXCEPTION_FRAME ExceptionFrame,
+                    IN PKTRAP_FRAME TrapFrame,
+                    IN KPROCESSOR_MODE PreviousMode,
+                    IN BOOLEAN FirstChance)
 {
     CONTEXT Context;
-    KD_CONTINUE_TYPE Action;
-    ULONG_PTR Stack, NewStack;
-    ULONG Size;
-    BOOLEAN UserDispatch = FALSE;
-    DPRINT("KiDispatchException() called\n");
+    EXCEPTION_RECORD LocalExceptRecord;
 
     /* Increase number of Exception Dispatches */
     KeGetCurrentPrcb()->KeExceptionDispatchCount++;
@@ -977,17 +873,49 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
     /* Set the context flags */
     Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
 
-    /* Check if User Mode */
-    if (PreviousMode == UserMode)
+    /* Check if User Mode or if the kernel debugger is enabled */
+    if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock))
     {
         /* Add the FPU Flag */
         Context.ContextFlags |= CONTEXT_FLOATING_POINT;
-        if (KeI386FxsrPresent) Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
+
+        /* Check for NPX Support */
+        if (KeI386FxsrPresent)
+        {
+            /* Save those too */
+            Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
+        }
     }
 
     /* Get a Context */
     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
 
+    /* Look at our exception code */
+    switch (ExceptionRecord->ExceptionCode)
+    {
+        /* Breakpoint */
+        case STATUS_BREAKPOINT:
+
+            /* Decrement EIP by one */
+            Context.Eip--;
+            break;
+
+        /* Internal exception */
+        case KI_EXCEPTION_ACCESS_VIOLATION:
+
+            /* Set correct code */
+            ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
+            if (PreviousMode == UserMode)
+            {
+                /* FIXME: Handle no execute */
+            }
+            break;
+    }
+
+    /* Sanity check */
+    ASSERT(!((PreviousMode == KernelMode) &&
+             (Context.EFlags & EFLAGS_V86_MASK)));
+
     /* Handle kernel-mode first, it's simpler */
     if (PreviousMode == KernelMode)
     {
@@ -995,81 +923,106 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
         if (FirstChance == TRUE)
         {
             /* Break into the debugger for the first time */
-            Action = KdpEnterDebuggerException(ExceptionRecord,
-                                               PreviousMode,
-                                               &Context,
-                                               TrapFrame,
-                                               TRUE,
-                                               TRUE);
-
-            /* If the debugger said continue, then continue */
-            if (Action == kdContinue) goto Handled;
-
-            /* If the Debugger couldn't handle it, dispatch the exception */
-            if (RtlDispatchException(ExceptionRecord, &Context))
+            if (KiDebugRoutine(TrapFrame,
+                               ExceptionFrame,
+                               ExceptionRecord,
+                               &Context,
+                               PreviousMode,
+                               FALSE))
             {
-                /* It was handled by an exception handler, continue */
+                /* Exception was handled */
                 goto Handled;
             }
+
+            /* If the Debugger couldn't handle it, dispatch the exception */
+            if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
         }
 
         /* This is a second-chance exception, only for the debugger */
-        Action = KdpEnterDebuggerException(ExceptionRecord,
-                                           PreviousMode,
-                                           &Context,
-                                           TrapFrame,
-                                           FALSE,
-                                           FALSE);
-
-        /* If the debugger said continue, then continue */
-        if (Action == kdContinue) goto Handled;
+        if (KiDebugRoutine(TrapFrame,
+                           ExceptionFrame,
+                           ExceptionRecord,
+                           &Context,
+                           PreviousMode,
+                           TRUE))
+        {
+            /* Exception was handled */
+            goto Handled;
+        }
 
         /* Third strike; you're out */
-        KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
-                         ExceptionRecord->ExceptionCode,
-                         (ULONG_PTR)ExceptionRecord->ExceptionAddress,
-                         ExceptionRecord->ExceptionInformation[0],
-                         ExceptionRecord->ExceptionInformation[1],
-                         TrapFrame);
+        KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
+                     ExceptionRecord->ExceptionCode,
+                     (ULONG_PTR)ExceptionRecord->ExceptionAddress,
+                     (ULONG_PTR)TrapFrame,
+                     0);
     }
     else
     {
         /* User mode exception, was it first-chance? */
         if (FirstChance)
         {
-            /* Enter Debugger if available */
-            Action = KdpEnterDebuggerException(ExceptionRecord,
-                                               PreviousMode,
-                                               &Context,
-                                               TrapFrame,
-                                               TRUE,
-                                               TRUE);
-
-            /* Exit if we're continuing */
-            if (Action == kdContinue) goto Handled;
+            /* 
+             * 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
+             */
+            if ((!(PsGetCurrentProcess()->DebugPort) &&
+                 !(KdIgnoreUmExceptions)) ||
+                 (KdIsThisAKdTrap(ExceptionRecord,
+                                  &Context,
+                                  PreviousMode)))
+            {
+                /* Call the kernel debugger */
+                if (KiDebugRoutine(TrapFrame,
+                                   ExceptionFrame,
+                                   ExceptionRecord,
+                                   &Context,
+                                   PreviousMode,
+                                   FALSE))
+                {
+                    /* Exception was handled */
+                    goto Handled;
+                }
+            }
 
-            /* FIXME: Forward exception to user mode debugger */
+            /* Forward exception to user mode debugger */
+            if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
 
             /* Set up the user-stack */
-            _SEH_TRY
+DispatchToUser:
+            _SEH2_TRY
             {
+                ULONG Size;
+                ULONG_PTR Stack, NewStack;
+
+                /* Make sure we have a valid SS and that this isn't V86 mode */
+                if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) ||
+                    (TrapFrame->EFlags & EFLAGS_V86_MASK))
+                {
+                    /* Raise an exception instead */
+                    LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
+                    LocalExceptRecord.ExceptionFlags = 0;
+                    LocalExceptRecord.NumberParameters = 0;
+                    RtlRaiseException(&LocalExceptRecord);
+                }
+
                 /* Align context size and get stack pointer */
                 Size = (sizeof(CONTEXT) + 3) & ~3;
                 Stack = (Context.Esp & ~3) - Size;
-                DPRINT("Stack: %lx\n", Stack);
 
                 /* Probe stack and copy Context */
                 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
                 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
 
                 /* Align exception record size and get stack pointer */
-                Size = (sizeof(EXCEPTION_RECORD) - 
-                        (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) *
-                        sizeof(ULONG) + 3) & ~3;
+                Size = (sizeof(EXCEPTION_RECORD) -
+                       (EXCEPTION_MAXIMUM_PARAMETERS -
+                        ExceptionRecord->NumberParameters) *
+                       sizeof(ULONG) + 3) & ~3;
                 NewStack = Stack - Size;
-                DPRINT("NewStack: %lx\n", NewStack);
 
-                /* Probe stack and copy exception record. Don't forget to add the two params */
+                /* Probe stack and copy exception record */
                 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
                               Size +  2 * sizeof(ULONG_PTR),
                               sizeof(ULONG));
@@ -1080,46 +1033,135 @@ KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
                 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
 
                 /* Set new Stack Pointer */
+                KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
                 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
 
-                /* Set EIP to the User-mode Dispathcer */
+                /* Force correct segments */
+                TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode);
+                TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
+                TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
+                TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB,  PreviousMode);
+                TrapFrame->SegGs = 0;
+
+                /* Set EIP to the User-mode Dispatcher */
                 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
-                UserDispatch = TRUE;
-                _SEH_LEAVE;
+
+                /* Dispatch exception to user-mode */
+                _SEH2_YIELD(return);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
             {
-                /* Do second-chance */
+                /* Check if we got a stack overflow and raise that instead */
+                if ((NTSTATUS)LocalExceptRecord.ExceptionCode ==
+                    STATUS_STACK_OVERFLOW)
+                {
+                    /* Copy the exception address and record */
+                    LocalExceptRecord.ExceptionAddress =
+                        ExceptionRecord->ExceptionAddress;
+                    RtlCopyMemory(ExceptionRecord,
+                                  (PVOID)&LocalExceptRecord,
+                                  sizeof(EXCEPTION_RECORD));
+
+                    /* Do the exception again */
+                    _SEH2_YIELD(goto DispatchToUser);
+                }
             }
-            _SEH_END;
+            _SEH2_END;
         }
 
-        /* If we dispatch to user, return now */
-        if (UserDispatch) return;
-
-        /* FIXME: Forward the exception to the debugger for 2nd chance */
+        /* Try second chance */
+        if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
+        {
+            /* Handled, get out */
+            return;
+        }
+        else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
+        {
+            /* Handled, get out */
+            return;
+        }
 
-        /* 3rd strike, kill the thread */
-        DPRINT1("Unhandled UserMode exception, terminating thread\n");
-        ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
-        KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
-                         ExceptionRecord->ExceptionCode,
-                         (ULONG_PTR)ExceptionRecord->ExceptionAddress,
-                         ExceptionRecord->ExceptionInformation[0],
-                         ExceptionRecord->ExceptionInformation[1],
-                         TrapFrame);
+        /* 3rd strike, kill the process */
+        DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx, BaseAddress: %lx\n",
+                PsGetCurrentProcess()->ImageFileName,
+                ExceptionRecord->ExceptionCode,
+                ExceptionRecord->ExceptionAddress,
+                PsGetCurrentProcess()->SectionBaseAddress);
+
+        ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
+        KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
+                     ExceptionRecord->ExceptionCode,
+                     (ULONG_PTR)ExceptionRecord->ExceptionAddress,
+                     (ULONG_PTR)TrapFrame,
+                     0);
     }
 
 Handled:
     /* Convert the context back into Trap/Exception Frames */
     KeContextToTrapFrame(&Context,
-                         NULL,
+                         ExceptionFrame,
                          TrapFrame,
                          Context.ContextFlags,
                          PreviousMode);
     return;
 }
 
+VOID
+NTAPI
+DECLSPEC_NORETURN
+KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,
+                                 IN ULONG_PTR Address,
+                                 IN ULONG ParameterCount,
+                                 IN ULONG_PTR Parameter1,
+                                 IN ULONG_PTR Parameter2,
+                                 IN ULONG_PTR Parameter3,
+                                 IN PKTRAP_FRAME TrapFrame)
+{
+    EXCEPTION_RECORD ExceptionRecord;
+
+    /* Build the exception record */
+    ExceptionRecord.ExceptionCode = Code;
+    ExceptionRecord.ExceptionFlags = 0;
+    ExceptionRecord.ExceptionRecord = NULL;
+    ExceptionRecord.ExceptionAddress = (PVOID)Address;
+    ExceptionRecord.NumberParameters = ParameterCount;
+    if (ParameterCount)
+    {
+        /* Copy extra parameters */
+        ExceptionRecord.ExceptionInformation[0] = Parameter1;
+        ExceptionRecord.ExceptionInformation[1] = Parameter2;
+        ExceptionRecord.ExceptionInformation[2] = Parameter3;
+    }
+    
+    /* Now go dispatch the exception */
+    KiDispatchException(&ExceptionRecord,
+                        NULL,
+                        TrapFrame,
+                        TrapFrame->EFlags & EFLAGS_V86_MASK ?
+                        -1 : KiUserTrap(TrapFrame),
+                        TRUE);
+
+    /* Return from this trap */
+    KiEoiHelper(TrapFrame);
+}
+
+VOID
+FASTCALL
+DECLSPEC_NORETURN
+KiSystemFatalException(IN ULONG ExceptionCode,
+                       IN PKTRAP_FRAME TrapFrame)
+{
+    /* Bugcheck the system */
+    KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
+                     ExceptionCode,
+                     0,
+                     0,
+                     0,
+                     TrapFrame);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
 /*
  * @implemented
  */
@@ -1127,27 +1169,29 @@ NTSTATUS
 NTAPI
 KeRaiseUserException(IN NTSTATUS ExceptionCode)
 {
-   ULONG OldEip;
-   PKTHREAD Thread = KeGetCurrentThread();
+    ULONG OldEip;
+    PTEB Teb = KeGetCurrentThread()->Teb;
+    PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
 
-   /* Make sure we can access the TEB */
-    _SEH_TRY
+    /* Make sure we can access the TEB */
+    _SEH2_TRY
     {
-        Thread->Teb->ExceptionCode = ExceptionCode;
+        /* Set the exception code */
+        Teb->ExceptionCode = ExceptionCode;
     }
-    _SEH_HANDLE
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        return(ExceptionCode);
+        /* Return the exception code */
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
     }
-    _SEH_END;
+    _SEH2_END;
 
     /* Get the old EIP */
-    OldEip = Thread->TrapFrame->Eip;
+    OldEip = TrapFrame->Eip;
 
     /* Change it to the user-mode dispatcher */
-    Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
+    TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
 
     /* Return the old EIP */
-    return((NTSTATUS)OldEip);
+    return (NTSTATUS)OldEip;
 }
-