[NTOS]
[reactos.git] / reactos / ntoskrnl / include / internal / i386 / asmmacro.S
index 312a1f4..d84872a 100644 (file)
@@ -4,50 +4,12 @@
  * FILE:            ntoskrnl/include/i386/asmmacro.S
  * PURPOSE:         Assembly Macros for Spinlocks and common Trap Code
  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  Timo Kreuzer (timo.kreuzer@reactos.org)
  */
  
-/* INCLUDES ******************************************************************/
-
-#include <ndk/asm.h>
-
-// Arguments for TRAP_EPILOG
-#define FromSystemCall              1
-#define DoRestorePreviousMode       1
-#define DoRestoreEverything         1
-#define DoRestoreSegments           1
-#define DoRestoreVolatiles          1
-#define DoPushFakeErrorCode         1
-#define DoFixupV86                  1
-#define DoFixupAbios                1
-#define NotFromSystemCall           0
-#define DoNotRestorePreviousMode    0
-#define DoNotRestoreEverything      0
-#define DoNotRestoreSegments        0
-#define DoNotRestoreVolatiles       0
-#define DoNotPushFakeErrorCode      0
-#define DoNotFixupV86               0
-#define DoNotFixupAbios             0
-
 // Arguments for idt
-#define INT_32_DPL0                 0x8E00
-#define INT_32_DPL3                 0xEE00
-
-//
-// This table contains the prefix flags that are used by V86 emulation
-//
-.equ PREFIX_FLAG_ES,                0x00000100
-.equ PREFIX_FLAG_CS,                0x00000200
-.equ PREFIX_FLAG_SS,                0x00000400
-.equ PREFIX_FLAG_DS,                0x00000800
-.equ PREFIX_FLAG_FS,                0x00001000
-.equ PREFIX_FLAG_GS,                0x00002000
-.equ PREFIX_FLAG_OPER32,            0x00004000
-.equ PREFIX_FLAG_ADDR32,            0x00008000
-.equ PREFIX_FLAG_LOCK,              0x00010000
-.equ PREFIX_FLAG_REPNE,             0x00020000
-.equ PREFIX_FLAG_REP,               0x00040000
-
-.intel_syntax noprefix
+#define INT_32_DPL0                 HEX(08E00)
+#define INT_32_DPL3                 HEX(0EE00)
 
 //
 // These macros are inlined equivalents of KiAcquire/ReleaseSpinlock, that is,
@@ -63,7 +25,7 @@
 //  #IFDEF CONFIG_SMP
 //  .spin
 //      <any necessary steps to be able to jump back safely>
-/       SPIN_ON_LOCK(reg, .BeginYourFunction)
+//       SPIN_ON_LOCK(reg, .BeginYourFunction)
 //  #ENDIF
 //
 #ifdef CONFIG_SMP
 #define RELEASE_SPINLOCK(x) 
 #endif
 
-//
-// @name UNHANDLED_PATH
-//
-// This macro prints out that the current code path is not expected yet
-//
-// @param None
-//
-// @remark None.
-//
-.macro UNHANDLED_PATH Reason
-
-    /* Push reason */
-    push offset 1f
-
-    /* Get EIP */
-    call $+5
-
-    /* Print debug message */
-    push offset _UnhandledMsg
-    call _DbgPrint
-    add esp, 12
-
-    /* Loop indefinitely */
-    jmp $
-
-1:
-    .asciz \Reason
-.endm
-
-//
-// @name UNHANDLED_V86_PATH
-//
-// This macro prints out that the current code path is for unhandled VDM support
-//
-// @param None
-//
-// @remark None.
-//
-.macro UNHANDLED_V86_PATH
-    /* Get EIP */
-    call $+5
-
-    /* Print debug message */
-    push offset _V86UnhandledMsg
-    call _DbgPrint
-    add esp, 8
-
-    /* Loop indefinitely */
-    jmp $
-.endm
-
 //
 // @name IDT
 //
 //
 // @remark None.
 //
-.macro idt Handler, Bits
-    .long \Handler
-    .short \Bits
+MACRO(idt, Handler, Bits)
+    .long VAL(Handler)
+    .short VAL(Bits)
     .short KGDT_R0_CODE
-.endm
+ENDM
 
-//
-// @name GENERATE_IDT_STUB
-//
-// This macro creates an IDT entry for an unexpected interrupt handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_IDT_STUB Number
-idt _KiUnexpectedInterrupt&Number, INT_32_DPL0
-.endm
 
-//
-// @name GENERATE_IDT_STUBS
-//
-// This macro creates unexpected interrupt IDT entries.
-//
-// @param None.
-//
-// @remark None.
-//
-.altmacro
-.macro GENERATE_IDT_STUBS
-.set i, 0
-.rept 208
-    GENERATE_IDT_STUB %i
-    .set i, i + 1
-.endr
-.endm
+KI_PUSH_FAKE_ERROR_CODE = HEX(0001)
+KI_UNUSED               = HEX(0002)
+KI_NONVOLATILES_ONLY    = HEX(0004)
+KI_FAST_SYSTEM_CALL     = HEX(0008)
+KI_SOFTWARE_TRAP        = HEX(0010)
+KI_HARDWARE_INT         = HEX(0020)
+KI_DONT_SAVE_SEGS       = HEX(0100)
 
-//
-// @name GENERATE_INT_HANDLER
-//
-// This macro creates an unexpected interrupt handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_INT_HANDLER Number
-.func KiUnexpectedInterrupt&Number
-_KiUnexpectedInterrupt&Number:
-    push PRIMARY_VECTOR_BASE + Number
-    jmp _KiEndUnexpectedRange@0
-.endfunc
-.endm
+MACRO(KiEnterTrap, Flags)
+    LOCAL kernel_trap
+    LOCAL not_v86_trap
+    LOCAL set_sane_segs
 
-//
-// @name GENERATE_INT_HANDLERS
-//
-// This macro creates the unexpected interrupt handlers.
-//
-// @param None.
-//
-// @remark None.
-//
-.altmacro
-.macro GENERATE_INT_HANDLERS
-.set i, 0
-.rept 208
-    GENERATE_INT_HANDLER %i
-    .set i, i + 1
-.endr
-.endm
+    /* Check what kind of trap frame this trap requires */
+    if (Flags AND KI_FAST_SYSTEM_CALL)
 
-//
-// @name TRAP_HANDLER_PROLOG
-//
-// This macro creates a kernel trap handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro TRAP_HANDLER_PROLOG ErrorCode=1, Software=0
+        /* SYSENTER requires us to build a complete ring transition trap frame */
+        FrameSize = KTRAP_FRAME_V86_ES
 
