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
100 /* Print debug message */
101 push offset _UnhandledMsg
105 /* Loop indefinitely */
112 // This macro creates an IDT entry for the given handler
115 // Pointer to the IDT handler
118 // Descriptor Bits to associate
122 .macro idt Handler, Bits
129 // @name GENERATE_IDT_STUB
131 // This macro creates an IDT entry for an unexpected interrupt handler.
137 .macro GENERATE_IDT_STUB Number
138 idt _KiUnexpectedInterrupt&Number, INT_32_DPL0
142 // @name GENERATE_IDT_STUBS
144 // This macro creates unexpected interrupt IDT entries.
151 .macro GENERATE_IDT_STUBS
160 // @name GENERATE_INT_HANDLER
162 // This macro creates an unexpected interrupt handler.
168 .macro GENERATE_INT_HANDLER Number
169 .func KiUnexpectedInterrupt&Number
170 _KiUnexpectedInterrupt&Number:
171 push PRIMARY_VECTOR_BASE + Number
172 jmp _KiEndUnexpectedRange@0
177 // @name GENERATE_INT_HANDLERS
179 // This macro creates the unexpected interrupt handlers.
186 .macro GENERATE_INT_HANDLERS
189 GENERATE_INT_HANDLER %i
195 // @name GENERATE_HAL_INT_HANDLER
197 // This macro creates a HAL hardware interrupt handler.
203 .macro GENERATE_HAL_INT_HANDLER Number
204 .func HalpHardwareInterrupt&Number
205 _HalpHardwareInterrupt&Number:
206 int PRIMARY_VECTOR_BASE + Number
212 // @name GENERATE_HAL_INT_HANDLERS
214 // This macro creates the unexpected interrupt handlers.
220 .macro GENERATE_HAL_INT_HANDLERS
223 GENERATE_HAL_INT_HANDLER %i
229 // @name INVALID_V86_OPCODE
231 // This macro creates one or more entries for unhandled V86 Opcodes
232 // in the V86 Opcode Table.
235 // Number of entries to generate.
239 .macro INVALID_V86_OPCODE count
246 // @name GENERATE_PREFIX_HANDLER
248 // This macro creates a prefix opcode handler.
254 .macro GENERATE_PREFIX_HANDLER Name
255 .func Opcode&Name&PrefixV86
256 _Opcode&Name&PrefixV86:
257 or ebx, PREFIX_FLAG_&Name
258 jmp _OpcodeGenericPrefixV86
263 // @name INVALID_V86_OPCODE
265 // This macro prints out visible message and hangs the computer.
269 // @remark Temporary debugging use.
271 .macro UNHANDLED_V86_OPCODE
272 /* Print debug message, breakpoint and freeze */
274 push offset V86DebugMsg
283 // This macro contains out-of-line code for various Trap Frame Fixups, such as:
285 // - DR Fixup: Loads and restores DR registers.
286 // - V86 Fixup: Loads and restores V86 segments.
287 // - ABIOS Fixup: Loads and restores the ABIOS state and stack.
291 // @remark ebp = PKTRAP_FRAME
293 .macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix
296 /* Check if this was V86 mode */
297 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
300 /* Check if it was user mode */
301 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
311 mov [ebp+KTRAP_FRAME_DR0], ebx
312 mov [ebp+KTRAP_FRAME_DR1], ecx
313 mov [ebp+KTRAP_FRAME_DR2], edi
321 mov [ebp+KTRAP_FRAME_DR3], ebx
322 mov [ebp+KTRAP_FRAME_DR6], ecx
323 mov [ebp+KTRAP_FRAME_DR7], edi
330 mov edi, fs:[KPCR_PRCB]
333 mov ebx, [edi+KPRCB_DR0]
334 mov ecx, [edi+KPRCB_DR1]
341 mov ebx, [edi+KPRCB_DR2]
342 mov ecx, [edi+KPRCB_DR3]
349 mov ebx, [edi+KPRCB_DR6]
350 mov ecx, [edi+KPRCB_DR7]
365 /* Get V86 segment registers */
366 mov eax, [ebp+KTRAP_FRAME_V86_FS]
367 mov ebx, [ebp+KTRAP_FRAME_V86_GS]
368 mov ecx, [ebp+KTRAP_FRAME_V86_ES]
369 mov edx, [ebp+KTRAP_FRAME_V86_DS]
371 /* Restore them into Protected Mode trap frame */
372 mov [ebp+KTRAP_FRAME_FS], ax
373 mov [ebp+KTRAP_FRAME_GS], bx
374 mov [ebp+KTRAP_FRAME_ES], cx
375 mov [ebp+KTRAP_FRAME_DS], dx
377 /* Go back to mainline code */
383 // @name SET_TF_DEBUG_HEADER
385 // This macro sets up the debug header in the trap frame.
389 // @remark ebp = PKTRAP_FRAME.
390 // edi/ebx = Have been saved and can be used.
392 .macro SET_TF_DEBUG_HEADER
393 /* Get the Debug Trap Frame EBP/EIP */
394 mov ebx, [ebp+KTRAP_FRAME_EBP]
395 mov edi, [ebp+KTRAP_FRAME_EIP]
397 /* Write the debug data */
398 mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
399 mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
400 mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
401 mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
405 // @name CHECK_FOR_APC_DELIVER
407 // This macro checks if the trapframe indicates a return to user-mode,
408 // and, if so, checks if user-mode APCs should be delivered.
410 // @param PreserveEax
411 // Determines if EAX should be preserved. Implies that the segment
412 // registers will also be saved.
414 // @remark ebp = PKTRAP_FRAME.
415 // ebx = Saved and will be used.
417 .macro CHECK_FOR_APC_DELIVER PreserveEax
418 /* Check for V86 mode */
419 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
422 /* Deliver APCs only if we were called from user mode */
423 test byte ptr [ebp+KTRAP_FRAME_CS], 1
426 /* Get the current thread */
428 mov ebx, PCR[KPCR_CURRENT_THREAD]
430 /* Make it non-alerted */
431 mov byte ptr [ebx+KTHREAD_ALERTED], 0
433 /* And only if any are actually pending */
434 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
437 /* Save pointer to Trap Frame */
441 /* Save some stuff that raising IRQL will kill */
442 mov [ebx+KTRAP_FRAME_EAX], eax
443 mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK
444 mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
445 mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
446 mov dword ptr [ebx+KTRAP_FRAME_GS], 0
449 /* Raise IRQL to APC_LEVEL */
461 call _KiDeliverApc@12
463 /* Return to old IRQL */
467 /* Restore EAX (only in volatile case) */
469 mov eax, [ebx+KTRAP_FRAME_EAX]
479 // This macro creates a standard trap entry prologue.
480 // It should be used for entry into any kernel trap (KiTrapXx), but not for
481 // system calls, which require special handling.
484 // Identifying name of the caller function; will be used to append
485 // to the name V86 and DR helper functions, which must already exist.
487 // @remark Use as follows:
489 // /* Push fake error code */
492 // /* Enter common prologue */
496 // <Your Trap Code Here>
498 .macro TRAP_PROLOG Label EndLabel
499 /* Just to be safe, clear out the HIWORD, since it's reserved */
500 mov word ptr [esp+2], 0
502 /* Save the non-volatiles */
508 /* Save FS and set it to PCR */
514 /* Save exception list and bogus previous mode */
515 push fs:[KPCR_EXCEPTION_LIST]
518 /* Save volatiles and segment registers */
526 /* Set the R3 data segment */
527 mov ax, KGDT_R3_DATA + RPL_MASK
529 /* Skip debug registers and debug stuff */
532 /* Load the segment registers */
538 /* Check if this interrupt happened in 16-bit mode */
540 jb _Ki16BitStackException
545 /* Check if this was from V86 Mode */
546 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
550 /* Get current thread */
551 mov ecx, fs:[KPCR_CURRENT_THREAD]
555 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
557 /* Check if the thread was being debugged */
558 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
561 /* Set the Trap Frame Debug Header */
569 // This macro creates a standard interrupt entry prologue.
570 // It should be used for entry into any interrupt, including software.
573 // Identifying name of the caller function; will be used to append
574 // to the name V86, ABIOS and DR helper functions, which must exist.
576 // @remark For software interrupts, make sure that a fake INT stack is created.
578 .macro INT_PROLOG Label EndLabel FakeErrorCode
581 /* Save fake error code */
585 /* Save the non-volatiles */
591 /* Skip debug registers and other stuff */
598 mov [esp+KTRAP_FRAME_EAX], eax
599 mov [esp+KTRAP_FRAME_ECX], ecx
600 mov [esp+KTRAP_FRAME_EDX], edx
601 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
603 /* Check if this was from V86 Mode */
604 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
607 /* Check if this was kernel mode */
609 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE
613 mov word ptr [esp+KTRAP_FRAME_FS], fs
614 mov word ptr [esp+KTRAP_FRAME_DS], ds
615 mov word ptr [esp+KTRAP_FRAME_ES], es
616 mov [esp+KTRAP_FRAME_GS], gs
618 /* Load the segment registers (use OVERRIDE (0x66)) */
620 mov eax, KGDT_R3_DATA | RPL_MASK
629 /* Get the previous exception list */
630 mov ebx, fs:[KPCR_EXCEPTION_LIST]
632 /* Set the exception handler chain terminator */
633 mov dword ptr fs:[KPCR_EXCEPTION_LIST], -1
635 /* Save the previous exception list */
636 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx
639 /* Setup the 16-bit stack */
640 lea eax, [esp+KTRAP_FRAME_ERROR_CODE]
641 lea ecx, [esp+KTRAP_FRAME_EIP]
646 /* Check if this is the ABIOS stack */
647 /* cmp esp, 0x10000*/
650 /* Delete error code */
651 and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0
653 /* Get the current thread and clear direction flag */
654 mov ecx, PCR[KPCR_CURRENT_THREAD]
658 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
660 /* Check if the thread was being debugged */
661 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
668 /* Save DR registers if needed */
671 /* Set the trap frame debug header */
677 // @name SYSCALL_PROLOG
679 // This macro creates a system call entry prologue.
680 // It should be used for entry into any fast-system call (KiGetTickCount,
681 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
685 // Unique label identifying the name of the caller function; will be
686 // used to append to the name of the DR helper function, which must
691 .macro SYSCALL_PROLOG Label EndLabel
692 /* Create a trap frame */
700 /* Load PCR Selector into fs */
705 /* Get a pointer to the current thread */
706 mov esi, PCR[KPCR_CURRENT_THREAD]
708 /* Save the previous exception list */
709 push PCR[KPCR_EXCEPTION_LIST]
711 /* Set the exception handler chain terminator */
712 mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
714 /* Save the old previous mode */
715 push [esi+KTHREAD_PREVIOUS_MODE]
717 /* Skip the other registers */
720 /* Set the new previous mode based on the saved CS selector */
723 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl
725 /* Go on the Kernel stack frame */
728 /* Save the old trap frame pointer where EDX would be saved */
729 mov ebx, [esi+KTHREAD_TRAP_FRAME]
730 mov [ebp+KTRAP_FRAME_EDX], ebx
733 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
735 /* Check if the thread was being debugged */
736 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
738 /* Set the thread's trap frame and clear direction flag */
739 mov [esi+KTHREAD_TRAP_FRAME], ebp
742 /* Save DR registers if needed */
745 /* Set the trap frame debug header */
749 /* Enable interrupts */
754 // @name FASTCALL_PROLOG
759 // Unique label identifying the name of the caller function; will be
760 // used to append to the name of the DR helper function, which must
765 .macro FASTCALL_PROLOG Label EndLabel
767 /* Set user selector */
768 mov ecx, KGDT_R3_DATA | RPL_MASK
774 /* Set DS/ES to User Selector */
778 /* Set the current stack to Kernel Stack */
779 mov ecx, PCR[KPCR_TSS]
780 mov esp, [ecx+KTSS_ESP0]
782 /* Set up a fake INT Stack. */
783 push KGDT_R3_DATA + RPL_MASK
784 push edx /* Ring 3 SS:ESP */
785 pushf /* Ring 3 EFLAGS */
786 push 2 /* Ring 0 EFLAGS */
787 add edx, 8 /* Skip user parameter list */
788 popf /* Set our EFLAGS */
789 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
790 push KGDT_R3_CODE + RPL_MASK
791 push dword ptr ds:KUSER_SHARED_SYSCALL_RET
793 /* Setup the Trap Frame stack */
799 push KGDT_R3_TEB + RPL_MASK
801 /* Save pointer to our PCR */
802 mov ebx, PCR[KPCR_SELF]
804 /* Get a pointer to the current thread */
805 mov esi, [ebx+KPCR_CURRENT_THREAD]
807 /* Set the exception handler chain terminator */
808 push [ebx+KPCR_EXCEPTION_LIST]
809 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
811 /* Use the thread's stack */
812 mov ebp, [esi+KTHREAD_INITIAL_STACK]
814 /* Push previous mode */
817 /* Skip the other registers */
820 /* Make space for us on the stack */
823 /* Write the previous mode */
824 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
831 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
833 /* Check if the thread was being debugged */
834 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
836 /* Set the thread's trap frame */
837 mov [esi+KTHREAD_TRAP_FRAME], ebp
839 /* Save DR registers if needed */
842 /* Set the trap frame debug header */
846 /* Enable interrupts */
851 // @name V86_TRAP_PROLOG
853 // This macro creates a V86 Trap entry prologue.
854 // It should be used for entry into any fast-system call (KiGetTickCount,
855 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
859 // Unique label identifying the name of the caller function; will be
860 // used to append to the name of the DR helper function, which must
865 .macro V86_TRAP_PROLOG Label EndLabel
867 /* Skip everything to the error code */
868 sub esp, KTRAP_FRAME_ERROR_CODE
870 /* Clear the error code */
871 mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
873 /* Save the registers we'll trample */
874 mov [esp+KTRAP_FRAME_EBX], ebx
875 mov [esp+KTRAP_FRAME_EAX], eax
876 mov [esp+KTRAP_FRAME_EBP], ebp
877 mov [esp+KTRAP_FRAME_ESI], esi
878 mov [esp+KTRAP_FRAME_EDI], edi
880 /* Save PCR and Ring 3 segments */
882 mov eax, KGDT_R3_DATA + RPL_MASK
884 /* Save ECX and EDX too */
885 mov [esp+KTRAP_FRAME_ECX], ecx
886 mov [esp+KTRAP_FRAME_EDX], edx
888 /* Set debugging markers */
889 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
890 mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
892 /* Now set segments (use OVERRIDE, 0x66) */
900 /* Set the trap frame in the stack and clear the direction flag */
904 /* Save the exception list */
905 mov eax, fs:[KPCR_EXCEPTION_LIST]
906 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
908 /* Check if we need debugging */
910 test eax, ~DR7_RESERVED_MASK
911 mov [esp+KTRAP_FRAME_DR7], eax
918 // @name V86_TRAP_EPILOG
920 // This macro creates an epilogue for leaving V86 traps
926 .macro V86_TRAP_EPILOG
928 /* Get the current thread and make it unalerted */
930 mov ebx, PCR[KPCR_CURRENT_THREAD]
931 mov byte ptr [ebx+KTHREAD_ALERTED], 0
933 /* Check if it has User-mode APCs pending */
934 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
937 /* It doesn't, pop the frame */
938 add esp, KTRAP_FRAME_EDX
943 /* Check if DR registers should be restored */
944 test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
947 /* Finish popping the rest of the frame, and return to P-mode */
961 mov esi, [ebp+KTRAP_FRAME_DR0]
962 mov edi, [ebp+KTRAP_FRAME_DR1]
967 /* Get DR2 and load DR0-2 */
968 mov ebx, [ebp+KTRAP_FRAME_DR2]
974 mov esi, [ebp+KTRAP_FRAME_DR0]
975 mov edi, [ebp+KTRAP_FRAME_DR1]
976 mov ebx, [ebp+KTRAP_FRAME_DR7]
986 /* Raise to APC level */
990 /* Save KIRQL and deliver APCs */
996 call _KiDeliverApc@12
1003 /* Check if we're not in V86 anymore */
1004 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1009 // @name TRAP_EPILOG
1011 // This macro creates an epilogue for leaving any system trap.
1012 // It is used for exiting system calls, exceptions, interrupts and generic
1015 // @param SystemCall
1016 // Specifies whether this trap will exit a system call. If so, special
1017 // code will be assembled to potentially use SYSEXIT instead of IRETD.
1019 // @param RestorePreviousMode
1020 // Specifies if the previous mode should be restored.
1022 // @param RestoreSegments
1023 // Specifies if the segment registers should be restored.
1025 // @param RestoreVolatiles
1026 // Specifies if the volatile registers should be restored.
1028 // @param RestoreAllRegs
1029 // Specifies if volatiles and segments should both be restored.
1033 .macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs
1035 /* Assert the flags */
1038 test edx, EFLAGS_INTERRUPT_MASK
1041 /* Assert the stack */
1045 /* Assert the trap frame */
1049 sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1057 /* Assert exception list */
1058 cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0
1067 /* Get exception list */
1068 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
1071 /* Assert the saved exception list */
1079 mov PCR[KPCR_EXCEPTION_LIST], edx
1081 .if \RestorePreviousMode
1082 /* Get previous mode */
1083 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1086 /* Assert the saved previous mode */
1093 /* Restore the previous mode */
1094 mov esi, PCR[KPCR_CURRENT_THREAD]
1095 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
1099 /* Assert the saved previous mode */
1100 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1108 /* Check for debug registers */
1109 test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1114 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1117 /* Check if the frame was edited */
1118 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
1122 /* Check the old mode */
1123 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1124 bt word ptr [esp+KTRAP_FRAME_CS], 0
1129 .if \RestoreVolatiles
1130 /* Restore volatiles */
1131 mov edx, [esp+KTRAP_FRAME_EDX]
1132 mov ecx, [esp+KTRAP_FRAME_ECX]
1133 mov eax, [esp+KTRAP_FRAME_EAX]
1136 /* Check if we were called from kernel mode */
1137 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1140 .if \RestoreSegments
1141 /* Restore segment registers */
1142 lea esp, [ebp+KTRAP_FRAME_GS]
1150 lea esp, [ebp+KTRAP_FRAME_FS]
1154 /* Skip debug information and unsaved registers */
1155 lea esp, [ebp+KTRAP_FRAME_EDI]
1161 /* Check for ABIOS */
1162 cmp word ptr [esp+8], 0x80
1165 /* Pop error code */
1169 /* Check if previous CS is from user-mode */
1170 test dword ptr [esp+4], 1
1172 /* It is, so use Fast Exit */
1175 /* Jump back to stub */
1187 /* Is SYSEXIT Supported/Wanted? */
1188 cmp dword ptr ss:[_KiFastSystemCallDisable], 0
1190 test dword ptr [esp+8], EFLAGS_TF
1193 /* Restore FS to TIB */
1194 mov ecx, KGDT_R3_TEB + RPL_MASK
1197 /* We will be cleaning up the stack ourselves */
1198 pop edx /* New Ring 3 EIP */
1199 add esp, 4 /* Skip Ring 3 DS */
1200 and dword ptr [esp], 0xfffffdff /* Remove EFLAGS_INTERRUPT_MASK from EFLAGS */
1201 popf /* Restore old EFLAGS */
1202 pop ecx /* Old Ring 3 SS:ESP */
1206 * ECX points to the old User Stack.
1207 * EDX points to the instruction to execute in usermode after the sysenter
1216 mov eax, [esp+KTRAP_FRAME_EAX]
1218 /* Skip registers */
1221 /* Restore segments and volatiles */
1228 /* Jump back to mainline code */
1234 /* Fix up the mask */
1235 add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1243 /* Check if this was V86 mode */
1244 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1247 /* Check if it was user mode */
1248 test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK
1257 mov esi, [ebp+KTRAP_FRAME_DR0]
1258 mov edi, [ebp+KTRAP_FRAME_DR1]
1259 mov ebx, [ebp+KTRAP_FRAME_DR2]
1267 mov esi, [ebp+KTRAP_FRAME_DR3]
1268 mov edi, [ebp+KTRAP_FRAME_DR6]
1269 mov ebx, [ebp+KTRAP_FRAME_DR7]
1278 /* Restore real CS value */
1279 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
1280 mov [esp+KTRAP_FRAME_CS], ebx
1283 * If ESP was modified, then a special interrupt exit stack
1284 * must be created to "update" ESP's value in a legal manner
1286 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
1288 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
1290 /* Copy Interrupt Stack */
1291 mov esi, [esp+KTRAP_FRAME_EFLAGS]
1293 mov esi, [esp+KTRAP_FRAME_CS]
1295 mov esi, [esp+KTRAP_FRAME_EIP]
1298 .if \RestoreVolatiles
1299 /* Restore volatiles */
1300 mov eax, [esp+KTRAP_FRAME_EAX]
1301 mov edx, [esp+KTRAP_FRAME_EDX]
1302 mov ecx, [esp+KTRAP_FRAME_ECX]
1306 add esp, KTRAP_FRAME_EDI
1318 // This macro creates an epilogue for leaving any system trap.
1319 // It is used for exiting system calls, exceptions, interrupts and generic
1322 // @param Spurious - TRUE if the interrupt was unexpected and spurious.
1326 .macro INT_EPILOG Spurious
1329 /* Just exit the trap */
1330 jmp _Kei386EoiHelper@0
1332 /* Disable interrupts */
1335 /* End the interrupt and do EOI */
1336 call _HalEndSystemInterrupt@8
1337 jmp _Kei386EoiHelper@0
1343 .macro VERIFY_INT Label
1344 /* Get the current time and mask it to 192 ticks */
1345 mov eax, _KeTickCount
1348 /* Check if we're in the same tick area */
1349 cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT]
1353 /* If we got here, then our count is too large */
1354 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT]
1359 .macro VERIFY_INT_END Label, Info
1362 /* Decrement the dispatch count and check if we should bug check */
1363 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2]
1366 /* Update the tick count */
1368 mov [edi+KINTERRUPT_TICK_COUNT], eax
1372 /* Check if the debugger is enabled */
1373 cmp byte ptr __KdDebuggerEnabled, 0
1376 /* It isn't, bugcheck */
1379 push [edi+KINTERRUPT_SERVICE_CONTEXT]
1380 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1381 push HARDWARE_INTERRUPT_STORM
1382 call _KeBugCheckEx@20
1385 /* Debugger enabled, do a debug print + break instead */
1386 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1387 push offset _IsrOverflowMsg
1392 /* Breakpoint handled, get the new tick count */
1393 mov eax, _KeTickCount
1397 /* Reset tick count */
1398 mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax
1399 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64
1402 /* Put default overflow count and continue */
1403 mov ax, _KiISROverflow
1404 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax
1408 /* Check if we wrapped */
1410 cmp eax, [edi+KINTERRUPT_TICK_COUNT]
1413 /* We did, start over */
1414 mov eax, _KeTickCount
1420 /* We don't verify interrupts on retail builds */
1421 .macro VERIFY_INT Label
1423 .macro VERIFY_INT_END Label, Info