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 TRAP_HANDLER_PROLOG
226 // This macro creates a kernel trap handler.
232 .macro TRAP_HANDLER_PROLOG ErrorCode=1, Software=0
234 /* What kind of trap is it */
236 /* Software traps need a fake interrupt stack */
238 sub esp, KTRAP_FRAME_ESP
240 /* Some traps generate an error code, some don't (thanks, Intel!) */
241 sub esp, KTRAP_FRAME_EIP
243 sub esp, KTRAP_FRAME_ERROR_CODE
246 /* Make space for trap frame and save registers before we enter C code */
247 mov [esp+KTRAP_FRAME_EAX], eax
248 mov [esp+KTRAP_FRAME_EBX], ebx
249 mov [esp+KTRAP_FRAME_ECX], ecx
250 mov [esp+KTRAP_FRAME_EDX], edx
251 mov [esp+KTRAP_FRAME_ESI], esi
252 mov [esp+KTRAP_FRAME_EDI], edi
253 mov [esp+KTRAP_FRAME_EBP], ebp
258 // @name GENERATE_TRAP_HANDLER
260 // This macro creates a kernel trap handler.
266 .macro GENERATE_TRAP_HANDLER Name, ErrorCode=1, FastV86=0, Software=0
270 TRAP_HANDLER_PROLOG ErrorCode, Software
272 * The GPF and Invalid Opcode handlers are performance critical when talking
273 * about V8086 traps, because they control the main flow of execution during
274 * that mode (GPFs will be issued for any privileged instruction we need to
275 * emulate, and invalid opcode might be generated for BOPs).
277 * Because of this, we employ a fast entry/exit macro into V8086 mode since
278 * we can make certain assumptions. We detect, and use, such scenarios when
279 * the V8086 flag is enabled in EFLAGS.
281 * However, because we can land in a GPF handler with an invalid DS/ES, as
282 * some V8086 code could trample this during BIOS calls for example, we must
283 * make sure that we are on a valid DS/ES before dereferencing any pointer.
285 * We fixup DS/ES either in KiEnterTrap (for normal entry/exit) or, for V86,
286 * in KiEnterV86Trap. Notice the problem: we need to detect which of these
287 * to use early on but we can't touch the EFLAGS in the frame because DS/ES
290 * Thankfully SS is always guaranteed valid, so stack dereferences are game!
292 * We therefore read the EFLAGS here, in assembly, where we can touch ESP as
293 * we please. We save this in EDX, which will be used as the second argument
294 * for the FASTCALL C trap entry.
296 * When we make the fast V86 check, we use the parameter instead of the trap
297 * frame, leading us to using the correct trap entry function, which fixes
298 * up DS/ES and lets us go on our merry way...
301 mov edx, [esp+KTRAP_FRAME_EFLAGS]
304 /* Normally we just have one parameter, but fast V86 handlers need two */
314 // @name GENERATE_HAL_INT_HANDLER
316 // This macro creates a HAL hardware interrupt handler.
322 .macro GENERATE_HAL_INT_HANDLER Number
323 .func HalpHardwareInterrupt&Number
324 _HalpHardwareInterrupt&Number:
325 int PRIMARY_VECTOR_BASE + Number
331 // @name GENERATE_HAL_INT_HANDLERS
333 // This macro creates the unexpected interrupt handlers.
339 .macro GENERATE_HAL_INT_HANDLERS
342 GENERATE_HAL_INT_HANDLER %i
348 // @name INVALID_V86_OPCODE
350 // This macro creates one or more entries for unhandled V86 Opcodes
351 // in the V86 Opcode Table.
354 // Number of entries to generate.
358 .macro INVALID_V86_OPCODE count
365 // @name GENERATE_PREFIX_HANDLER
367 // This macro creates a prefix opcode handler.
373 .macro GENERATE_PREFIX_HANDLER Name
374 .func Opcode&Name&PrefixV86
375 _Opcode&Name&PrefixV86:
376 or ebx, PREFIX_FLAG_&Name
377 jmp _OpcodeGenericPrefixV86
382 // @name INVALID_V86_OPCODE
384 // This macro prints out visible message and hangs the computer.
388 // @remark Temporary debugging use.
390 .macro UNHANDLED_V86_OPCODE
391 /* Print debug message, breakpoint and freeze */
393 push offset V86DebugMsg
402 // This macro contains out-of-line code for various Trap Frame Fixups, such as:
404 // - DR Fixup: Loads and restores DR registers.
405 // - V86 Fixup: Loads and restores V86 segments.
406 // - ABIOS Fixup: Loads and restores the ABIOS state and stack.
410 // @remark ebp = PKTRAP_FRAME
412 .macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix
415 /* Check if this was V86 mode */
416 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
419 /* Check if it was user mode */
420 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
430 mov [ebp+KTRAP_FRAME_DR0], ebx
431 mov [ebp+KTRAP_FRAME_DR1], ecx
432 mov [ebp+KTRAP_FRAME_DR2], edi
440 mov [ebp+KTRAP_FRAME_DR3], ebx
441 mov [ebp+KTRAP_FRAME_DR6], ecx
442 mov [ebp+KTRAP_FRAME_DR7], edi
449 mov edi, fs:[KPCR_PRCB]
452 mov ebx, [edi+KPRCB_DR0]
453 mov ecx, [edi+KPRCB_DR1]
460 mov ebx, [edi+KPRCB_DR2]
461 mov ecx, [edi+KPRCB_DR3]
468 mov ebx, [edi+KPRCB_DR6]
469 mov ecx, [edi+KPRCB_DR7]
484 /* Get V86 segment registers */
485 mov eax, [ebp+KTRAP_FRAME_V86_FS]
486 mov ebx, [ebp+KTRAP_FRAME_V86_GS]
487 mov ecx, [ebp+KTRAP_FRAME_V86_ES]
488 mov edx, [ebp+KTRAP_FRAME_V86_DS]
490 /* Restore them into Protected Mode trap frame */
491 mov [ebp+KTRAP_FRAME_FS], ax
492 mov [ebp+KTRAP_FRAME_GS], bx
493 mov [ebp+KTRAP_FRAME_ES], cx
494 mov [ebp+KTRAP_FRAME_DS], dx
496 /* Go back to mainline code */
502 // @name SET_TF_DEBUG_HEADER
504 // This macro sets up the debug header in the trap frame.
508 // @remark ebp = PKTRAP_FRAME.
509 // edi/ebx = Have been saved and can be used.
511 .macro SET_TF_DEBUG_HEADER
512 /* Get the Debug Trap Frame EBP/EIP */
513 mov ebx, [ebp+KTRAP_FRAME_EBP]
514 mov edi, [ebp+KTRAP_FRAME_EIP]
516 /* Write the debug data */
517 mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
518 mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
519 mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
520 mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
524 // @name CHECK_FOR_APC_DELIVER
526 // This macro checks if the trapframe indicates a return to user-mode,
527 // and, if so, checks if user-mode APCs should be delivered.
529 // @param PreserveEax
530 // Determines if EAX should be preserved. Implies that the segment
531 // registers will also be saved.
533 // @remark ebp = PKTRAP_FRAME.
534 // ebx = Saved and will be used.
536 .macro CHECK_FOR_APC_DELIVER PreserveEax
537 /* Check for V86 mode */
538 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
541 /* Deliver APCs only if we were called from user mode */
542 test byte ptr [ebp+KTRAP_FRAME_CS], 1
545 /* Get the current thread */
547 mov ebx, PCR[KPCR_CURRENT_THREAD]
549 /* Make it non-alerted */
550 mov byte ptr [ebx+KTHREAD_ALERTED], 0
552 /* And only if any are actually pending */
553 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
556 /* Save pointer to Trap Frame */
560 /* Save some stuff that raising IRQL will kill */
561 mov [ebx+KTRAP_FRAME_EAX], eax
562 mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK
563 mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
564 mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
565 mov dword ptr [ebx+KTRAP_FRAME_GS], 0
568 /* Raise IRQL to APC_LEVEL */
580 call _KiDeliverApc@12
582 /* Return to old IRQL */
586 /* Restore EAX (only in volatile case) */
588 mov eax, [ebx+KTRAP_FRAME_EAX]
598 // This macro creates a standard trap entry prologue.
599 // It should be used for entry into any kernel trap (KiTrapXx), but not for
600 // system calls, which require special handling.
603 // Identifying name of the caller function; will be used to append
604 // to the name V86 and DR helper functions, which must already exist.
606 // @remark Use as follows:
608 // /* Push fake error code */
611 // /* Enter common prologue */
615 // <Your Trap Code Here>
617 .macro TRAP_PROLOG Label EndLabel
618 /* Just to be safe, clear out the HIWORD, since it's reserved */
619 mov word ptr [esp+2], 0
621 /* Save the non-volatiles */
627 /* Save FS and set it to PCR */
633 /* Save exception list and bogus previous mode */
634 push fs:[KPCR_EXCEPTION_LIST]
637 /* Save volatiles and segment registers */
645 /* Set the R3 data segment */
646 mov ax, KGDT_R3_DATA + RPL_MASK
648 /* Skip debug registers and debug stuff */
651 /* Load the segment registers */
657 /* Check if this interrupt happened in 16-bit mode */
659 jb _Ki16BitStackException
664 /* Check if this was from V86 Mode */
665 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
669 /* Get current thread */
670 mov ecx, fs:[KPCR_CURRENT_THREAD]
674 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
676 /* Check if the thread was being debugged */
677 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
680 /* Set the Trap Frame Debug Header */
688 // This macro creates a standard interrupt entry prologue.
689 // It should be used for entry into any interrupt, including software.
692 // Identifying name of the caller function; will be used to append
693 // to the name V86, ABIOS and DR helper functions, which must exist.
695 // @remark For software interrupts, make sure that a fake INT stack is created.
697 .macro INT_PROLOG Label EndLabel FakeErrorCode
700 /* Save fake error code */
704 /* Save the non-volatiles */
710 /* Skip debug registers and other stuff */
717 mov [esp+KTRAP_FRAME_EAX], eax
718 mov [esp+KTRAP_FRAME_ECX], ecx
719 mov [esp+KTRAP_FRAME_EDX], edx
720 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
722 /* Check if this was from V86 Mode */
723 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
726 /* Check if this was kernel mode */
728 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE
732 mov word ptr [esp+KTRAP_FRAME_FS], fs
733 mov word ptr [esp+KTRAP_FRAME_DS], ds
734 mov word ptr [esp+KTRAP_FRAME_ES], es
735 mov [esp+KTRAP_FRAME_GS], gs
737 /* Load the segment registers (use OVERRIDE (0x66)) */
739 mov eax, KGDT_R3_DATA | RPL_MASK
748 /* Get the previous exception list */
749 mov ebx, fs:[KPCR_EXCEPTION_LIST]
751 /* Set the exception handler chain terminator */
752 mov dword ptr fs:[KPCR_EXCEPTION_LIST], -1
754 /* Save the previous exception list */
755 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx
758 /* Setup the 16-bit stack */
759 lea eax, [esp+KTRAP_FRAME_ERROR_CODE]
760 lea ecx, [esp+KTRAP_FRAME_EIP]
765 /* Check if this is the ABIOS stack */
766 /* cmp esp, 0x10000*/
769 /* Delete error code */
770 and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0
772 /* Get the current thread and clear direction flag */
773 mov ecx, PCR[KPCR_CURRENT_THREAD]
777 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
779 /* Check if the thread was being debugged */
780 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
787 /* Save DR registers if needed */
790 /* Set the trap frame debug header */
796 // @name SYSCALL_PROLOG
798 // This macro creates a system call entry prologue.
799 // It should be used for entry into any fast-system call (KiGetTickCount,
800 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
804 // Unique label identifying the name of the caller function; will be
805 // used to append to the name of the DR helper function, which must
810 .macro SYSCALL_PROLOG Label EndLabel
811 /* Create a trap frame */
819 /* Load PCR Selector into fs */
824 /* Get a pointer to the current thread */
825 mov esi, PCR[KPCR_CURRENT_THREAD]
827 /* Save the previous exception list */
828 push PCR[KPCR_EXCEPTION_LIST]
830 /* Set the exception handler chain terminator */
831 mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
833 /* Save the old previous mode */
834 push [esi+KTHREAD_PREVIOUS_MODE]
836 /* Skip the other registers */
839 /* Set the new previous mode based on the saved CS selector */
842 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl
844 /* Go on the Kernel stack frame */
847 /* Save the old trap frame pointer where EDX would be saved */
848 mov ebx, [esi+KTHREAD_TRAP_FRAME]
849 mov [ebp+KTRAP_FRAME_EDX], ebx
852 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
854 /* Check if the thread was being debugged */
855 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
857 /* Set the thread's trap frame and clear direction flag */
858 mov [esi+KTHREAD_TRAP_FRAME], ebp
861 /* Save DR registers if needed */
864 /* Set the trap frame debug header */
868 /* Enable interrupts */
873 // @name FASTCALL_PROLOG
878 // Unique label identifying the name of the caller function; will be
879 // used to append to the name of the DR helper function, which must
884 .macro FASTCALL_PROLOG Label EndLabel
886 /* Set user selector */
887 mov ecx, KGDT_R3_DATA | RPL_MASK
893 /* Set DS/ES to User Selector */
897 /* Set the current stack to Kernel Stack */
898 mov ecx, PCR[KPCR_TSS]
899 mov esp, [ecx+KTSS_ESP0]
901 /* Set up a fake INT Stack. */
902 push KGDT_R3_DATA + RPL_MASK
903 push edx /* Ring 3 SS:ESP */
904 pushf /* Ring 3 EFLAGS */
905 push 2 /* Ring 0 EFLAGS */
906 add edx, 8 /* Skip user parameter list */
907 popf /* Set our EFLAGS */
908 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
909 push KGDT_R3_CODE + RPL_MASK
910 push dword ptr ds:KUSER_SHARED_SYSCALL_RET
912 /* Setup the Trap Frame stack */
918 push KGDT_R3_TEB + RPL_MASK
920 /* Save pointer to our PCR */
921 mov ebx, PCR[KPCR_SELF]
923 /* Get a pointer to the current thread */
924 mov esi, [ebx+KPCR_CURRENT_THREAD]
926 /* Set the exception handler chain terminator */
927 push [ebx+KPCR_EXCEPTION_LIST]
928 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
930 /* Use the thread's stack */
931 mov ebp, [esi+KTHREAD_INITIAL_STACK]
933 /* Push previous mode */
936 /* Skip the other registers */
939 /* Make space for us on the stack */
942 /* Write the previous mode */
943 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
950 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
952 /* Check if the thread was being debugged */
953 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
955 /* Set the thread's trap frame */
956 mov [esi+KTHREAD_TRAP_FRAME], ebp
958 /* Save DR registers if needed */
961 /* Set the trap frame debug header */
965 /* Enable interrupts */
970 // @name V86_TRAP_PROLOG
972 // This macro creates a V86 Trap entry prologue.
973 // It should be used for entry into any fast-system call (KiGetTickCount,
974 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
978 // Unique label identifying the name of the caller function; will be
979 // used to append to the name of the DR helper function, which must
984 .macro V86_TRAP_PROLOG Label EndLabel
986 /* Skip everything to the error code */
987 sub esp, KTRAP_FRAME_ERROR_CODE
989 /* Clear the error code */
990 mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
992 /* Save the registers we'll trample */
993 mov [esp+KTRAP_FRAME_EBX], ebx
994 mov [esp+KTRAP_FRAME_EAX], eax
995 mov [esp+KTRAP_FRAME_EBP], ebp
996 mov [esp+KTRAP_FRAME_ESI], esi
997 mov [esp+KTRAP_FRAME_EDI], edi
999 /* Save PCR and Ring 3 segments */
1000 mov ebx, KGDT_R0_PCR
1001 mov eax, KGDT_R3_DATA + RPL_MASK
1003 /* Save ECX and EDX too */
1004 mov [esp+KTRAP_FRAME_ECX], ecx
1005 mov [esp+KTRAP_FRAME_EDX], edx
1007 /* Set debugging markers */
1008 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
1009 mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1011 /* Now set segments (use OVERRIDE, 0x66) */
1019 /* Set the trap frame in the stack and clear the direction flag */
1023 /* Save the exception list */
1024 mov eax, fs:[KPCR_EXCEPTION_LIST]
1025 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
1027 /* Check if we need debugging */
1029 test eax, ~DR7_RESERVED_MASK
1030 mov [esp+KTRAP_FRAME_DR7], eax
1037 // @name V86_TRAP_EPILOG
1039 // This macro creates an epilogue for leaving V86 traps
1045 .macro V86_TRAP_EPILOG
1047 /* Get the current thread and make it unalerted */
1049 mov ebx, PCR[KPCR_CURRENT_THREAD]
1050 mov byte ptr [ebx+KTHREAD_ALERTED], 0
1052 /* Check if it has User-mode APCs pending */
1053 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
1056 /* It doesn't, pop the frame */
1057 add esp, KTRAP_FRAME_EDX
1062 /* Check if DR registers should be restored */
1063 test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1066 /* Finish popping the rest of the frame, and return to P-mode */
1080 mov esi, [ebp+KTRAP_FRAME_DR0]
1081 mov edi, [ebp+KTRAP_FRAME_DR1]
1086 /* Get DR2 and load DR0-2 */
1087 mov ebx, [ebp+KTRAP_FRAME_DR2]
1093 mov esi, [ebp+KTRAP_FRAME_DR0]
1094 mov edi, [ebp+KTRAP_FRAME_DR1]
1095 mov ebx, [ebp+KTRAP_FRAME_DR7]
1101 jmp V86DebugContinue
1105 /* Raise to APC level */
1109 /* Save KIRQL and deliver APCs */
1115 call _KiDeliverApc@12
1122 /* Check if we're not in V86 anymore */
1123 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1128 // @name TRAP_EPILOG
1130 // This macro creates an epilogue for leaving any system trap.
1131 // It is used for exiting system calls, exceptions, interrupts and generic
1134 // @param SystemCall
1135 // Specifies whether this trap will exit a system call. If so, special
1136 // code will be assembled to potentially use SYSEXIT instead of IRETD.
1138 // @param RestorePreviousMode
1139 // Specifies if the previous mode should be restored.
1141 // @param RestoreSegments
1142 // Specifies if the segment registers should be restored.
1144 // @param RestoreVolatiles
1145 // Specifies if the volatile registers should be restored.
1147 // @param RestoreAllRegs
1148 // Specifies if volatiles and segments should both be restored.
1152 .macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs
1154 /* Assert the flags */
1157 test edx, EFLAGS_INTERRUPT_MASK
1160 /* Assert the stack */
1164 /* Assert the trap frame */
1168 sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1176 /* Assert exception list */
1177 cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0
1186 /* Get exception list */
1187 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
1190 /* Assert the saved exception list */
1198 mov PCR[KPCR_EXCEPTION_LIST], edx
1200 .if \RestorePreviousMode
1201 /* Get previous mode */
1202 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1205 /* Assert the saved previous mode */
1212 /* Restore the previous mode */
1213 mov esi, PCR[KPCR_CURRENT_THREAD]
1214 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
1218 /* Assert the saved previous mode */
1219 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1227 /* Check for debug registers */
1228 test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1233 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1236 /* Check if the frame was edited */
1237 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
1241 /* Check the old mode */
1242 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1243 bt word ptr [esp+KTRAP_FRAME_CS], 0
1248 .if \RestoreVolatiles
1249 /* Restore volatiles */
1250 mov edx, [esp+KTRAP_FRAME_EDX]
1251 mov ecx, [esp+KTRAP_FRAME_ECX]
1252 mov eax, [esp+KTRAP_FRAME_EAX]
1255 /* Check if we were called from kernel mode */
1256 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1259 .if \RestoreSegments
1260 /* Restore segment registers */
1261 lea esp, [ebp+KTRAP_FRAME_GS]
1269 lea esp, [ebp+KTRAP_FRAME_FS]
1273 /* Skip debug information and unsaved registers */
1274 lea esp, [ebp+KTRAP_FRAME_EDI]
1280 /* Check for ABIOS */
1281 cmp word ptr [esp+8], 0x80
1284 /* Pop error code */
1288 /* Check if previous CS is from user-mode */
1289 test dword ptr [esp+4], 1
1291 /* It is, so use Fast Exit */
1294 /* Jump back to stub */
1306 /* Is SYSEXIT Supported/Wanted? */
1307 cmp dword ptr ss:[_KiFastSystemCallDisable], 0
1309 test dword ptr [esp+8], EFLAGS_TF
1312 /* Restore FS to TIB */
1313 mov ecx, KGDT_R3_TEB + RPL_MASK
1316 /* We will be cleaning up the stack ourselves */
1317 pop edx /* New Ring 3 EIP */
1318 add esp, 4 /* Skip Ring 3 DS */
1319 and dword ptr [esp], 0xfffffdff /* Remove EFLAGS_INTERRUPT_MASK from EFLAGS */
1320 popf /* Restore old EFLAGS */
1321 pop ecx /* Old Ring 3 SS:ESP */
1325 * ECX points to the old User Stack.
1326 * EDX points to the instruction to execute in usermode after the sysenter
1335 mov eax, [esp+KTRAP_FRAME_EAX]
1337 /* Skip registers */
1340 /* Restore segments and volatiles */
1347 /* Jump back to mainline code */
1353 /* Fix up the mask */
1354 add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1362 /* Check if this was V86 mode */
1363 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1366 /* Check if it was user mode */
1367 test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK
1376 mov esi, [ebp+KTRAP_FRAME_DR0]
1377 mov edi, [ebp+KTRAP_FRAME_DR1]
1378 mov ebx, [ebp+KTRAP_FRAME_DR2]
1386 mov esi, [ebp+KTRAP_FRAME_DR3]
1387 mov edi, [ebp+KTRAP_FRAME_DR6]
1388 mov ebx, [ebp+KTRAP_FRAME_DR7]
1397 /* Restore real CS value */
1398 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
1399 mov [esp+KTRAP_FRAME_CS], ebx
1402 * If ESP was modified, then a special interrupt exit stack
1403 * must be created to "update" ESP's value in a legal manner
1405 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
1407 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
1409 /* Copy Interrupt Stack */
1410 mov esi, [esp+KTRAP_FRAME_EFLAGS]
1412 mov esi, [esp+KTRAP_FRAME_CS]
1414 mov esi, [esp+KTRAP_FRAME_EIP]
1417 .if \RestoreVolatiles
1418 /* Restore volatiles */
1419 mov eax, [esp+KTRAP_FRAME_EAX]
1420 mov edx, [esp+KTRAP_FRAME_EDX]
1421 mov ecx, [esp+KTRAP_FRAME_ECX]
1425 add esp, KTRAP_FRAME_EDI
1437 // This macro creates an epilogue for leaving any system trap.
1438 // It is used for exiting system calls, exceptions, interrupts and generic
1441 // @param Spurious - TRUE if the interrupt was unexpected and spurious.
1445 .macro INT_EPILOG Spurious
1448 /* Just exit the trap */
1449 jmp _Kei386EoiHelper@0
1451 /* Disable interrupts */
1454 /* End the interrupt and do EOI */
1456 mov PCR[KPCR_VDM_ALERT], eax
1457 call _HalEndSystemInterrupt@8
1458 jmp _Kei386EoiHelper@0
1464 .macro VERIFY_INT Label
1465 /* Get the current time and mask it to 192 ticks */
1466 mov eax, _KeTickCount
1469 /* Check if we're in the same tick area */
1470 cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT]
1474 /* If we got here, then our count is too large */
1475 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT]
1480 .macro VERIFY_INT_END Label, Info
1483 /* Decrement the dispatch count and check if we should bug check */
1484 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2]
1487 /* Update the tick count */
1489 mov [edi+KINTERRUPT_TICK_COUNT], eax
1493 /* Check if the debugger is enabled */
1494 cmp byte ptr __KdDebuggerEnabled, 0
1497 /* It isn't, bugcheck */
1500 push [edi+KINTERRUPT_SERVICE_CONTEXT]
1501 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1502 push HARDWARE_INTERRUPT_STORM
1503 call _KeBugCheckEx@20
1506 /* Debugger enabled, do a debug print + break instead */
1507 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1508 push offset _IsrOverflowMsg
1513 /* Breakpoint handled, get the new tick count */
1514 mov eax, _KeTickCount
1518 /* Reset tick count */
1519 mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax
1520 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64
1523 /* Put default overflow count and continue */
1524 mov ax, _KiISROverflow
1525 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax
1529 /* Check if we wrapped */
1531 cmp eax, [edi+KINTERRUPT_TICK_COUNT]
1534 /* We did, start over */
1535 mov eax, _KeTickCount
1541 /* We don't verify interrupts on retail builds */
1542 .macro VERIFY_INT Label
1544 .macro VERIFY_INT_END Label, Info