-    /* What kind of trap is it */
-    .if \Software
-        /* Software traps need a fake interrupt stack */
-        pop eax
-        sub esp, KTRAP_FRAME_ESP
-    .elseif \ErrorCode
-        /* Some traps generate an error code, some don't (thanks, Intel!) */
-        sub esp, KTRAP_FRAME_EIP
-    .else
-        sub esp, KTRAP_FRAME_ERROR_CODE
-    .endif
-
-    /* Make space for trap frame and save registers before we enter C code */
-    mov [esp+KTRAP_FRAME_EAX], eax
-    mov [esp+KTRAP_FRAME_EBX], ebx
-    mov [esp+KTRAP_FRAME_ECX], ecx
-    mov [esp+KTRAP_FRAME_EDX], edx
-    mov [esp+KTRAP_FRAME_ESI], esi
-    mov [esp+KTRAP_FRAME_EDI], edi
-    mov [esp+KTRAP_FRAME_EBP], ebp
-    mov ecx, esp
-.endm
+        /* Fixup fs. cx is free to clobber */
+        mov cx, KGDT_R0_PCR
+        mov fs, cx
 
-//
-// @name GENERATE_TRAP_HANDLER
-//
-// This macro creates a kernel trap handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_TRAP_HANDLER Name, ErrorCode=1, FastV86=0, Software=0
-.globl _&Name
-.func Name
-_&Name:
-    TRAP_HANDLER_PROLOG ErrorCode, Software
-    /*
-     * The GPF and Invalid Opcode handlers are performance critical when talking
-     * about V8086 traps, because they control the main flow of execution during
-     * that mode (GPFs will be issued for any privileged instruction we need to
-     * emulate, and invalid opcode might be generated for BOPs).
-     *
-     * Because of this, we employ a fast entry/exit macro into V8086 mode since
-     * we can make certain assumptions. We detect, and use, such scenarios when
-     * the V8086 flag is enabled in EFLAGS.
-     *
-     * However, because we can land in a GPF handler with an invalid DS/ES, as
-     * some V8086 code could trample this during BIOS calls for example, we must
-     * make sure that we are on a valid DS/ES before dereferencing any pointer.
-     *
-     * We fixup DS/ES either in KiEnterTrap (for normal entry/exit) or, for V86,
-     * in KiEnterV86Trap. Notice the problem: we need to detect which of these
-     * to use early on but we can't touch the EFLAGS in the frame because DS/ES
-     * could be invalid.
-     *
-     * Thankfully SS is always guaranteed valid, so stack dereferences are game!
-     *
-     * We therefore read the EFLAGS here, in assembly, where we can touch ESP as
-     * we please. We save this in EDX, which will be used as the second argument
-     * for the FASTCALL C trap entry.
-     *
-     * When we make the fast V86 check, we use the parameter instead of the trap
-     * frame, leading us to using the correct trap entry function, which fixes
-     * up DS/ES and lets us go on our merry way...
-     */
-    .if \FastV86
-        mov edx, [esp+KTRAP_FRAME_EFLAGS]
-    .endif
-
-    /* Normally we just have one parameter, but fast V86 handlers need two */
-    .if \FastV86
-        jmp @&Name&Handler@8
-    .else
-        jmp @&Name&Handler@4
-    .endif
-.endfunc
-.endm
-
-//
-// @name GENERATE_HAL_INT_HANDLER
-//
-// This macro creates a HAL hardware interrupt handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_HAL_INT_HANDLER Number
-.func HalpHardwareInterrupt&Number
-_HalpHardwareInterrupt&Number:
-    int PRIMARY_VECTOR_BASE + Number
-    ret
-.endfunc
-.endm
-
-//
-// @name GENERATE_HAL_INT_HANDLERS
-//
-// This macro creates the unexpected interrupt handlers.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_HAL_INT_HANDLERS
-.set i, 0
-.rept 16
-    GENERATE_HAL_INT_HANDLER %i
-    .set i, i + 1
-.endr
-.endm
-
-//
-// @name INVALID_V86_OPCODE
-//
-// This macro creates one or more entries for unhandled V86 Opcodes
-// in the V86 Opcode Table.
-//
-// @param count.
-//        Number of entries to generate.
-//
-// @remark None.
-//
-.macro INVALID_V86_OPCODE count
-    .rept \count
-        .byte 0
-    .endr
-.endm
-
-//
-// @name GENERATE_PREFIX_HANDLER
-//
-// This macro creates a prefix opcode handler.
-//
-// @param None.
-//
-// @remark None.
-//
-.macro GENERATE_PREFIX_HANDLER Name
-.func Opcode&Name&PrefixV86
-_Opcode&Name&PrefixV86:
-    or ebx, PREFIX_FLAG_&Name
-    jmp _OpcodeGenericPrefixV86
-.endfunc
-.endm
+        /* Get pointer to the TSS */
+        mov ecx, fs:[KPCR_TSS]
 
-//
-// @name INVALID_V86_OPCODE
-//
-// This macro prints out visible message and hangs the computer.
-//
-// @param None.
-//
-// @remark Temporary debugging use.
-//
-.macro UNHANDLED_V86_OPCODE
-    /* Print debug message, breakpoint and freeze */
-    push ecx
-    push offset V86DebugMsg
-    call _DbgPrint
-    add esp, 8
-    jmp $
-.endm
+        /* Get a stack pointer */
+        mov esp, [ecx + KTSS_ESP0]
 
