- Use _SEH2_YIELD when returning from an exception instead of returning outside the...
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
index e923f53..6ee3c74 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/ke/i386/exp.c
- * PURPOSE:         Handling exceptions
- *
- * PROGRAMMERS:     David Welch (welch@cwcom.net)
+ * PURPOSE:         Exception Dispatching and Context<->Trap Frame Conversion
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Gregor Anich
  *                  Skywing (skywing@valhallalegends.com)
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
-
 #define NDEBUG
-#include <internal/debug.h>
-
-/* 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 void KiSystemService(void);
-extern void KiDebugService(void);
-
-extern VOID KiTrap0(VOID);
-extern VOID KiTrap1(VOID);
-extern VOID KiTrap2(VOID);
-extern VOID KiTrap3(VOID);
-extern VOID KiTrap4(VOID);
-extern VOID KiTrap5(VOID);
-extern VOID KiTrap6(VOID);
-extern VOID KiTrap7(VOID);
-extern VOID KiTrap8(VOID);
-extern VOID KiTrap9(VOID);
-extern VOID KiTrap10(VOID);
-extern VOID KiTrap11(VOID);
-extern VOID KiTrap12(VOID);
-extern VOID KiTrap13(VOID);
-extern VOID KiTrap14(VOID);
-extern VOID KiTrap15(VOID);
-extern VOID KiTrap16(VOID);
-extern VOID KiTrap17(VOID);
-extern VOID KiTrap18(VOID);
-extern VOID KiTrap19(VOID);
-extern VOID KiTrapUnknown(VOID);
-
-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)
+#include <debug.h>
+
+/* GLOBALS *******************************************************************/
+
+/* DR Registers in the CONTEXT structure */
+UCHAR KiDebugRegisterContextOffsets[9] =
 {
-   PLIST_ENTRY current_entry;
-   MODULE_TEXT_SECTION* current;
-   extern LIST_ENTRY ModuleTextListHead;
-   ULONG_PTR RelativeAddress;
-   ULONG i = 0;
-
-   do
-   {
-     current_entry = ModuleTextListHead.Flink;
-
-     while (current_entry != &ModuleTextListHead &&
-            current_entry != NULL)
-       {
-          current =
-            CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
-
-          if (address >= (PVOID)current->Base &&
-              address < (PVOID)(current->Base + current->Length))
-            {
-              RelativeAddress = (ULONG_PTR) address - current->Base;
-              DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
-              return(TRUE);
-            }
-          current_entry = current_entry->Flink;
-       }
+    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
+KeInitExceptions(VOID)
+{
+    ULONG i;
+    USHORT FlippedSelector;
+    extern KIDTENTRY KiIdt[MAXIMUM_IDTVECTOR];
 
-     address = (PVOID)((ULONG_PTR)address & ~0xC0000000);
-   } 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;
+    }
 }
 
 ULONG
-KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
+FASTCALL
+KiUpdateDr7(IN ULONG Dr7)
 {
-  EXCEPTION_RECORD Er;
+    ULONG DebugMask = KeGetCurrentThread()->DispatcherHeader.DebugActive;
 
-  Er.ExceptionFlags = 0;
-  Er.ExceptionRecord = NULL;
-  Er.ExceptionAddress = (PVOID)Tf->Eip;
+    /* 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;
+    }
 
-  if (ExceptionNr == 14)
+    /* Return DR7 itself */
+    return Dr7;
+}
+
+BOOLEAN
+FASTCALL
+KiRecordDr7(OUT PULONG Dr7Ptr,
+            OUT PULONG DrMask)
+{
+    ULONG NewMask, Mask;
+    UCHAR Result;
+
+    /* Check if the caller gave us a mask */
+    if (!DrMask)
     {
-      Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
-      Er.NumberParameters = 2;
-      Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
-      Er.ExceptionInformation[1] = (ULONG)Cr2;
+        /* He didn't, use the one from the thread */
+        Mask = KeGetCurrentThread()->DispatcherHeader.DebugActive;
     }
-  else
+    else
     {
-      if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
-       {
-         Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
-       }
-      else
-       {
-         Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
-       }
-      Er.NumberParameters = 0;
+        /* He did, read it */
+        Mask = *DrMask;
     }
 
-  /* FIXME: Which exceptions are noncontinuable? */
-  Er.ExceptionFlags = 0;
+    /* Sanity check */
+    ASSERT((*Dr7Ptr & DR7_RESERVED_MASK) == 0);
 
-  KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
+    /* 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(0);
+    /* Return the result */
+    return Result;
 }
 
 ULONG
