2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/include/i386/asmmacro.S
5 * PURPOSE: Assembly Macros for Spinlocks and common Trap Code
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES ******************************************************************/
13 // Arguments for TRAP_EPILOG
14 #define FromSystemCall 1
15 #define DoRestorePreviousMode 1
16 #define DoRestoreEverything 1
17 #define DoRestoreSegments 1
18 #define DoRestoreVolatiles 1
19 #define DoPushFakeErrorCode 1
21 #define DoFixupAbios 1
22 #define NotFromSystemCall 0
23 #define DoNotRestorePreviousMode 0
24 #define DoNotRestoreEverything 0
25 #define DoNotRestoreSegments 0
26 #define DoNotRestoreVolatiles 0
27 #define DoNotPushFakeErrorCode 0
28 #define DoNotFixupV86 0
29 #define DoNotFixupAbios 0
32 #define INT_32_DPL0 0x8E00
33 #define INT_32_DPL3 0xEE00
36 // This table contains the prefix flags that are used by V86 emulation
38 .equ PREFIX_FLAG_ES, 0x00000100
39 .equ PREFIX_FLAG_CS, 0x00000200
40 .equ PREFIX_FLAG_SS, 0x00000400
41 .equ PREFIX_FLAG_DS, 0x00000800
42 .equ PREFIX_FLAG_FS, 0x00001000
43 .equ PREFIX_FLAG_GS, 0x00002000
44 .equ PREFIX_FLAG_OPER32, 0x00004000
45 .equ PREFIX_FLAG_ADDR32, 0x00008000
46 .equ PREFIX_FLAG_LOCK, 0x00010000
47 .equ PREFIX_FLAG_REPNE, 0x00020000
48 .equ PREFIX_FLAG_REP, 0x00040000
50 .intel_syntax noprefix
53 // These macros are inlined equivalents of KiAcquire/ReleaseSpinlock, that is,
54 // they will not be compiled into non-SMP builds. Usage is as follows:
58 // ACQUIRE_SPINLOCK(reg, .spin)
59 // <thread-safe code here>
60 // RELEASE_SPINLOCK(reg)
65 // <any necessary steps to be able to jump back safely>
66 / SPIN_ON_LOCK(reg, .BeginYourFunction)
71 #define ACQUIRE_SPINLOCK(x, y) \
72 lock bts dword ptr [x], 0; \
74 #define RELEASE_SPINLOCK(x) mov byte ptr [x], 0
75 #define SPIN_ON_LOCK(x, y) \
77 test dword ptr [x], 1; \
83 #define ACQUIRE_SPINLOCK(x, y)
84 #define RELEASE_SPINLOCK(x)
88 // @name UNHANDLED_PATH
90 // This macro prints out that the current code path is not expected yet
96 .macro UNHANDLED_PATH Reason
104 /* Print debug message */
105 push offset _UnhandledMsg
109 /* Loop indefinitely */
117 // @name UNHANDLED_V86_PATH
119 // This macro prints out that the current code path is for unhandled VDM support
125 .macro UNHANDLED_V86_PATH
129 /* Print debug message */
130 push offset _V86UnhandledMsg
134 /* Loop indefinitely */
141 // This macro creates an IDT entry for the given handler
144 // Pointer to the IDT handler
147 // Descriptor Bits to associate
151 .macro idt Handler, Bits
158 // @name GENERATE_IDT_STUB
160 // This macro creates an IDT entry for an unexpected interrupt handler.
166 .macro GENERATE_IDT_STUB Number
167 idt _KiUnexpectedInterrupt&Number, INT_32_DPL0
171 // @name GENERATE_IDT_STUBS
173 // This macro creates unexpected interrupt IDT entries.
180 .macro GENERATE_IDT_STUBS
189 // @name GENERATE_INT_HANDLER
191 // This macro creates an unexpected interrupt handler.
197 .macro GENERATE_INT_HANDLER Number
198 .func KiUnexpectedInterrupt&Number
199 _KiUnexpectedInterrupt&Number:
200 push PRIMARY_VECTOR_BASE + Number
201 jmp _KiEndUnexpectedRange@0
206 // @name GENERATE_INT_HANDLERS
208 // This macro creates the unexpected interrupt handlers.
215 .macro GENERATE_INT_HANDLERS
218 GENERATE_INT_HANDLER %i
224 // @name GENERATE_TRAP_HANDLER
226 // This macro creates a kernel trap handler.
232 .macro GENERATE_TRAP_HANDLER Name, ErrorCode
239 sub esp, KTRAP_FRAME_LENGTH - KTRAP_FRAME_PREVIOUS_MODE
241 call @&Name&Handler@4
246 // @name GENERATE_HAL_INT_HANDLER
248 // This macro creates a HAL hardware interrupt handler.
254 .macro GENERATE_HAL_INT_HANDLER Number
255 .func HalpHardwareInterrupt&Number
256 _HalpHardwareInterrupt&Number:
257 int PRIMARY_VECTOR_BASE + Number
263 // @name GENERATE_HAL_INT_HANDLERS
265 // This macro creates the unexpected interrupt handlers.
271 .macro GENERATE_HAL_INT_HANDLERS
274 GENERATE_HAL_INT_HANDLER %i
280 // @name INVALID_V86_OPCODE
282 // This macro creates one or more entries for unhandled V86 Opcodes
283 // in the V86 Opcode Table.
286 // Number of entries to generate.
290 .macro INVALID_V86_OPCODE count
297 // @name GENERATE_PREFIX_HANDLER
299 // This macro creates a prefix opcode handler.
305 .macro GENERATE_PREFIX_HANDLER Name
306 .func Opcode&Name&PrefixV86
307 _Opcode&Name&PrefixV86:
308 or ebx, PREFIX_FLAG_&Name
309 jmp _OpcodeGenericPrefixV86
314 // @name INVALID_V86_OPCODE
316 // This macro prints out visible message and hangs the computer.
320 // @remark Temporary debugging use.
322 .macro UNHANDLED_V86_OPCODE
323 /* Print debug message, breakpoint and freeze */
325 push offset V86DebugMsg
334 // This macro contains out-of-line code for various Trap Frame Fixups, such as:
336 // - DR Fixup: Loads and restores DR registers.
337 // - V86 Fixup: Loads and restores V86 segments.
338 // - ABIOS Fixup: Loads and restores the ABIOS state and stack.
342 // @remark ebp = PKTRAP_FRAME
344 .macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix
347 /* Check if this was V86 mode */
348 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
351 /* Check if it was user mode */
352 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
362 mov [ebp+KTRAP_FRAME_DR0], ebx
363 mov [ebp+KTRAP_FRAME_DR1], ecx
364 mov [ebp+KTRAP_FRAME_DR2], edi
372 mov [ebp+KTRAP_FRAME_DR3], ebx
373 mov [ebp+KTRAP_FRAME_DR6], ecx
374 mov [ebp+KTRAP_FRAME_DR7], edi
381 mov edi, fs:[KPCR_PRCB]
384 mov ebx, [edi+KPRCB_DR0]
385 mov ecx, [edi+KPRCB_DR1]
392 mov ebx, [edi+KPRCB_DR2]
393 mov ecx, [edi+KPRCB_DR3]
400 mov ebx, [edi+KPRCB_DR6]
401 mov ecx, [edi+KPRCB_DR7]
416 /* Get V86 segment registers */
417 mov eax, [ebp+KTRAP_FRAME_V86_FS]
418 mov ebx, [ebp+KTRAP_FRAME_V86_GS]
419 mov ecx, [ebp+KTRAP_FRAME_V86_ES]
420 mov edx, [ebp+KTRAP_FRAME_V86_DS]
422 /* Restore them into Protected Mode trap frame */
423 mov [ebp+KTRAP_FRAME_FS], ax
424 mov [ebp+KTRAP_FRAME_GS], bx
425 mov [ebp+KTRAP_FRAME_ES], cx
426 mov [ebp+KTRAP_FRAME_DS], dx
428 /* Go back to mainline code */
434 // @name SET_TF_DEBUG_HEADER
436 // This macro sets up the debug header in the trap frame.
440 // @remark ebp = PKTRAP_FRAME.
441 // edi/ebx = Have been saved and can be used.
443 .macro SET_TF_DEBUG_HEADER
444 /* Get the Debug Trap Frame EBP/EIP */
445 mov ebx, [ebp+KTRAP_FRAME_EBP]
446 mov edi, [ebp+KTRAP_FRAME_EIP]
448 /* Write the debug data */
449 mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
450 mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
451 mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
452 mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
456 // @name CHECK_FOR_APC_DELIVER
458 // This macro checks if the trapframe indicates a return to user-mode,
459 // and, if so, checks if user-mode APCs should be delivered.
461 // @param PreserveEax
462 // Determines if EAX should be preserved. Implies that the segment
463 // registers will also be saved.
465 // @remark ebp = PKTRAP_FRAME.
466 // ebx = Saved and will be used.
468 .macro CHECK_FOR_APC_DELIVER PreserveEax
469 /* Check for V86 mode */
470 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
473 /* Deliver APCs only if we were called from user mode */
474 test byte ptr [ebp+KTRAP_FRAME_CS], 1
477 /* Get the current thread */
479 mov ebx, PCR[KPCR_CURRENT_THREAD]
481 /* Make it non-alerted */
482 mov byte ptr [ebx+KTHREAD_ALERTED], 0
484 /* And only if any are actually pending */
485 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
488 /* Save pointer to Trap Frame */
492 /* Save some stuff that raising IRQL will kill */
493 mov [ebx+KTRAP_FRAME_EAX], eax
494 mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK
495 mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
496 mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
497 mov dword ptr [ebx+KTRAP_FRAME_GS], 0
500 /* Raise IRQL to APC_LEVEL */
512 call _KiDeliverApc@12
514 /* Return to old IRQL */
518 /* Restore EAX (only in volatile case) */
520 mov eax, [ebx+KTRAP_FRAME_EAX]
530 // This macro creates a standard trap entry prologue.
531 // It should be used for entry into any kernel trap (KiTrapXx), but not for
532 // system calls, which require special handling.
535 // Identifying name of the caller function; will be used to append
536 // to the name V86 and DR helper functions, which must already exist.
538 // @remark Use as follows:
540 // /* Push fake error code */
543 // /* Enter common prologue */
547 // <Your Trap Code Here>
549 .macro TRAP_PROLOG Label EndLabel
550 /* Just to be safe, clear out the HIWORD, since it's reserved */
551 mov word ptr [esp+2], 0
553 /* Save the non-volatiles */
559 /* Save FS and set it to PCR */
565 /* Save exception list and bogus previous mode */
566 push fs:[KPCR_EXCEPTION_LIST]
569 /* Save volatiles and segment registers */
577 /* Set the R3 data segment */
578 mov ax, KGDT_R3_DATA + RPL_MASK
580 /* Skip debug registers and debug stuff */
583 /* Load the segment registers */
589 /* Check if this interrupt happened in 16-bit mode */
591 jb _Ki16BitStackException
596 /* Check if this was from V86 Mode */
597 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
601 /* Get current thread */
602 mov ecx, fs:[KPCR_CURRENT_THREAD]
606 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
608 /* Check if the thread was being debugged */
609 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
612 /* Set the Trap Frame Debug Header */
620 // This macro creates a standard interrupt entry prologue.
621 // It should be used for entry into any interrupt, including software.
624 // Identifying name of the caller function; will be used to append
625 // to the name V86, ABIOS and DR helper functions, which must exist.
627 // @remark For software interrupts, make sure that a fake INT stack is created.
629 .macro INT_PROLOG Label EndLabel FakeErrorCode
632 /* Save fake error code */
636 /* Save the non-volatiles */
642 /* Skip debug registers and other stuff */
649 mov [esp+KTRAP_FRAME_EAX], eax
650 mov [esp+KTRAP_FRAME_ECX], ecx
651 mov [esp+KTRAP_FRAME_EDX], edx
652 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
654 /* Check if this was from V86 Mode */
655 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
658 /* Check if this was kernel mode */
660 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE
664 mov word ptr [esp+KTRAP_FRAME_FS], fs
665 mov word ptr [esp+KTRAP_FRAME_DS], ds
666 mov word ptr [esp+KTRAP_FRAME_ES], es
667 mov [esp+KTRAP_FRAME_GS], gs
669 /* Load the segment registers (use OVERRIDE (0x66)) */
671 mov eax, KGDT_R3_DATA | RPL_MASK
680 /* Get the previous exception list */
681 mov ebx, fs:[KPCR_EXCEPTION_LIST]
683 /* Set the exception handler chain terminator */
684 mov dword ptr fs:[KPCR_EXCEPTION_LIST], -1
686 /* Save the previous exception list */
687 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx
690 /* Setup the 16-bit stack */
691 lea eax, [esp+KTRAP_FRAME_ERROR_CODE]
692 lea ecx, [esp+KTRAP_FRAME_EIP]
697 /* Check if this is the ABIOS stack */
698 /* cmp esp, 0x10000*/
701 /* Delete error code */
702 and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0
704 /* Get the current thread and clear direction flag */
705 mov ecx, PCR[KPCR_CURRENT_THREAD]
709 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
711 /* Check if the thread was being debugged */
712 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
719 /* Save DR registers if needed */
722 /* Set the trap frame debug header */
728 // @name SYSCALL_PROLOG
730 // This macro creates a system call entry prologue.
731 // It should be used for entry into any fast-system call (KiGetTickCount,
732 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
736 // Unique label identifying the name of the caller function; will be
737 // used to append to the name of the DR helper function, which must
742 .macro SYSCALL_PROLOG Label EndLabel
743 /* Create a trap frame */
751 /* Load PCR Selector into fs */
756 /* Get a pointer to the current thread */
757 mov esi, PCR[KPCR_CURRENT_THREAD]
759 /* Save the previous exception list */
760 push PCR[KPCR_EXCEPTION_LIST]
762 /* Set the exception handler chain terminator */
763 mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
765 /* Save the old previous mode */
766 push [esi+KTHREAD_PREVIOUS_MODE]
768 /* Skip the other registers */
771 /* Set the new previous mode based on the saved CS selector */
774 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl
776 /* Go on the Kernel stack frame */
779 /* Save the old trap frame pointer where EDX would be saved */
780 mov ebx, [esi+KTHREAD_TRAP_FRAME]
781 mov [ebp+KTRAP_FRAME_EDX], ebx
784 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
786 /* Check if the thread was being debugged */
787 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
789 /* Set the thread's trap frame and clear direction flag */
790 mov [esi+KTHREAD_TRAP_FRAME], ebp
793 /* Save DR registers if needed */
796 /* Set the trap frame debug header */
800 /* Enable interrupts */
805 // @name FASTCALL_PROLOG
810 // Unique label identifying the name of the caller function; will be
811 // used to append to the name of the DR helper function, which must
816 .macro FASTCALL_PROLOG Label EndLabel
818 /* Set user selector */
819 mov ecx, KGDT_R3_DATA | RPL_MASK
825 /* Set DS/ES to User Selector */
829 /* Set the current stack to Kernel Stack */
830 mov ecx, PCR[KPCR_TSS]
831 mov esp, [ecx+KTSS_ESP0]
833 /* Set up a fake INT Stack. */
834 push KGDT_R3_DATA + RPL_MASK
835 push edx /* Ring 3 SS:ESP */
836 pushf /* Ring 3 EFLAGS */
837 push 2 /* Ring 0 EFLAGS */
838 add edx, 8 /* Skip user parameter list */
839 popf /* Set our EFLAGS */
840 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
841 push KGDT_R3_CODE + RPL_MASK
842 push dword ptr ds:KUSER_SHARED_SYSCALL_RET
844 /* Setup the Trap Frame stack */
850 push KGDT_R3_TEB + RPL_MASK
852 /* Save pointer to our PCR */
853 mov ebx, PCR[KPCR_SELF]
855 /* Get a pointer to the current thread */
856 mov esi, [ebx+KPCR_CURRENT_THREAD]
858 /* Set the exception handler chain terminator */
859 push [ebx+KPCR_EXCEPTION_LIST]
860 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
862 /* Use the thread's stack */
863 mov ebp, [esi+KTHREAD_INITIAL_STACK]
865 /* Push previous mode */
868 /* Skip the other registers */
871 /* Make space for us on the stack */
874 /* Write the previous mode */
875 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
882 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
884 /* Check if the thread was being debugged */
885 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
887 /* Set the thread's trap frame */
888 mov [esi+KTHREAD_TRAP_FRAME], ebp
890 /* Save DR registers if needed */
893 /* Set the trap frame debug header */
897 /* Enable interrupts */
902 // @name V86_TRAP_PROLOG
904 // This macro creates a V86 Trap entry prologue.
905 // It should be used for entry into any fast-system call (KiGetTickCount,
906 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
910 // Unique label identifying the name of the caller function; will be
911 // used to append to the name of the DR helper function, which must
916 .macro V86_TRAP_PROLOG Label EndLabel
918 /* Skip everything to the error code */
919 sub esp, KTRAP_FRAME_ERROR_CODE
921 /* Clear the error code */
922 mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
924 /* Save the registers we'll trample */
925 mov [esp+KTRAP_FRAME_EBX], ebx
926 mov [esp+KTRAP_FRAME_EAX], eax
927 mov [esp+KTRAP_FRAME_EBP], ebp
928 mov [esp+KTRAP_FRAME_ESI], esi
929 mov [esp+KTRAP_FRAME_EDI], edi
931 /* Save PCR and Ring 3 segments */
933 mov eax, KGDT_R3_DATA + RPL_MASK
935 /* Save ECX and EDX too */
936 mov [esp+KTRAP_FRAME_ECX], ecx
937 mov [esp+KTRAP_FRAME_EDX], edx
939 /* Set debugging markers */
940 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
941 mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
943 /* Now set segments (use OVERRIDE, 0x66) */
951 /* Set the trap frame in the stack and clear the direction flag */
955 /* Save the exception list */
956 mov eax, fs:[KPCR_EXCEPTION_LIST]
957 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
959 /* Check if we need debugging */
961 test eax, ~DR7_RESERVED_MASK
962 mov [esp+KTRAP_FRAME_DR7], eax
969 // @name V86_TRAP_EPILOG
971 // This macro creates an epilogue for leaving V86 traps
977 .macro V86_TRAP_EPILOG
979 /* Get the current thread and make it unalerted */
981 mov ebx, PCR[KPCR_CURRENT_THREAD]
982 mov byte ptr [ebx+KTHREAD_ALERTED], 0
984 /* Check if it has User-mode APCs pending */
985 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
988 /* It doesn't, pop the frame */
989 add esp, KTRAP_FRAME_EDX
994 /* Check if DR registers should be restored */
995 test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
998 /* Finish popping the rest of the frame, and return to P-mode */
1012 mov esi, [ebp+KTRAP_FRAME_DR0]
1013 mov edi, [ebp+KTRAP_FRAME_DR1]
1018 /* Get DR2 and load DR0-2 */
1019 mov ebx, [ebp+KTRAP_FRAME_DR2]
1025 mov esi, [ebp+KTRAP_FRAME_DR0]
1026 mov edi, [ebp+KTRAP_FRAME_DR1]
1027 mov ebx, [ebp+KTRAP_FRAME_DR7]
1033 jmp V86DebugContinue
1037 /* Raise to APC level */
1041 /* Save KIRQL and deliver APCs */
1047 call _KiDeliverApc@12
1054 /* Check if we're not in V86 anymore */
1055 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1060 // @name TRAP_EPILOG
1062 // This macro creates an epilogue for leaving any system trap.
1063 // It is used for exiting system calls, exceptions, interrupts and generic
1066 // @param SystemCall
1067 // Specifies whether this trap will exit a system call. If so, special
1068 // code will be assembled to potentially use SYSEXIT instead of IRETD.
1070 // @param RestorePreviousMode
1071 // Specifies if the previous mode should be restored.
1073 // @param RestoreSegments
1074 // Specifies if the segment registers should be restored.
1076 // @param RestoreVolatiles
1077 // Specifies if the volatile registers should be restored.
1079 // @param RestoreAllRegs
1080 // Specifies if volatiles and segments should both be restored.
1084 .macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs
1086 /* Assert the flags */
1089 test edx, EFLAGS_INTERRUPT_MASK
1092 /* Assert the stack */
1096 /* Assert the trap frame */
1100 sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1108 /* Assert exception list */
1109 cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0
1118 /* Get exception list */
1119 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
1122 /* Assert the saved exception list */
1130 mov PCR[KPCR_EXCEPTION_LIST], edx
1132 .if \RestorePreviousMode
1133 /* Get previous mode */
1134 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1137 /* Assert the saved previous mode */
1144 /* Restore the previous mode */
1145 mov esi, PCR[KPCR_CURRENT_THREAD]
1146 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
1150 /* Assert the saved previous mode */
1151 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1159 /* Check for debug registers */
1160 test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1165 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1168 /* Check if the frame was edited */
1169 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
1173 /* Check the old mode */
1174 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1175 bt word ptr [esp+KTRAP_FRAME_CS], 0
1180 .if \RestoreVolatiles
1181 /* Restore volatiles */
1182 mov edx, [esp+KTRAP_FRAME_EDX]
1183 mov ecx, [esp+KTRAP_FRAME_ECX]
1184 mov eax, [esp+KTRAP_FRAME_EAX]
1187 /* Check if we were called from kernel mode */
1188 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1191 .if \RestoreSegments
1192 /* Restore segment registers */
1193 lea esp, [ebp+KTRAP_FRAME_GS]
1201 lea esp, [ebp+KTRAP_FRAME_FS]
1205 /* Skip debug information and unsaved registers */
1206 lea esp, [ebp+KTRAP_FRAME_EDI]
1212 /* Check for ABIOS */
1213 cmp word ptr [esp+8], 0x80
1216 /* Pop error code */
1220 /* Check if previous CS is from user-mode */
1221 test dword ptr [esp+4], 1
1223 /* It is, so use Fast Exit */
1226 /* Jump back to stub */
1238 /* Is SYSEXIT Supported/Wanted? */
1239 cmp dword ptr ss:[_KiFastSystemCallDisable], 0
1241 test dword ptr [esp+8], EFLAGS_TF
1244 /* Restore FS to TIB */
1245 mov ecx, KGDT_R3_TEB + RPL_MASK
1248 /* We will be cleaning up the stack ourselves */
1249 pop edx /* New Ring 3 EIP */
1250 add esp, 4 /* Skip Ring 3 DS */
1251 and dword ptr [esp], 0xfffffdff /* Remove EFLAGS_INTERRUPT_MASK from EFLAGS */
1252 popf /* Restore old EFLAGS */
1253 pop ecx /* Old Ring 3 SS:ESP */
1257 * ECX points to the old User Stack.
1258 * EDX points to the instruction to execute in usermode after the sysenter
1267 mov eax, [esp+KTRAP_FRAME_EAX]
1269 /* Skip registers */
1272 /* Restore segments and volatiles */
1279 /* Jump back to mainline code */
1285 /* Fix up the mask */
1286 add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1294 /* Check if this was V86 mode */
1295 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1298 /* Check if it was user mode */
1299 test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK
1308 mov esi, [ebp+KTRAP_FRAME_DR0]
1309 mov edi, [ebp+KTRAP_FRAME_DR1]
1310 mov ebx, [ebp+KTRAP_FRAME_DR2]
1318 mov esi, [ebp+KTRAP_FRAME_DR3]
1319 mov edi, [ebp+KTRAP_FRAME_DR6]
1320 mov ebx, [ebp+KTRAP_FRAME_DR7]
1329 /* Restore real CS value */
1330 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
1331 mov [esp+KTRAP_FRAME_CS], ebx
1334 * If ESP was modified, then a special interrupt exit stack
1335 * must be created to "update" ESP's value in a legal manner
1337 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
1339 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
1341 /* Copy Interrupt Stack */
1342 mov esi, [esp+KTRAP_FRAME_EFLAGS]
1344 mov esi, [esp+KTRAP_FRAME_CS]
1346 mov esi, [esp+KTRAP_FRAME_EIP]
1349 .if \RestoreVolatiles
1350 /* Restore volatiles */
1351 mov eax, [esp+KTRAP_FRAME_EAX]
1352 mov edx, [esp+KTRAP_FRAME_EDX]
1353 mov ecx, [esp+KTRAP_FRAME_ECX]
1357 add esp, KTRAP_FRAME_EDI
1369 // This macro creates an epilogue for leaving any system trap.
1370 // It is used for exiting system calls, exceptions, interrupts and generic
1373 // @param Spurious - TRUE if the interrupt was unexpected and spurious.
1377 .macro INT_EPILOG Spurious
1380 /* Just exit the trap */
1381 jmp _Kei386EoiHelper@0
1383 /* Disable interrupts */
1386 /* End the interrupt and do EOI */
1387 call _HalEndSystemInterrupt@8
1388 jmp _Kei386EoiHelper@0
1394 .macro VERIFY_INT Label
1395 /* Get the current time and mask it to 192 ticks */
1396 mov eax, _KeTickCount
1399 /* Check if we're in the same tick area */
1400 cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT]
1404 /* If we got here, then our count is too large */
1405 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT]
1410 .macro VERIFY_INT_END Label, Info
1413 /* Decrement the dispatch count and check if we should bug check */
1414 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2]
1417 /* Update the tick count */
1419 mov [edi+KINTERRUPT_TICK_COUNT], eax
1423 /* Check if the debugger is enabled */
1424 cmp byte ptr __KdDebuggerEnabled, 0
1427 /* It isn't, bugcheck */
1430 push [edi+KINTERRUPT_SERVICE_CONTEXT]
1431 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1432 push HARDWARE_INTERRUPT_STORM
1433 call _KeBugCheckEx@20
1436 /* Debugger enabled, do a debug print + break instead */
1437 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1438 push offset _IsrOverflowMsg
1443 /* Breakpoint handled, get the new tick count */
1444 mov eax, _KeTickCount
1448 /* Reset tick count */
1449 mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax
1450 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64
1453 /* Put default overflow count and continue */
1454 mov ax, _KiISROverflow
1455 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax
1459 /* Check if we wrapped */
1461 cmp eax, [edi+KINTERRUPT_TICK_COUNT]
1464 /* We did, start over */
1465 mov eax, _KeTickCount
1471 /* We don't verify interrupts on retail builds */
1472 .macro VERIFY_INT Label
1474 .macro VERIFY_INT_END Label, Info