-//
-// @name TRAP_FIXUPS
-//
-// This macro contains out-of-line code for various Trap Frame Fixups, such as:
-//
-//  - DR Fixup: Loads and restores DR registers.
-//  - V86 Fixup: Loads and restores V86 segments.
-//  - ABIOS Fixup: Loads and restores the ABIOS state and stack.
-//
-// @param None.
-//
-// @remark ebp = PKTRAP_FRAME
-//
-.macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix
-Dr_&Label:
-
-    /* Check if this was V86 mode */
-    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz 2f
-
-    /* Check if it was user mode */
-    test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
-    jz Dr_&EndLabel
-
-2:
-    /* Get DR0, 1, 2 */
-    mov ebx, dr0
-    mov ecx, dr1
-    mov edi, dr2
-
-    /* Save them */
-    mov [ebp+KTRAP_FRAME_DR0], ebx
-    mov [ebp+KTRAP_FRAME_DR1], ecx
-    mov [ebp+KTRAP_FRAME_DR2], edi
-
-    /* Get DR3, 6, 7 */
-    mov ebx, dr3
-    mov ecx, dr6
-    mov edi, dr7
-
-    /* Save them */
-    mov [ebp+KTRAP_FRAME_DR3], ebx
-    mov [ebp+KTRAP_FRAME_DR6], ecx
-    mov [ebp+KTRAP_FRAME_DR7], edi
-
-    /* Clear DR7 */
-    xor ebx, ebx
-    mov dr7, ebx
-
-    /* Get the PRCB */
-    mov edi, fs:[KPCR_PRCB]
-
-    /* Get DR0, 1 */
-    mov ebx, [edi+KPRCB_DR0]
-    mov ecx, [edi+KPRCB_DR1]
-
-    /* Set them */
-    mov dr0, ebx
-    mov dr1, ecx
-
-    /* Get DR2, 3 */
-    mov ebx, [edi+KPRCB_DR2]
-    mov ecx, [edi+KPRCB_DR3]
-
-    /* Set them */
-    mov dr2, ebx
-    mov dr3, ecx
-
-    /* Get DR6, 7 */
-    mov ebx, [edi+KPRCB_DR6]
-    mov ecx, [edi+KPRCB_DR7]
-
-    /* Set them */
-    mov dr6, ebx
-    mov dr7, ecx
-    jmp Dr_&EndLabel
-
-.if \AbiosFix
-Abios_&Label:
-    UNHANDLED_PATH
-.endif
-
-.if \V86Fix
-V86_&Label:
-
-    /* Get V86 segment registers */
-    mov eax, [ebp+KTRAP_FRAME_V86_FS]
-    mov ebx, [ebp+KTRAP_FRAME_V86_GS]
-    mov ecx, [ebp+KTRAP_FRAME_V86_ES]
-    mov edx, [ebp+KTRAP_FRAME_V86_DS]
-
-    /* Restore them into Protected Mode trap frame */
-    mov [ebp+KTRAP_FRAME_FS], ax
-    mov [ebp+KTRAP_FRAME_GS], bx
-    mov [ebp+KTRAP_FRAME_ES], cx
-    mov [ebp+KTRAP_FRAME_DS], dx
-
-    /* Go back to mainline code */
-    jmp V86_&EndLabel
-.endif
-.endm
+    elseif (Flags AND KI_SOFTWARE_TRAP)
 
-//
-// @name SET_TF_DEBUG_HEADER
-//
-// This macro sets up the debug header in the trap frame.
-//
-// @param None.
-//
-// @remark ebp = PKTRAP_FRAME.
-//         edi/ebx = Have been saved and can be used.
-//
-.macro SET_TF_DEBUG_HEADER
-    /* Get the Debug Trap Frame EBP/EIP */
-    mov ebx, [ebp+KTRAP_FRAME_EBP]
-    mov edi, [ebp+KTRAP_FRAME_EIP]
-
-    /* Write the debug data */
-    mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
-    mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
-    mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
-    mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
-.endm
-
-//
-// @name CHECK_FOR_APC_DELIVER
-// 
-// This macro checks if the trapframe indicates a return to user-mode,
-// and, if so, checks if user-mode APCs should be delivered.
-//
-// @param PreserveEax
-//        Determines if EAX should be preserved. Implies that the segment
-//        registers will also be saved.
-//
-// @remark ebp = PKTRAP_FRAME.
-//         ebx = Saved and will be used.
-//
-.macro CHECK_FOR_APC_DELIVER PreserveEax
-    /* Check for V86 mode */
-    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz 1f
-
-    /* Deliver APCs only if we were called from user mode */
-    test byte ptr [ebp+KTRAP_FRAME_CS], 1
-    je 2f
-
-    /* Get the current thread */
-1:
-    mov ebx, PCR[KPCR_CURRENT_THREAD]
-
-    /* Make it non-alerted */
-    mov byte ptr [ebx+KTHREAD_ALERTED], 0
-
-    /* And only if any are actually pending */
-    cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
-    je 2f
-
-    /* Save pointer to Trap Frame */
-    mov ebx, ebp
-
-.if \PreserveEax
-    /* Save some stuff that raising IRQL will kill */
-    mov [ebx+KTRAP_FRAME_EAX], eax
-    mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK
-    mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
-    mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
-    mov dword ptr [ebx+KTRAP_FRAME_GS], 0
-.endif
-
-    /* Raise IRQL to APC_LEVEL */
-    mov ecx, 1
-    call @KfRaiseIrql@4
-
-    /* Save old IRQL */
-    push eax
-
-    /* Deliver APCs */
-    sti
-    push ebx
-    push 0
-    push UserMode
-    call _KiDeliverApc@12
-
-    /* Return to old IRQL */
-    pop ecx
-    call @KfLowerIrql@4
-
-    /* Restore EAX (only in volatile case) */
-.if \PreserveEax
-    mov eax, [ebx+KTRAP_FRAME_EAX]
-.endif
-    cli
-    jmp 1b
-2:
-.endm
+        /* Software traps need a complete non-ring transition trap frame */
+        FrameSize = KTRAP_FRAME_ESP
 
-//
-// @name TRAP_PROLOG
-// 
-// This macro creates a standard trap entry prologue.
-// It should be used for entry into any kernel trap (KiTrapXx), but not for
-// system calls, which require special handling.
-//
-// @param Label
-//        Identifying name of the caller function; will be used to append
-//        to the name V86 and DR helper functions, which must already exist.
-//
-// @remark Use as follows:
-//          _KiTrap00:
-//              /* Push fake error code */
-//              push 0
-//
-//              /* Enter common prologue */
-//              TRAP_PROLOG(0)
-//
-//              /* Handle trap */
-//              <Your Trap Code Here>
-//
-.macro TRAP_PROLOG Label EndLabel
-    /* Just to be safe, clear out the HIWORD, since it's reserved */
-    mov word ptr [esp+2], 0
-
-    /* Save the non-volatiles */
-    push ebp
-    push ebx
-    push esi
-    push edi
-
-    /* Save FS and set it to PCR */
-    push fs
-    mov ebx, KGDT_R0_PCR
-    .byte 0x66
-    mov fs, bx
-
-    /* Save exception list and bogus previous mode */
-    push fs:[KPCR_EXCEPTION_LIST]
-    push -1
-
-    /* Save volatiles and segment registers */
-    push eax
-    push ecx
-    push edx
-    push ds
-    push es
-    push gs
-
-    /* Set the R3 data segment */
-    mov ax, KGDT_R3_DATA + RPL_MASK
-
-    /* Skip debug registers and debug stuff */
-    sub esp, 0x30
-
-    /* Load the segment registers */
-    .byte 0x66
-    mov ds, ax
-    .byte 0x66
-    mov es, ax
-
-    /* Check if this interrupt happened in 16-bit mode */
-    cmp esp, 0x10000
-    jb _Ki16BitStackException
-
-    /* Set up frame */
-    mov ebp, esp
-
-    /* Check if this was from V86 Mode */
-    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz V86_&Label
-
-V86_&EndLabel:
-    /* Get current thread */
-    mov ecx, fs:[KPCR_CURRENT_THREAD]
-    cld
-
-    /* Flush DR7 */
-    and dword ptr [ebp+KTRAP_FRAME_DR7], 0
-
-    /* Check if the thread was being debugged */
-    test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
-    jnz Dr_&Label
-
-    /* Set the Trap Frame Debug Header */
-Dr_&EndLabel:
-    SET_TF_DEBUG_HEADER
-.endm
-
-//
-// @name INT_PROLOG
-// 
-// This macro creates a standard interrupt entry prologue.
-// It should be used for entry into any interrupt, including software.
-//
-// @param Label
-//        Identifying name of the caller function; will be used to append
-//        to the name V86, ABIOS and DR helper functions, which must exist.
-//
-// @remark For software interrupts, make sure that a fake INT stack is created.
-//
-.macro INT_PROLOG Label EndLabel FakeErrorCode
-
-.if \FakeErrorCode
-    /* Save fake error code */
-    push esp
-.endif
-
-    /* Save the non-volatiles */
-    push ebp
-    push ebx
-    push esi
-    push edi
-
-    /* Skip debug registers and other stuff */
-    sub esp, 0x54
-
-    /* Set up frame */
-    mov ebp, esp
+        /* Software traps need to get their EIP from the caller's frame */
+        pop eax
 