-KiDoubleFaultHandler(VOID)
+NTAPI
+KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
 {
-  unsigned int cr2;
-  ULONG StackLimit;
-  ULONG StackBase;
-  ULONG Esp0;
-  ULONG ExceptionNr = 8;
-  KTSS* OldTss;
-  PULONG Frame;
-  ULONG OldCr3;
-#if 0
-  ULONG i, j;
-  static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
-  static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
-  static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
-  ULONG TraceLength;
-  BOOLEAN FoundRepeat;
-#endif
-
-  OldTss = KeGetCurrentKPCR()->TSS;
-  Esp0 = OldTss->Esp;
-
-  /* Get CR2 */
-  cr2 = Ke386GetCr2();
-  if (PsGetCurrentThread() != NULL &&
-      PsGetCurrentThread()->ThreadsProcess != NULL)
-    {
-      OldCr3 = (ULONG)
-       PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
-    }
-  else
-    {
-      OldCr3 = 0xBEADF0AL;
-    }
-
-   /*
-    * Check for stack underflow
-    */
-   if (PsGetCurrentThread() != NULL &&
-       Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
-     {
-       DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
-                Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
-       ExceptionNr = 12;
-     }
-
-   /*
-    * Print out the CPU registers
-    */
-   if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
-     {
-       DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
-               ExceptionNr, 0);
-     }
-   else
-     {
-       DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
-     }
-   DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
-   KeRosPrintAddress((PVOID)OldTss->Eip);
-   DbgPrint("\n");
-   DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
-   DbgPrint("Proc: %x ",PsGetCurrentProcess());
-   if (PsGetCurrentProcess() != NULL)
-     {
-       DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
-       DbgPrint("%.8s> ", 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", OldTss->Ds, OldTss->Es,
-           OldTss->Fs, OldTss->Gs);
-   DbgPrint("EAX: %.8x   EBX: %.8x   ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
-           OldTss->Ecx);
-   DbgPrint("EDX: %.8x   EBP: %.8x   ESI: %.8x\n   ESP: %.8x", OldTss->Edx,
-           OldTss->Ebp, OldTss->Esi, Esp0);
-   DbgPrint("EDI: %.8x   EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
-   if (OldTss->Cs == KERNEL_CS)
-     {
-       DbgPrint("kESP %.8x ", Esp0);
-       if (PsGetCurrentThread() != NULL)
-         {
-            DbgPrint("kernel stack base %x\n",
-                     PsGetCurrentThread()->Tcb.StackLimit);
-
-         }
-     }
-   else
-     {
-       DbgPrint("User ESP %.8x\n", OldTss->Esp);
-     }
-  if ((OldTss->Cs & 0xffff) == KERNEL_CS)
-    {
-      if (PsGetCurrentThread() != NULL)
-       {
-         StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
-         StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
-       }
-      else
-       {
-         StackLimit = (ULONG)init_stack_top;
-         StackBase = (ULONG)init_stack;
-       }
-
-      /*
-        Change to an #if 0 to reduce the amount of information printed on
-        a recursive stack trace.
-      */
-#if 1
-      DbgPrint("Frames: ");
-      Frame = (PULONG)OldTss->Ebp;
-      while (Frame != NULL && (ULONG)Frame >= StackBase)
-       {
-         KeRosPrintAddress((PVOID)Frame[1]);
-         Frame = (PULONG)Frame[0];
-          DbgPrint("\n");
-       }
-#else
-      DbgPrint("Frames: ");
-      i = 0;
-      Frame = (PULONG)OldTss->Ebp;
-      while (Frame != NULL && (ULONG)Frame >= StackBase)
-       {
-         StackTrace[i] = (PVOID)Frame[1];
-         Frame = (PULONG)Frame[0];
-         i++;
-       }
-      TraceLength = i;
-
-      i = 0;
-      while (i < TraceLength)
-       {
-         StackRepeatCount[i] = 0;
-         j = i + 1;
-         FoundRepeat = FALSE;
-         while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
-           {
-             if (memcmp(&StackTrace[i], &StackTrace[j],
-                        (j - i) * sizeof(PVOID)) == 0)
-               {
-                 StackRepeatCount[i] = 2;
-                 StackRepeatLength[i] = j - i;
-                 FoundRepeat = TRUE;
-               }
-             else
-               {
-                 j++;
-               }
-           }
-         if (FoundRepeat == FALSE)
-           {
-             i++;
-             continue;
-           }
-         j = j + StackRepeatLength[i];
-         while ((TraceLength - j) >= StackRepeatLength[i] &&
-                FoundRepeat == TRUE)
-           {
-             if (memcmp(&StackTrace[i], &StackTrace[j],
-                        StackRepeatLength[i] * sizeof(PVOID)) == 0)
-               {
-                 StackRepeatCount[i]++;
-                 j = j + StackRepeatLength[i];
-               }
-             else
-               {
-                 FoundRepeat = FALSE;
-               }
-           }
-         i = j;
-       }
-
-      i = 0;
-      while (i < TraceLength)
-       {
-         if (StackRepeatCount[i] == 0)
-           {
-             KeRosPrintAddress(StackTrace[i]);
-             i++;
-           }
-         else
-           {
-             DbgPrint("{");
-             if (StackRepeatLength[i] == 0)
-               {
-                 for(;;);
-               }
-             for (j = 0; j < StackRepeatLength[i]; j++)
-               {
-                 KeRosPrintAddress(StackTrace[i + j]);
-               }
-             DbgPrint("}*%d", StackRepeatCount[i]);
-             i = i + StackRepeatLength[i] * StackRepeatCount[i];
-           }
-       }
-#endif
-    }
-
-   DbgPrint("\n");
-   for(;;);
-   return 0;
+    /* Check if this is user-mode or V86 */
+    if ((TrapFrame->SegCs & MODE_MASK) ||
+        (TrapFrame->EFlags & EFLAGS_V86_MASK))
+    {
+        /* Return it directly */
+        return TrapFrame->HardwareEsp;
+    }
+    else
+    {
+        /* Edited frame */
+        if (!(TrapFrame->SegCs & FRAME_EDITED))
+        {
+            /* Return edited value */
+            return TrapFrame->TempEsp;
+        }
+        else
+        {
+            /* Virgin frame, calculate */
+            return (ULONG)&TrapFrame->HardwareEsp;
+        }
+    }
 }
 
 VOID
-KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
+NTAPI
+KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
+                 IN ULONG Esp)
 {
-  ULONG cr3_;
-  ULONG StackLimit;
-  ULONG Esp0;
-  ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
-  ULONG cr2 = (ULONG)Tf->DebugPointer;
-
-  Esp0 = (ULONG)Tf;
-
-   /*
-    * Print out the CPU registers
-    */
-   if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
-     {
-       DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
-                ExceptionNr, Tf->ErrorCode&0xffff);
-     }
-   else
-     {
-       DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
-     }
-   DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
-           Tf->Cs&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("%.8s> ", 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->Ds&0xffff, Tf->Es&0xffff,
-           Tf->Fs&0xffff, Tf->Gs&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->Cs&0xffff) == KERNEL_CS)
-     {
-       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);
+    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))
+    {
+        /* Write it directly */
+        TrapFrame->HardwareEsp = Esp;
+    }
+    else
+    {
+        /* Don't allow ESP to be lowered, this is illegal */
+        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))
+        {
+            /* Update the value */
+            TrapFrame->TempEsp = Esp;
+        }
+        else
+        {
+            /* Check if ESP changed */
+            if (Previous != Esp)
+            {
+                /* Save CS */
+                TrapFrame->TempSegCs = TrapFrame->SegCs;
+                TrapFrame->SegCs &= ~FRAME_EDITED;
+
+                /* Save ESP */
+                TrapFrame->TempEsp = Esp;
+            }
+        }
+    }
+
+    /* Restore IRQL */
+    if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
 }
 
 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