-    /* Save volatiles */ 
-    mov [esp+KTRAP_FRAME_EAX], eax
-    mov [esp+KTRAP_FRAME_ECX], ecx
-    mov [esp+KTRAP_FRAME_EDX], edx
-    mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
-
-    /* Check if this was from V86 Mode */
-    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz V86_&Label
-
-    /* Check if this was kernel mode */
-V86_&EndLabel:
-    cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE
-    jz 1f
-
-    /* Set segments */
-    mov word ptr [esp+KTRAP_FRAME_FS], fs
-    mov word ptr [esp+KTRAP_FRAME_DS], ds
-    mov word ptr [esp+KTRAP_FRAME_ES], es
-    mov [esp+KTRAP_FRAME_GS], gs
-
-    /* Load the segment registers (use OVERRIDE (0x66)) */
-    mov ebx, KGDT_R0_PCR
-    mov eax, KGDT_R3_DATA | RPL_MASK
-    .byte 0x66
-    mov fs, bx
-    .byte 0x66
+    elseif (Flags AND KI_PUSH_FAKE_ERROR_CODE)
+
+        /* If the trap doesn't have an error code, we'll make space for it */
+        FrameSize = KTRAP_FRAME_EIP
+
+    else
+
+        /* The trap already has an error code, so just make space for the rest */
+        FrameSize = KTRAP_FRAME_ERROR_CODE
+
+    endif
+
+    /* Make space for this frame */
+    sub esp, FrameSize
+
+    /* Save nonvolatile registers */
+    mov [esp + KTRAP_FRAME_EBP], ebp
+    mov [esp + KTRAP_FRAME_EBX], ebx
+    mov [esp + KTRAP_FRAME_ESI], esi
+    mov [esp + KTRAP_FRAME_EDI], edi
+
+    /* Save eax for system calls, for use by the C handler */
+    mov [esp + KTRAP_FRAME_EAX], eax
+
+    /* Does the caller want nonvolatiles only? */
+    if (NOT (Flags AND KI_NONVOLATILES_ONLY))
+        /* Otherwise, save the volatiles as well */
+        mov [esp + KTRAP_FRAME_ECX], ecx
+        mov [esp + KTRAP_FRAME_EDX], edx
+    endif
+
+    /* Save segment registers? */
+    if (Flags AND KI_DONT_SAVE_SEGS)
+
+        /* Initialize TrapFrame segment registers with sane values */
+        mov eax, 0x23
+        mov ecx, fs
+        mov [esp - FrameSize + KTRAP_FRAME_DS], eax
+        mov [esp - FrameSize + KTRAP_FRAME_ES], eax
+        mov [esp - FrameSize + KTRAP_FRAME_FS], ecx
+        mov dword ptr [esp - FrameSize + KTRAP_FRAME_GS], 0
+
+    else
+
+        /* Check for V86 mode */
+        test byte ptr [esp + KTRAP_FRAME_EFLAGS + 2], (EFLAGS_V86_MASK / HEX(10000))
+        jz not_v86_trap
+
+            /* Restore V8086 segments into Protected Mode segments */
+            mov eax, [esp + KTRAP_FRAME_V86_DS]
+            mov ecx, [esp + KTRAP_FRAME_V86_ES]
+            mov [esp + KTRAP_FRAME_DS], eax
+            mov [esp + KTRAP_FRAME_ES], ecx
+            mov eax, [esp + KTRAP_FRAME_V86_FS]
+            mov ecx, [esp + KTRAP_FRAME_V86_GS]
+            mov [esp + KTRAP_FRAME_FS], eax
+            mov [esp + KTRAP_FRAME_GS], ecx
+            jmp set_sane_segs
+
+        not_v86_trap:
+
+            /* Save segment selectors */
+            mov eax, ds
+            mov ecx, es
+            mov [esp + KTRAP_FRAME_DS], eax
+            mov [esp + KTRAP_FRAME_ES], ecx
+            mov eax, fs
+            mov ecx, gs
+            mov [esp + KTRAP_FRAME_FS], eax
+            mov [esp + KTRAP_FRAME_GS], ecx
+
+    endif
+
+set_sane_segs:
+    /* Load correct data segments */
+    mov ax, KGDT_R3_DATA OR RPL_MASK
     mov ds, ax
-    .byte 0x66
     mov es, ax
 
-1: 
-    /* Get the previous exception list */
-    mov ebx, fs:[KPCR_EXCEPTION_LIST]
-
-    /* Set the exception handler chain terminator */
-    mov dword ptr fs:[KPCR_EXCEPTION_LIST], -1
-
-    /* Save the previous exception list */
-    mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx
-
-.ifeq \FakeErrorCode
-    /* Setup the 16-bit stack */
-    lea eax, [esp+KTRAP_FRAME_ERROR_CODE]
-    lea ecx, [esp+KTRAP_FRAME_EIP]
-    mov ebx, ss:[eax]
-    mov ss:[eax], ecx
-.endif
-
-    /* Check if this is the ABIOS stack */
-    /* cmp esp, 0x10000*/
-    /* jb Abios_Label*/
-
-    /* Delete error code */
-    and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0
+    /* Fast system calls have fs already fixed */
+    if (NOT (Flags AND KI_FAST_SYSTEM_CALL))
+        /* Otherwise fix fs now */
+        mov ax, KGDT_R0_PCR
+        mov fs, ax
+    endif
 