- */
+NTAPI
+KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
 {
-   unsigned int cr2;
-   NTSTATUS Status;
-   ULONG Esp0;
-
-   /* Store the exception number in an unused field in the trap frame. */
-   Tf->DebugArgMark = (PVOID)ExceptionNr;
-
-   /* Use the address of the trap frame as approximation to the ring0 esp */
-   Esp0 = (ULONG)&Tf->Eip;
-
-   /* Get CR2 */
-   cr2 = Ke386GetCr2();
-   Tf->DebugPointer = (PVOID)cr2;
-
-   if (ExceptionNr == 14 && Tf->Eflags & FLAG_IF)
-   {
-     Ke386EnableInterrupts();
-   }
-
-   /*
-    * 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));
-     }
-
-   /*
-    * Check for stack underflow, this may be obsolete
-    */
-   if (PsGetCurrentThread() != NULL &&
-       Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
-     {
-       DPRINT1("Stack underflow (tf->esp %x Limit %x)\n",
-                Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
-       ExceptionNr = 12;
-     }
-
-   if (ExceptionNr == 15)
-     {
-       /*
-        * FIXME:
-        *   This exception should never occur. The P6 has a bug, which does sometimes deliver
-        *   the apic spurious interrupt as exception 15. On an athlon64, I get one exception
-        *   in the early boot phase in apic mode (using the smp build). I've looked to the linux
-        *   sources. Linux does ignore this exception.
-        *
-        *   Hartmut Birr
-        */
-       DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
-       return(0);
-     }
-
-   /*
-    * Maybe handle the page fault and return
-    */
-   if (ExceptionNr == 14)
-     {
-        if (Ke386NoExecute && Tf->ErrorCode & 0x10 && cr2 >= KERNEL_BASE)
-       {
-           KEBUGCHECKWITHTF(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY, 0, 0, 0, 0, Tf);
-       }
-       Status = MmPageFault(Tf->Cs&0xffff,
-                            &Tf->Eip,
-                            &Tf->Eax,
-                            cr2,
-                            Tf->ErrorCode);
-       if (NT_SUCCESS(Status))
-         {
-            return(0);
-         }
-     }
-
-   /*
-    * Check for a breakpoint that was only for the attention of the debugger.
-    */
-   if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
-     {
-       /*
-         EIP is already adjusted by the processor to point to the instruction
-         after the breakpoint.
-       */
-       return(0);
-     }
-
-   /*
-    * Try to handle device-not-present, math-fault and xmm-fault exceptions.
-    */
-   if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
-     {
-       Status = KiHandleFpuFault(Tf, ExceptionNr);
-       if (NT_SUCCESS(Status))
-         {
-           return(0);
-         }
-     }
+    /* Check if this was V86 Mode */
+    if (TrapFrame->EFlags & EFLAGS_V86_MASK)
+    {
+        /* Just return it */
+        return TrapFrame->HardwareSegSs;
+    }
+    else if (TrapFrame->SegCs & MODE_MASK)
+    {
+        /* User mode, return the User SS */
+        return TrapFrame->HardwareSegSs | RPL_MASK;
+    }
+    else
+    {
+        /* Kernel mode */
+        return KGDT_R0_DATA;
+    }
+}
+
+VOID
+NTAPI
+KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
+                IN ULONG Ss)
+{
+    /* Remove the high-bits */
+    Ss &= 0xFFFF;
 
-   /*
-    * Handle user exceptions differently
-    */
-   if ((Tf->Cs & 0xFFFF) == USER_CS)
-     {
-       return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
-     }
-   else
+    /* If this was V86 Mode */
+    if (TrapFrame->EFlags & EFLAGS_V86_MASK)
     {
-      return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
+        /* Just write it */
+        TrapFrame->HardwareSegSs = Ss;
+    }
+    else if (TrapFrame->SegCs & MODE_MASK)
+    {
+        /* Usermode, save the User SS */
+        TrapFrame->HardwareSegSs = Ss | RPL_MASK;
     }
 }
 
-BOOLEAN
-STDCALL
-KeContextToTrapFrame(PCONTEXT Context,
-                     PKTRAP_FRAME TrapFrame)
+USHORT
+NTAPI
+KiTagWordFnsaveToFxsave(USHORT 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)
+     */
+    FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
+    FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
+    FxTagWord = (FxTagWord | (FxTagWord >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
+    FxTagWord = (FxTagWord | (FxTagWord >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
+    return FxTagWord;
+}
+
+VOID
+NTAPI
+KeContextToTrapFrame(IN PCONTEXT Context,
+                     IN OUT PKEXCEPTION_FRAME ExceptionFrame,
+                     IN OUT PKTRAP_FRAME TrapFrame,
+                     IN ULONG ContextFlags,
+                     IN KPROCESSOR_MODE PreviousMode)
+{
+    PFX_SAVE_AREA FxSaveArea;
+    ULONG i;
+    BOOLEAN V86Switch = FALSE;
+    KIRQL OldIrql;
+    ULONG DrMask = 0;
+    PVOID SafeDr;
+
+    /* Do this at APC_LEVEL */
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+
     /* Start with the basic Registers */
-    if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+    if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
     {
-        TrapFrame->Esp = Context->Esp;
-        TrapFrame->Ss = Context->SegSs;
-        TrapFrame->Cs = Context->SegCs;
-        TrapFrame->Eip = Context->Eip;
-        TrapFrame->Eflags = Context->EFlags;   
+        /* Check if we went through a V86 switch */
+        if ((Context->EFlags & EFLAGS_V86_MASK) !=
+            (TrapFrame->EFlags & EFLAGS_V86_MASK))
+        {
+            /* We did, remember this for later */
+            V86Switch = TRUE;
+        }
+
+        /* Copy EFLAGS and sanitize them*/
+        TrapFrame->EFlags = Ke386SanitizeFlags(Context->EFlags, PreviousMode);
+
+        /* Copy EBP and EIP */
         TrapFrame->Ebp = Context->Ebp;
+        TrapFrame->Eip = Context->Eip;
+
+        /* Check if we were in V86 Mode */
+        if (TrapFrame->EFlags & EFLAGS_V86_MASK)
+        {
+            /* Simply copy the CS value */
+            TrapFrame->SegCs = Context->SegCs;
+        }
+        else
+        {
+            /* 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;
+            }
+        }
+
+        /* Handle SS Specially for validation */
+        KiSsToTrapFrame(TrapFrame, Context->SegSs);
+
+        /* Write ESP back; take into account Edited Trap Frames */
+        KiEspToTrapFrame(TrapFrame, Context->Esp);
+
+        /* Handle our V86 Bias if we went through a switch */
+        if (V86Switch) Ki386AdjustEsp0(TrapFrame);
     }
-    
+
     /* Process the Integer Registers */
-    if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+    if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
     {
+        /* Copy them manually */
         TrapFrame->Eax = Context->Eax;
         TrapFrame->Ebx = Context->Ebx;
         TrapFrame->Ecx = Context->Ecx;
@@ -607,377 +383,718 @@ KeContextToTrapFrame(PCONTEXT Context,
         TrapFrame->Esi = Context->Esi;
         TrapFrame->Edi = Context->Edi;
     }
-    
+
     /* Process the Context Segments */
-    if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
+    if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
     {
-        TrapFrame->Ds = Context->SegDs;
-        TrapFrame->Es = Context->SegEs;
-        TrapFrame->Fs = Context->SegFs;
-        TrapFrame->Gs = Context->SegGs;
+        /* Check if we were in V86 Mode */
+        if (TrapFrame->EFlags & EFLAGS_V86_MASK)
+        {
+            /* Copy the V86 Segments directly */
+            TrapFrame->V86Ds = Context->SegDs;
+            TrapFrame->V86Es = Context->SegEs;
+            TrapFrame->V86Fs = Context->SegFs;
+            TrapFrame->V86Gs = Context->SegGs;
+        }
+        else if (!(TrapFrame->SegCs & MODE_MASK))
+        {
+            /* For kernel mode, write the standard values */
+            TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
+            TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
+            TrapFrame->SegFs = Ke386SanitizeSeg(Context->SegFs, PreviousMode);
+            TrapFrame->SegGs = 0;
+        }
+        else
+        {
+            /* For user mode, return the values directly */
+            TrapFrame->SegDs = Context->SegDs;
+            TrapFrame->SegEs = Context->SegEs;
+            TrapFrame->SegFs = Context->SegFs;
+
+            /* Handle GS specially */
+            if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
+            {
+                /* Don't use it, if user */
+                TrapFrame->SegGs = 0;
+            }
+            else
+            {
+                /* Copy it if kernel */
+                TrapFrame->SegGs = Context->SegGs;
+            }
+        }
+    }
+
+    /* Handle the extended registers */
+    if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
+        CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
+    {
+        /* Get the FX Area */
+        FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
+
+        /* Check if NPX is present */
+        if (KeI386NpxPresent)
+        {
+            /* Flush the NPX State */
+            KiFlushNPXState(NULL);
+
+            /* Copy the FX State */
+            RtlCopyMemory(&FxSaveArea->U.FxArea,
+                          &Context->ExtendedRegisters[0],
+                          MAXIMUM_SUPPORTED_EXTENSION);
+
+            /* Remove reserved bits from MXCSR */
+            FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask;
+
+            /* Mask out any invalid flags */
+            FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
+
+            /* Check if this is a VDM app */
+            if (PsGetCurrentProcess()->VdmObjects)
+            {
+                /* Allow the EM flag */
+                FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
+                                           (CR0_EM | CR0_MP);
+            }
+        }
+    }
+
+    /* Handle the floating point state */
+    if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
+        CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
+    {
+        /* Get the FX Area */
+        FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
+
+        /* Check if NPX is present */
+        if (KeI386NpxPresent)
+        {
+            /* Flush the NPX State */
+            KiFlushNPXState(NULL);
+
+            /* Check if we have Fxsr support */
+            if (KeI386FxsrPresent)
+            {
+                /* Convert the Fn Floating Point state to Fx */
+                FxSaveArea->U.FxArea.ControlWord =
+                    (USHORT)Context->FloatSave.ControlWord;
+                FxSaveArea->U.FxArea.StatusWord =
+                    (USHORT)Context->FloatSave.StatusWord;
+                FxSaveArea->U.FxArea.TagWord =
+                    KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord);
+                FxSaveArea->U.FxArea.ErrorOpcode =
+                    (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF);
+                FxSaveArea->U.FxArea.ErrorOffset =
+                    Context->FloatSave.ErrorOffset;
+                FxSaveArea->U.FxArea.ErrorSelector =
+                    Context->FloatSave.ErrorSelector & 0xFFFF;
+                FxSaveArea->U.FxArea.DataOffset =
+                    Context->FloatSave.DataOffset;
+                FxSaveArea->U.FxArea.DataSelector =
+                    Context->FloatSave.DataSelector;
+
+                /* Clear out the Register Area */
+                RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0],
+                              SIZE_OF_FX_REGISTERS);
+
+                /* Loop the 8 floating point registers */
+                for (i = 0; i < 8; i++)
+                {
+                    /* Copy from Fn to Fx */
+                    RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
+                                  Context->FloatSave.RegisterArea + (i * 10),
+                                  10);
+                }
+            }
+            else
+            {
+                /* 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);
+
+            /* 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);
+        }
     }
-     
+
     /* Handle the Debug Registers */
-    if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
-    {
-        TrapFrame->Dr0 = Context->Dr0;
-        TrapFrame->Dr1 = Context->Dr1;
-        TrapFrame->Dr2 = Context->Dr2;
-        TrapFrame->Dr3 = Context->Dr3;
-        TrapFrame->Dr6 = Context->Dr6;
-        TrapFrame->Dr7 = Context->Dr7;
-    }
-    
-    /* Handle FPU and Extended Registers */
-    return KiContextToFxSaveArea((PFX_SAVE_AREA)(TrapFrame + 1), Context);
-}
+    if ((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 */
+        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)
+        {
+            /* Save the mask */
+            KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
+        }
+    }
 
-VOID
-KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
-                    PCONTEXT Context)
-{
-   if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
-     {
-       Context->SegSs = TrapFrame->Ss;
-       Context->Esp = TrapFrame->Esp;
-       Context->SegCs = TrapFrame->Cs;
-       Context->Eip = TrapFrame->Eip;
-       Context->EFlags = TrapFrame->Eflags;
-       Context->Ebp = TrapFrame->Ebp;
-     }
-   if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
-     {
-       Context->Eax = TrapFrame->Eax;
-       Context->Ebx = TrapFrame->Ebx;
-       Context->Ecx = TrapFrame->Ecx;
-       /*
-        * NOTE: In the trap frame which is built on entry to a system
-        * call TrapFrame->Edx will actually hold the address of the
-        * previous TrapFrame. I don't believe leaking this information
-        * has security implications. Also EDX holds the address of the
-        * arguments to the system call in progress so it isn't of much
-        * interest to the debugger.
-        */
-       Context->Edx = TrapFrame->Edx;
-       Context->Esi = TrapFrame->Esi;
-       Context->Edi = TrapFrame->Edi;
-     }
-   if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
-     {
-       Context->SegDs = TrapFrame->Ds;
-       Context->SegEs = TrapFrame->Es;
-       Context->SegFs = TrapFrame->Fs;
-       Context->SegGs = TrapFrame->Gs;
-     }
-   if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
-     {
-       /*
-        * FIXME: Implement this case
-        */     
-       Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
-     }
-   if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
-     {
-       /*
-        * FIXME: Implement this case
-        *
-        * I think this should only be filled for FPU exceptions, otherwise I
-         * would not know where to get it from as it can be the current state
-        * of the FPU or already saved in the thread's FPU save area.
-        *  -blight
-        */
-       Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
-     }
-#if 0
-   if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
-     {
-       /*
-        * FIXME: Investigate this
-        *
-        * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
-        * This should only be filled in case of a SIMD exception I think, so
-        * this is not the right place (like for FPU the state could already be
-        * saved in the thread's FX_SAVE_AREA or still be in the CPU)
-        *  -blight
-        */
-        Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS;
-     }
-#endif
+    /* 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);
 }
 
 VOID
-KeDumpStackFrames(PULONG Frame)
+NTAPI
+KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
+                     IN PKEXCEPTION_FRAME ExceptionFrame,
+                     IN OUT PCONTEXT Context)
 {
-       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: NtQueryVirtualMemory() failed: %x\n", Status );
-                       return;
-               }
-
-               StackBase = Frame;
-               StackEnd = 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");
-}
+    PFX_SAVE_AREA FxSaveArea;
+    struct _AlignHack
+    {
+        UCHAR Hack[15];
+        FLOATING_SAVE_AREA UnalignedArea;
+    } FloatSaveBuffer;
+    FLOATING_SAVE_AREA *FloatSaveArea;
+    KIRQL OldIrql;
+    ULONG i;
+
+    /* Do this at APC_LEVEL */
+    OldIrql = KeGetCurrentIrql();
+    if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
+
+    /* Start with the Control flags */
+    if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+    {
+        /* EBP, EIP and EFLAGS */
+        Context->Ebp = TrapFrame->Ebp;
+        Context->Eip = TrapFrame->Eip;
+        Context->EFlags = TrapFrame->EFlags;
+
+        /* Return the correct CS */
+        if (!(TrapFrame->SegCs & FRAME_EDITED) &&
+            !(TrapFrame->EFlags & EFLAGS_V86_MASK))
+        {
+            /* Get it from the Temp location */
+            Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
+        }
+        else
+        {
+            /* Return it directly */
+            Context->SegCs = TrapFrame->SegCs & 0xFFFF;
+        }
+
+        /* Get the Ss and ESP */
+        Context->SegSs = KiSsFromTrapFrame(TrapFrame);
+        Context->Esp = KiEspFromTrapFrame(TrapFrame);
+    }
 
-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, %%ebx" : "=b" (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: NtQueryVirtualMemory() failed: %x\n", Status );
-                       return;
-               }
-
-               StackBase = Frame;
-               StackEnd = 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");
-}
+    /* Handle the Segments */
+    if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
+    {
+        /* Do V86 Mode first */
+        if (TrapFrame->EFlags & EFLAGS_V86_MASK)
+        {
+            /* Return from the V86 location */
+            Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
+            Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
+            Context->SegEs = TrapFrame->V86Es & 0xFFFF;
+            Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
+        }
+        else
+        {
+            /* Check if this was a Kernel Trap */
+            if (TrapFrame->SegCs == KGDT_R0_CODE)
+            {
+                /* Set valid selectors */
+                TrapFrame->SegGs = 0;
+                TrapFrame->SegFs = KGDT_R0_PCR;
+                TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
+                TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
+            }
 
-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, %%ebx" : "=b" (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: NtQueryVirtualMemory() failed: %x\n", Status );
-                       return 0;
-               }
-
-               StackBase = Frame;
-               StackEnd = 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;
-}
+            /* Return the segments */
+            Context->SegGs = TrapFrame->SegGs & 0xFFFF;
+            Context->SegFs = TrapFrame->SegFs & 0xFFFF;
+            Context->SegEs = TrapFrame->SegEs & 0xFFFF;
+            Context->SegDs = TrapFrame->SegDs & 0xFFFF;
+        }
+    }
 
-static void
-set_system_call_gate(unsigned int sel, unsigned int func)
-{
-   DPRINT("sel %x %d\n",sel,sel);
-   KiIdt[sel].a = (((int)func)&0xffff) +
-     (KERNEL_CS << 16);
-   KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
-   DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
-}
+    /* Handle the simple registers */
+    if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+    {
+        /* Return them directly */
+        Context->Eax = TrapFrame->Eax;
+        Context->Ebx = TrapFrame->Ebx;
+        Context->Ecx = TrapFrame->Ecx;
+        Context->Edx = TrapFrame->Edx;
+        Context->Esi = TrapFrame->Esi;
+        Context->Edi = TrapFrame->Edi;
+    }
 
-static void set_interrupt_gate(unsigned int sel, unsigned int func)
-{
-   DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
-   KiIdt[sel].a = (((int)func)&0xffff) +
-     (KERNEL_CS << 16);
-   KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
-}
+    /* Handle extended registers */
+    if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
+        CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
+    {
+        /* Get the FX Save Area */
+        FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
+
+        /* Make sure NPX is present */
+        if (KeI386NpxPresent)
+        {
+            /* Flush the NPX State */
+            KiFlushNPXState(NULL);
+
+            /* Copy the registers */
+            RtlCopyMemory(&Context->ExtendedRegisters[0],
+                          &FxSaveArea->U.FxArea,
+                          MAXIMUM_SUPPORTED_EXTENSION);
+        }
+    }
 