-    /* Get the current thread and clear direction flag */
-    mov ecx, PCR[KPCR_CURRENT_THREAD]
-    cld
-
-    /* Flush DR7 */
-    and dword ptr [ebp+KTRAP_FRAME_DR7], 0
-
-    /* Check if the thread was being debugged */
-    test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
-
-.ifeq \FakeErrorCode
-    /* Push parameter */
-    push ebx
-.endif
-
-    /* Save DR registers if needed */
-    jnz Dr_&Label
-
-    /* Set the trap frame debug header */
-Dr_&EndLabel:
-    SET_TF_DEBUG_HEADER
-.endm
-
-//
-// @name SYSCALL_PROLOG
-// 
-// This macro creates a system call entry prologue.
-// It should be used for entry into any fast-system call (KiGetTickCount,
-// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
-// (KiSystemService)
-//
-// @param Label
-//        Unique label identifying the name of the caller function; will be
-//        used to append to the name of the DR helper function, which must
-//        already exist.
-//
-// @remark None.
-//
-.macro SYSCALL_PROLOG Label EndLabel
-    /* Create a trap frame */
-    push 0
-    push ebp
-    push ebx
-    push esi
-    push edi
-    push fs
-
-    /* Load PCR Selector into fs */
-    mov ebx, KGDT_R0_PCR
-    .byte 0x66
-    mov fs, bx
-
-    /* Get a pointer to the current thread */
-    mov esi, PCR[KPCR_CURRENT_THREAD]
-
-    /* Save the previous exception list */
-    push PCR[KPCR_EXCEPTION_LIST]
-
-    /* Set the exception handler chain terminator */
-    mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
-
-    /* Save the old previous mode */
-    push [esi+KTHREAD_PREVIOUS_MODE]
-
-    /* Skip the other registers */
-    sub esp, 0x48
-
-    /* Set the new previous mode based on the saved CS selector */
-    mov ebx, [esp+0x6C]
-    and ebx, 1
-    mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl
-
-    /* Go on the Kernel stack frame */
+#if DBG
+    /* Keep the frame chain intact */
+    mov eax, [esp + KTRAP_FRAME_EIP]
+    mov [esp + KTRAP_FRAME_DEBUGEIP], eax
+    mov [esp + KTRAP_FRAME_DEBUGEBP], ebp
     mov ebp, esp
+#endif
 
-    /* Save the old trap frame pointer where EDX would be saved */
-    mov ebx, [esi+KTHREAD_TRAP_FRAME]
-    mov [ebp+KTRAP_FRAME_EDX], ebx
-
-    /* Flush DR7 */
-    and dword ptr [ebp+KTRAP_FRAME_DR7], 0
-
-    /* Check if the thread was being debugged */
-    test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
+    /* Set parameter 1 (ECX) to point to the frame */
+    mov ecx, esp
 
-    /* Set the thread's trap frame and clear direction flag */
-    mov [esi+KTHREAD_TRAP_FRAME], ebp
+    /* Clear direction flag */
     cld
 
-    /* Save DR registers if needed */
-    jnz Dr_&Label
-
-    /* Set the trap frame debug header */
-Dr_&EndLabel:
-    SET_TF_DEBUG_HEADER
-
-    /* Enable interrupts */
-    sti
-.endm
-
-//
-// @name FASTCALL_PROLOG
-// 
-// TODO
-//
-// @param Label
-//        Unique label identifying the name of the caller function; will be
-//        used to append to the name of the DR helper function, which must
-//        already exist.
-//
-// @remark None.
-//
-.macro FASTCALL_PROLOG Label EndLabel
-
-    /* Set user selector */
-    mov ecx, KGDT_R3_DATA | RPL_MASK
-
-    /* Set FS to PCR */
-    push KGDT_R0_PCR
-    pop fs
-
-    /* Set DS/ES to User Selector */
-    mov ds, cx
-    mov es, cx
-
-    /* Set the current stack to Kernel Stack */
-    mov ecx, PCR[KPCR_TSS]
-    mov esp, [ecx+KTSS_ESP0]
+ENDM
 
-    /* Set up a fake INT Stack. */
-    push KGDT_R3_DATA + RPL_MASK
-    push edx                            /* Ring 3 SS:ESP */
-    pushf                               /* Ring 3 EFLAGS */
-    push 2                              /* Ring 0 EFLAGS */
-    add edx, 8                          /* Skip user parameter list */
-    popf                                /* Set our EFLAGS */
-    or dword ptr [esp], EFLAGS_INTERRUPT_MASK   /* Re-enable IRQs in EFLAGS, to fake INT */
-    push KGDT_R3_CODE + RPL_MASK
-    push dword ptr ds:KUSER_SHARED_SYSCALL_RET
-
-    /* Setup the Trap Frame stack */
-    push 0
-    push ebp
-    push ebx
-    push esi
-    push edi
-    push KGDT_R3_TEB + RPL_MASK
-
-    /* Save pointer to our PCR */
-    mov ebx, PCR[KPCR_SELF]
-
-    /* Get a pointer to the current thread */
-    mov esi, [ebx+KPCR_CURRENT_THREAD]
-
-    /* Set the exception handler chain terminator */
-    push [ebx+KPCR_EXCEPTION_LIST]
-    mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
-
-    /* Use the thread's stack */
-    mov ebp, [esi+KTHREAD_INITIAL_STACK]
+MACRO(KiCallHandler, Handler)
+#if DBG
+    /* Use a call to get the return address for back traces */
+    call Handler
+#else
+    /* Use the faster jmp */
+    jmp Handler
+#endif
+    nop
+ENDM
 
-    /* Push previous mode */
-    push UserMode
+MACRO(TRAP_ENTRY, Trap, Flags)
+EXTERN @&Trap&Handler@4 :PROC
+    PUBLIC _&Trap
+    _&Trap:
+    KiEnterTrap Flags
+    KiCallHandler @&Trap&Handler@4
+ENDM
 
-    /* Skip the other registers */
-    sub esp, 0x48
+#define KI_RESTORE_EAX        HEX(001)
+#define KI_RESTORE_ECX_EDX    HEX(002)
+#define KI_RESTORE_FS         HEX(004)
+#define KI_RESTORE_SEGMENTS   HEX(008)
+#define KI_RESTORE_EFLAGS     HEX(010)
+#define KI_EXIT_SYSCALL       HEX(020)
+#define KI_EXIT_JMP           HEX(040)
+#define KI_EXIT_RET           HEX(080)
+#define KI_EXIT_IRET          HEX(100)
+#define KI_EDITED_FRAME       HEX(200)
+#define KI_RESTORE_VOLATILES  (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX)
 
-    /* Make space for us on the stack */
-    sub ebp, 0x29C
+MACRO(KiTrapExitStub, Name, Flags)
 
-    /* Write the previous mode */
-    mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
+PUBLIC @&Name&@4
+@&Name&@4:
 
-    /* Sanity check */
-    cmp ebp, esp
-    jnz BadStack
+    if (Flags AND KI_RESTORE_EFLAGS)
 
-    /* Flush DR7 */
-    and dword ptr [ebp+KTRAP_FRAME_DR7], 0
+        /* We will pop EFlags off the stack */
+        OffsetEsp = KTRAP_FRAME_EFLAGS
 
-    /* Check if the thread was being debugged */
-    test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
+    elseif (Flags AND KI_EXIT_IRET)
 
-    /* Set the thread's trap frame */
-    mov [esi+KTHREAD_TRAP_FRAME], ebp
+        /* This is the IRET frame */
+        OffsetEsp = KTRAP_FRAME_EIP
 
-    /* Save DR registers if needed */
-    jnz Dr_&Label
+    else
 
-    /* Set the trap frame debug header */
-Dr_&EndLabel:
-    SET_TF_DEBUG_HEADER
+        OffsetEsp = 0
 
-    /* Enable interrupts */
-    sti
-.endm
+    endif
 
-//
-// @name V86_TRAP_PROLOG
-// 
-// This macro creates a V86 Trap entry prologue.
-// It should be used for entry into any fast-system call (KiGetTickCount,
-// KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
-// (KiSystemService)
-//
-// @param Label
-//        Unique label identifying the name of the caller function; will be
-//        used to append to the name of the DR helper function, which must
-//        already exist.
-//
-// @remark None.
-//
-.macro V86_TRAP_PROLOG Label EndLabel
+    if (Flags AND KI_EDITED_FRAME)
 
-    /* Skip everything to the error code */
-    sub esp, KTRAP_FRAME_ERROR_CODE
+        /* Load the requested ESP */
+        mov esp, [ecx + KTRAP_FRAME_TEMPESP]
 
-    /* Clear the error code */
-    mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
+        /* Put return address on the new stack */
+        push [ecx + KTRAP_FRAME_EIP]
 
-    /* Save the registers we'll trample */
-    mov [esp+KTRAP_FRAME_EBX], ebx
-    mov [esp+KTRAP_FRAME_EAX], eax
-    mov [esp+KTRAP_FRAME_EBP], ebp
-    mov [esp+KTRAP_FRAME_ESI], esi
-    mov [esp+KTRAP_FRAME_EDI], edi
+        /* Put EFLAGS on the new stack */
+        push [ecx + KTRAP_FRAME_EFLAGS]
 
-    /* Save PCR and Ring 3 segments */
-    mov ebx, KGDT_R0_PCR
-    mov eax, KGDT_R3_DATA + RPL_MASK
+    else
 
-    /* Save ECX and EDX too */
-    mov [esp+KTRAP_FRAME_ECX], ecx
-    mov [esp+KTRAP_FRAME_EDX], edx
+        /* Point esp to an appropriate member of the frame */
+        lea esp, [ecx + OffsetEsp]
 
-    /* Set debugging markers */
-    mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
-    mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
+    endif
 
-    /* Now set segments (use OVERRIDE, 0x66) */
-    .byte 0x66
-    mov fs, bx
-    .byte 0x66
-    mov ds, ax
-    .byte 0x66
-    mov es, ax
+    /* Restore non volatiles */
+    mov ebx, [ecx + KTRAP_FRAME_EBX]
+    mov esi, [ecx + KTRAP_FRAME_ESI]
+    mov edi, [ecx + KTRAP_FRAME_EDI]
+    mov ebp, [ecx + KTRAP_FRAME_EBP]
 
-    /* Set the trap frame in the stack and clear the direction flag */
-    mov ebp, esp
-    cld
+    if (Flags AND KI_RESTORE_EAX)
 
-    /* Save the exception list */
-    mov eax, fs:[KPCR_EXCEPTION_LIST]
-    mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
+        /* Restore eax */
+        mov eax, [ecx + KTRAP_FRAME_EAX]
 
-    /* Check if we need debugging */
-    mov eax, dr7
-    test eax, ~DR7_RESERVED_MASK
-    mov [esp+KTRAP_FRAME_DR7], eax
-    jnz Dr_&Label
+    endif
 
-Dr_&EndLabel:
-.endm
+    if (Flags AND KI_RESTORE_ECX_EDX)
 
-//
-// @name V86_TRAP_EPILOG
-// 
-// This macro creates an epilogue for leaving V86 traps
-//
-// @param None.
-//
-// @remark None.
-//
-.macro V86_TRAP_EPILOG
-
-    /* Get the current thread and make it unalerted */
-ExitBegin:
-    mov ebx, PCR[KPCR_CURRENT_THREAD]
-    mov byte ptr [ebx+KTHREAD_ALERTED], 0
-
-    /* Check if it has User-mode APCs pending */
-    cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
-    jne PendingUserApc
-
-    /* It doesn't, pop the frame */
-    add esp, KTRAP_FRAME_EDX
-    pop edx
-    pop ecx
-    pop eax
-
-    /* Check if DR registers should be restored */
-    test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
-    jnz V86DebugRestore
-
-    /* Finish popping the rest of the frame, and return to P-mode */
-V86DebugContinue:
-    add esp, 12
-    pop edi
-    pop esi
-    pop ebx
-    pop ebp
-    add esp, 4
-    iretd
-
-V86DebugRestore:
-
-    /* Get DR0, 1 */
-    xor ebx, ebx
-    mov esi, [ebp+KTRAP_FRAME_DR0]
-    mov edi, [ebp+KTRAP_FRAME_DR1]
-
-    /* Clear DR 7 */
-    mov dr7, ebx
-
-    /* Get DR2 and load DR0-2 */
-    mov ebx, [ebp+KTRAP_FRAME_DR2]
-    mov dr0, esi
-    mov dr1, edi
-    mov dr2, ebx
-
-    /* Get DR3-7 */
-    mov esi, [ebp+KTRAP_FRAME_DR0]
-    mov edi, [ebp+KTRAP_FRAME_DR1]
-    mov ebx, [ebp+KTRAP_FRAME_DR7]
-
-    /* Load them */
-    mov dr3, esi
-    mov dr6, edi
-    mov dr7, ebx
-    jmp V86DebugContinue
-
-PendingUserApc:
-
-    /* Raise to APC level */
-    mov ecx, APC_LEVEL
-    call @KfRaiseIrql@4
-
-    /* Save KIRQL and deliver APCs */
-    push eax
-    sti
-    push ebp
-    push 0
-    push UserMode
-    call _KiDeliverApc@12
-
-    /* Restore IRQL */
-    pop ecx
-    call @KfLowerIrql@4
-    cli
-
-    /* Check if we're not in V86 anymore */
-    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz ExitBegin
-.endm
+        /* Restore volatiles */
+        mov edx, [ecx + KTRAP_FRAME_EDX]
+        mov ecx, [ecx + KTRAP_FRAME_ECX]
 