-static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
-{
-   DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
-   ASSERT(dpl <= 3);
-   KiIdt[sel].a = (((int)func)&0xffff) +
-     (KERNEL_CS << 16);
-   KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
-}
+    /* Handle Floating Point */
+    if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
+        CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
+    {
+        /* Get the FX Save Area */
+        FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
 
-static void
-set_task_gate(unsigned int sel, unsigned task_sel)
-{
-  KiIdt[sel].a = task_sel << 16;
-  KiIdt[sel].b = 0x8500;
+        /* Make sure we have an NPX */
+        if (KeI386NpxPresent)
+         {
+            /* Check if we have Fxsr support */
+            if (KeI386FxsrPresent)
+            {
+                /* Align the floating area to 16-bytes */
+                FloatSaveArea = (FLOATING_SAVE_AREA*)
+                                ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
+
+                /* Get the State */
+                KiFlushNPXState(FloatSaveArea);
+            }
+            else
+            {
+                /* We don't, use the FN area and flush the NPX State */
+                FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
+                KiFlushNPXState(NULL);
+            }
+
+            /* 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
+         {
+            /* FIXME: Handle Emulation */
+            ASSERT(FALSE);
+         }
+    }
+
+    /* Handle debug registers */
+    if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
+        CONTEXT_DEBUG_REGISTERS)
+    {
+        /* Make sure DR7 is valid */
+        if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK)
+        {
+            /* 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
+        {
+            /* Otherwise clear DR registers */
+            Context->Dr0 =
+            Context->Dr1 =
+            Context->Dr3 =
+            Context->Dr6 =
+            Context->Dr7 = 0;
+        }
+    }
+
+    /* Restore IRQL */
+    if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
 }
 