-//
-// @name TRAP_EPILOG
-// 
-// This macro creates an epilogue for leaving any system trap.
-// It is used for exiting system calls, exceptions, interrupts and generic
-// traps.
-//
-// @param SystemCall
-//        Specifies whether this trap will exit a system call. If so, special
-//        code will be assembled to potentially use SYSEXIT instead of IRETD.
-//
-// @param RestorePreviousMode
-//        Specifies if the previous mode should be restored.
-//
-// @param RestoreSegments
-//        Specifies if the segment registers should be restored.
-//
-// @param RestoreVolatiles
-//        Specifies if the volatile registers should be restored.
-//
-// @param RestoreAllRegs
-//        Specifies if volatiles and segments should both be restored.
-//
-// @remark
-//
-.macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs
-#if DBG
-    /* Assert the flags */
-    pushfd
-    pop edx
-    test edx, EFLAGS_INTERRUPT_MASK
-    jnz 6f
+    elseif (Flags AND KI_EXIT_JMP)
 
-    /* Assert the stack */
-    cmp esp, ebp
-    jnz 6f
+        /* Load return address into edx */
+        mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
 
-    /* Assert the trap frame */
-#endif
-5:
-#if DBG
-    sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
-    jnz 0f
+    elseif (Flags AND KI_EXIT_SYSCALL)
 
-    /* Assert FS */
-    mov bx, fs
-    cmp bx, KGDT_R0_PCR
-    jnz 1f
+        /* Set sysexit parameters */
+        mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
+        mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP]
 
-    /* Assert exception list */
-    cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0
-    jnz 2f
+        /* Keep interrupts disabled until the sti / sysexit */
+        and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], NOT (EFLAGS_INTERRUPT_MASK / HEX(100))
 
-1:
-    push -1
-    call _KeBugCheck@4
-#endif
+    endif
 
-2:
-    /* Get exception list */
-    mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
+    if (Flags AND KI_RESTORE_SEGMENTS)
 
-#if DBG
-    /* Assert the saved exception list */
-    or edx, edx
-    jnz 1f
-    UNHANDLED_PATH
-1:
-#endif
+        /* Restore segments for user mode */
+        mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS]
+        mov es, [esp - OffsetEsp + KTRAP_FRAME_ES]
+        mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS]
 
-    /* Restore it */
-    mov PCR[KPCR_EXCEPTION_LIST], edx
+    endif
 
-.if \RestorePreviousMode
-    /* Get previous mode */
-    mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
+    if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS))
 
-#if DBG
-    /* Assert the saved previous mode */
-    cmp ecx, -1
-    jnz 1f
-    UNHANDLED_PATH
-1:
-#endif
+        /* Restore user mode FS */
+        mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS]
 
-    /* Restore the previous mode */
-    mov esi, PCR[KPCR_CURRENT_THREAD]
-    mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
-.else
+    endif
 
-#if DBG
-    /* Assert the saved previous mode */
-    mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
-    cmp ecx, -1
-    jz 1f
-    UNHANDLED_PATH
-1:
-#endif
-.endif
-
-    /* Check for debug registers */
-    test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
-    jnz 2f
-
-    /* Check for V86 */
-4:
-    test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz V86_Exit
-
-    /* Check if the frame was edited */
-    test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
-    jz 7f
-
-.if \RestoreAllRegs
-    /* Check the old mode */
-    cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
-    bt word ptr [esp+KTRAP_FRAME_CS], 0
-    cmc
-    ja 8f
-.endif
-
-.if \RestoreVolatiles
-    /* Restore volatiles */
-    mov edx, [esp+KTRAP_FRAME_EDX]
-    mov ecx, [esp+KTRAP_FRAME_ECX]
-    mov eax, [esp+KTRAP_FRAME_EAX]
-.endif
-
-    /* Check if we were called from kernel mode */
-    cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
-    jz 9f
-
-.if \RestoreSegments
-    /* Restore segment registers */
-    lea esp, [ebp+KTRAP_FRAME_GS]
-    pop gs
-    pop es
-    pop ds
-.endif
-
-    /* Restore FS */
-3:
-    lea esp, [ebp+KTRAP_FRAME_FS]
-    pop fs
-
-9:
-    /* Skip debug information and unsaved registers */
-    lea esp, [ebp+KTRAP_FRAME_EDI]
-    pop edi
-    pop esi
-    pop ebx
-    pop ebp
-
-    /* Check for ABIOS */
-    cmp word ptr [esp+8], 0x80
-    ja AbiosExit
-
-    /* Pop error code */
-    add esp, 4
-
-.if \SystemCall
-    /* Check if previous CS is from user-mode */
-    test dword ptr [esp+4], 1
-
-    /* It is, so use Fast Exit */
-    jnz FastExit
-
-    /* Jump back to stub */
-    pop edx
-    pop ecx
-    popf
-    jmp edx
-
-.ret:
-.endif
-    iret
-
-.if \SystemCall
-FastExit:
-    /* Is SYSEXIT Supported/Wanted? */
-    cmp dword ptr ss:[_KiFastSystemCallDisable], 0
-    jnz .ret
-    test dword ptr [esp+8], EFLAGS_TF
-    jnz .ret
-
-    /* Restore FS to TIB */
-    mov ecx, KGDT_R3_TEB + RPL_MASK
-    mov fs, ecx
-
-    /* We will be cleaning up the stack ourselves */
-    pop edx                                 /* New Ring 3 EIP */
-    add esp, 4                              /* Skip Ring 3 DS */
-    and dword ptr [esp], 0xfffffdff         /* Remove EFLAGS_INTERRUPT_MASK from EFLAGS */
-    popf                                    /* Restore old EFLAGS */
-    pop ecx                                 /* Old Ring 3 SS:ESP */
-
-    /*
-     * At this point:
-     *     ECX points to the old User Stack.
-     *     EDX points to the instruction to execute in usermode after the sysenter
-     */
-    sti
-    sysexit
-.endif
-
-.if \RestoreAllRegs
-8:
-    /* Restore EAX */
-    mov eax, [esp+KTRAP_FRAME_EAX]
-
-    /* Skip registers */
-    add esp, 0x30
-
-    /* Restore segments and volatiles */
-    pop gs
-    pop es
-    pop ds
-    pop edx
-    pop ecx
-
-    /* Jump back to mainline code */
-    jmp 3b
-.endif
+    if (Flags AND KI_RESTORE_EFLAGS)
 