-VOID INIT_FUNCTION
-KeInitExceptions(VOID)
-/*
- * FUNCTION: Initalize CPU exception handling
- */
+BOOLEAN
+FASTCALL
+KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)
 {
-   int i;
-
-   DPRINT("KeInitExceptions()\n");
-
-   /*
-    * Set up the other gates
-    */
-   set_trap_gate(0, (ULONG)KiTrap0, 0);
-   set_trap_gate(1, (ULONG)KiTrap1, 0);
-   set_trap_gate(2, (ULONG)KiTrap2, 0);
-   set_trap_gate(3, (ULONG)KiTrap3, 3);
-   set_trap_gate(4, (ULONG)KiTrap4, 0);
-   set_trap_gate(5, (ULONG)KiTrap5, 0);
-   set_trap_gate(6, (ULONG)KiTrap6, 0);
-   set_trap_gate(7, (ULONG)KiTrap7, 0);
-   set_task_gate(8, TRAP_TSS_SELECTOR);
-   set_trap_gate(9, (ULONG)KiTrap9, 0);
-   set_trap_gate(10, (ULONG)KiTrap10, 0);
-   set_trap_gate(11, (ULONG)KiTrap11, 0);
-   set_trap_gate(12, (ULONG)KiTrap12, 0);
-   set_trap_gate(13, (ULONG)KiTrap13, 0);
-   set_interrupt_gate(14, (ULONG)KiTrap14);
-   set_trap_gate(15, (ULONG)KiTrap15, 0);
-   set_trap_gate(16, (ULONG)KiTrap16, 0);
-   set_trap_gate(17, (ULONG)KiTrap17, 0);
-   set_trap_gate(18, (ULONG)KiTrap18, 0);
-   set_trap_gate(19, (ULONG)KiTrap19, 0);
-
-   for (i = 20; i < 256; i++)
-     {
-        set_trap_gate(i,(int)KiTrapUnknown, 0);
-     }
-
-   set_system_call_gate(0x2d,(int)KiDebugService);
-   set_system_call_gate(0x2e,(int)KiSystemService);
+    ULONG Eip;
+    PKTRAP_FRAME TrapFrame = TrapInformation;
+    VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
+
+    /* Don't do anything if we didn't get a trap frame */
+    if (!TrapInformation) return FALSE;
+
+    /* Check where we came from */
+    switch (TrapFrame->SegCs)
+    {
+        /* Kernel mode */
+        case KGDT_R0_CODE:
+
+            /* Allow S-LIST Routine to fail */
+            Eip = (ULONG)&ExpInterlockedPopEntrySListFault;
+            break;
+
+        /* User code */
+        case KGDT_R3_CODE | RPL_MASK:
+
+            /* 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;
 }
 
-/*
- * @implemented
- */
-NTSTATUS STDCALL
-KeRaiseUserException(IN NTSTATUS ExceptionCode)
+VOID
+NTAPI
+KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
+                    IN PKEXCEPTION_FRAME ExceptionFrame,
+                    IN PKTRAP_FRAME TrapFrame,
+                    IN KPROCESSOR_MODE PreviousMode,
+                    IN BOOLEAN FirstChance)
 {
-   ULONG OldEip;
-   PKTHREAD Thread = KeGetCurrentThread();
-
-    _SEH_TRY {
-        Thread->Teb->ExceptionCode = ExceptionCode;
-    } _SEH_HANDLE {
-        return(ExceptionCode);
-    } _SEH_END;
-
-   OldEip = Thread->TrapFrame->Eip;
-   Thread->TrapFrame->Eip = (ULONG_PTR)LdrpGetSystemDllRaiseExceptionDispatcher();
-   return((NTSTATUS)OldEip);
+    CONTEXT Context;
+    EXCEPTION_RECORD LocalExceptRecord;
+
+    /* Increase number of Exception Dispatches */
+    KeGetCurrentPrcb()->KeExceptionDispatchCount++;
+
+    /* Set the context flags */
+    Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
+
+    /* Check if User Mode or if the debugger is enabled */
+    if ((PreviousMode == UserMode) || (KdDebuggerEnabled))
+    {
+        /* Add the FPU Flag */
+        Context.ContextFlags |= CONTEXT_FLOATING_POINT;
+
+        /* 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)
+    {
+        /* Check if this is a first-chance exception */
+        if (FirstChance == TRUE)
+        {
+            /* Break into the debugger for the first time */
+            if (KiDebugRoutine(TrapFrame,
+                               ExceptionFrame,
+                               ExceptionRecord,
+                               &Context,
+                               PreviousMode,
+                               FALSE))
+            {
+                /* 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 */
+        if (KiDebugRoutine(TrapFrame,
+                           ExceptionFrame,
+                           ExceptionRecord,
+                           &Context,
+                           PreviousMode,
+                           TRUE))
+        {
+            /* Exception was handled */
+            goto Handled;
+        }
+
+        /* Third strike; you're out */
+        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)
+        {
+            /* Make sure a debugger is present, and ignore user-mode if requested */
+            if ((KiDebugRoutine) &&
+                (!(PsGetCurrentProcess()->DebugPort)))
+            {
+                /* Call the debugger */
+                if (KiDebugRoutine(TrapFrame,
+                                   ExceptionFrame,
+                                   ExceptionRecord,
+                                   &Context,
+                                   PreviousMode,
+                                   FALSE))
+                {
+                    /* Exception was handled */
+                    goto Handled;
+                }
+            }
+
+            /* Forward exception to user mode debugger */
+            if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) goto Exit;
+
+            /* Set up the user-stack */
+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;
+
+                /* 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;
+                NewStack = Stack - Size;
+
+                /* Probe stack and copy exception record */
+                ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
+                              Size +  2 * sizeof(ULONG_PTR),
+                              sizeof(ULONG));
+                RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
+
+                /* Now write the two params for the user-mode dispatcher */
+                *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
+                *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
+
+                /* Set new Stack Pointer */
+                KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
+                KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
+
+                /* 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;
+
+                /* Dispatch exception to user-mode */
+                _SEH2_YIELD(return);
+            }
+            _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
+            {
+                /* 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);
+                }
+            }
+            _SEH2_END;
+        }
+
+        /* Try second chance */
+        if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
+        {
+            /* Handled, get out */
+            goto Exit;
+        }
+        else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
+        {
+            /* Handled, get out */
+            goto Exit;
+        }
+
+        /* 3rd strike, kill the process */
+        DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx\n",
+                PsGetCurrentProcess()->ImageFileName,
+                ExceptionRecord->ExceptionCode,
+                ExceptionRecord->ExceptionAddress);
+
+        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,
+                         ExceptionFrame,
+                         TrapFrame,
+                         Context.ContextFlags,
+                         PreviousMode);
+Exit:
+    return;
 }
 
 /*
  * @implemented
  */
 NTSTATUS
-STDCALL
-NtRaiseException (
-    IN PEXCEPTION_RECORD ExceptionRecord,
-    IN PCONTEXT Context,
-    IN BOOLEAN SearchFrames)
+NTAPI
+KeRaiseUserException(IN NTSTATUS ExceptionCode)
 {
-    PKTHREAD Thread = KeGetCurrentThread();
-    PKTRAP_FRAME TrapFrame = Thread->TrapFrame;
-    PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
+    ULONG OldEip;
+    PTEB Teb = KeGetCurrentThread()->Teb;
+    PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
 
-    KeGetCurrentKPCR()->Tib.ExceptionList = TrapFrame->ExceptionList;
+    /* Make sure we can access the TEB */
+    _SEH2_TRY
+    {
+        /* Set the exception code */
+        Teb->ExceptionCode = ExceptionCode;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* Return the exception code */
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
 
-    KiDispatchException(ExceptionRecord,
-                        Context,
-                        TrapFrame,
-                        KeGetPreviousMode(),
-                        SearchFrames);
+    /* Get the old EIP */
+    OldEip = TrapFrame->Eip;
 
-    /* Restore the user context */
-    Thread->TrapFrame = PrevTrapFrame;
-    __asm__("mov %%ebx, %%esp;\n" "jmp _KiServiceExit": : "b" (TrapFrame));
+    /* Change it to the user-mode dispatcher */
+    TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
 
-    /* We never get here */
-    return(STATUS_SUCCESS);
+    /* Return the old EIP */
+    return (NTSTATUS)OldEip;
 }