-#if DBG
-0:
-    /* Fix up the mask */
-    add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
+        /* Restore EFLAGS */
+        popf
 
-6:
-    UNHANDLED_PATH
-    jmp 5b
-#endif
+    endif
 
-2:
-    /* Check if this was V86 mode */
-    test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz 1f
-
-    /* Check if it was user mode */
-    test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK
-    jz 4b
-
-1:
-    /* Clear DR7 */
-    xor ebx, ebx
-    mov dr7, ebx
-
-    /* Get DR0, 1, 2 */
-    mov esi, [ebp+KTRAP_FRAME_DR0]
-    mov edi, [ebp+KTRAP_FRAME_DR1]
-    mov ebx, [ebp+KTRAP_FRAME_DR2]
-
-    /* Set them */
-    mov dr0, esi
-    mov dr1, edi
-    mov dr2, ebx
-
-    /* Get DR3, 6, 7 */
-    mov esi, [ebp+KTRAP_FRAME_DR3]
-    mov edi, [ebp+KTRAP_FRAME_DR6]
-    mov ebx, [ebp+KTRAP_FRAME_DR7]
-
-    /* Set them */
-    mov dr3, esi
-    mov dr6, edi
-    mov dr7, ebx
-    jmp 4b
-
-7:
-    /* Restore real CS value */
-    mov ebx, [esp+KTRAP_FRAME_TEMPCS]
-    mov [esp+KTRAP_FRAME_CS], ebx
-
-    /*
-     * If ESP was modified, then a special interrupt exit stack
-     * must be created to "update" ESP's value in a legal manner
-     */
-    mov ebx, [esp+KTRAP_FRAME_TEMPESP]
-    sub ebx, 0xC
-    mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
-
-    /* Copy Interrupt Stack */
-    mov esi, [esp+KTRAP_FRAME_EFLAGS]
-    mov [ebx+8], esi
-    mov esi, [esp+KTRAP_FRAME_CS]
-    mov [ebx+4], esi
-    mov esi, [esp+KTRAP_FRAME_EIP]
-    mov [ebx], esi
-
-.if \RestoreVolatiles
-    /* Restore volatiles */
-    mov eax, [esp+KTRAP_FRAME_EAX]
-    mov edx, [esp+KTRAP_FRAME_EDX]
-    mov ecx, [esp+KTRAP_FRAME_ECX]
-.endif
-
-    /* Return */
-    add esp, KTRAP_FRAME_EDI
-    pop edi
-    pop esi
-    pop ebx
-    pop ebp
-    mov esp, [esp]
-    iret
-.endm
+    if (Flags AND KI_EXIT_SYSCALL)
 
-//
-// @name INT_EPILOG
-// 
-// This macro creates an epilogue for leaving any system trap.
-// It is used for exiting system calls, exceptions, interrupts and generic
-// traps.
-//
-// @param Spurious - TRUE if the interrupt was unexpected and spurious.
-//
-// @remark None.
-//
-.macro INT_EPILOG Spurious
+        /* Enable interrupts and return to user mode.
+           Both must follow directly after another to be "atomic". */
+        sti
+        sysexit
 
-.if \Spurious
-    /* Just exit the trap */
-    jmp _Kei386EoiHelper@0
-.else
-    /* Disable interrupts */
-    cli
+    elseif (Flags AND KI_EXIT_IRET)
 
-    /* End the interrupt and do EOI */
-    call _HalEndSystemInterrupt@8
-    jmp _Kei386EoiHelper@0
-.endif
-.endm
+        /* Return with iret */
+        iret
 
-#if DBG
+    elseif (Flags AND KI_EXIT_JMP)
 
-.macro VERIFY_INT Label
-    /* Get the current time and mask it to 192 ticks */
-    mov eax, _KeTickCount
-    and eax, 0xC0
-
-    /* Check if we're in the same tick area */
-    cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT]
-    jg VfRst_&Label
-    jl VfWrap_&Label
-
-    /* If we got here, then our count is too large */
-    dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT]
-    jz VfOvr_&Label
-Vf_&Label:
-.endm
-
-.macro VERIFY_INT_END Label, Info
-VfOvr_&Label:
-
-    /* Decrement the dispatch count and check if we should bug check */
-    dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2]
-    jz 1f
-
-    /* Update the tick count */
-    add eax, 0x40
-    mov [edi+KINTERRUPT_TICK_COUNT], eax
-    jmp VfRstDef_&Label
-
-1:
-    /* Check if the debugger is enabled */
-    cmp byte ptr __KdDebuggerEnabled, 0
-    jnz 1f
-
-    /* It isn't, bugcheck */
-    push Info
-    push edi
-    push [edi+KINTERRUPT_SERVICE_CONTEXT]
-    push [edi+KINTERRUPT_SERVICE_ROUTINE]
-    push HARDWARE_INTERRUPT_STORM
-    call _KeBugCheckEx@20
-
-1:
-    /* Debugger enabled, do a debug print + break instead */
-    push [edi+KINTERRUPT_SERVICE_ROUTINE]
-    push offset _IsrOverflowMsg
-    call _DbgPrint
-    add esp, 8
-    int 3
-
-    /* Breakpoint handled, get the new tick count */
-    mov eax, _KeTickCount
-    and eax, 0xC0
-
-VfRst_&Label:
-    /* Reset tick count */
-    mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax
-    mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64
-
-VfRstDef_&Label:
-    /* Put default overflow count and continue */
-    mov ax, _KiISROverflow
-    mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax
-    jmp Vf_&Label
-
-VfWrap_&Label:
-    /* Check if we wrapped */
-    add eax, 0x40
-    cmp eax, [edi+KINTERRUPT_TICK_COUNT]
-    je Vf_&Label
-
-    /* We did, start over */
-    mov eax, _KeTickCount
-    jmp VfRst_&Label
-.endm
+        /* Return to kernel mode with a jmp */
+        jmp edx
 
-#else
+    elseif (Flags AND KI_EXIT_RET)
 
-/* We don't verify interrupts on retail builds */
-.macro VERIFY_INT Label
-.endm
-.macro VERIFY_INT_END Label, Info
-.endm
+        /* Return to kernel mode with a ret */
+        ret
 
-#endif
+    endif
 
+ENDM