Sync to trunk HEAD (r45072)
[reactos.git] / reactos / ntoskrnl / include / internal / i386 / asmmacro.S
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ndk/asm.h>
12
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
20 #define DoFixupV86 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
30
31 // Arguments for idt
32 #define INT_32_DPL0 0x8E00
33 #define INT_32_DPL3 0xEE00
34
35 //
36 // This table contains the prefix flags that are used by V86 emulation
37 //
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
49
50 .intel_syntax noprefix
51
52 //
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:
55 //
56 // .BeginYourFunction
57 // mov reg, lockaddr
58 // ACQUIRE_SPINLOCK(reg, .spin)
59 // <thread-safe code here>
60 // RELEASE_SPINLOCK(reg)
61 // <misc code here>
62 // retn
63 // #IFDEF CONFIG_SMP
64 // .spin
65 // <any necessary steps to be able to jump back safely>
66 / SPIN_ON_LOCK(reg, .BeginYourFunction)
67 // #ENDIF
68 //
69 #ifdef CONFIG_SMP
70 #define LOCK lock
71 #define ACQUIRE_SPINLOCK(x, y) \
72 lock bts dword ptr [x], 0; \
73 jb y
74 #define RELEASE_SPINLOCK(x) mov byte ptr [x], 0
75 #define SPIN_ON_LOCK(x, y) \
76 1: \
77 test dword ptr [x], 1; \
78 jz y; \
79 pause; \
80 jmp 1b
81 #else
82 #define LOCK
83 #define ACQUIRE_SPINLOCK(x, y)
84 #define RELEASE_SPINLOCK(x)
85 #endif
86
87 //
88 // @name UNHANDLED_PATH
89 //
90 // This macro prints out that the current code path is not expected yet
91 //
92 // @param None
93 //
94 // @remark None.
95 //
96 .macro UNHANDLED_PATH Reason
97
98 /* Push reason */
99 push offset 1f
100
101 /* Get EIP */
102 call $+5
103
104 /* Print debug message */
105 push offset _UnhandledMsg
106 call _DbgPrint
107 add esp, 12
108
109 /* Loop indefinitely */
110 jmp $
111
112 1:
113 .asciz \Reason
114 .endm
115
116 //
117 // @name UNHANDLED_V86_PATH
118 //
119 // This macro prints out that the current code path is for unhandled VDM support
120 //
121 // @param None
122 //
123 // @remark None.
124 //
125 .macro UNHANDLED_V86_PATH
126 /* Get EIP */
127 call $+5
128
129 /* Print debug message */
130 push offset _V86UnhandledMsg
131 call _DbgPrint
132 add esp, 8
133
134 /* Loop indefinitely */
135 jmp $
136 .endm
137
138 //
139 // @name IDT
140 //
141 // This macro creates an IDT entry for the given handler
142 //
143 // @param Handler
144 // Pointer to the IDT handler
145 //
146 // @param Bits
147 // Descriptor Bits to associate
148 //
149 // @remark None.
150 //
151 .macro idt Handler, Bits
152 .long \Handler
153 .short \Bits
154 .short KGDT_R0_CODE
155 .endm
156
157 //
158 // @name GENERATE_IDT_STUB
159 //
160 // This macro creates an IDT entry for an unexpected interrupt handler.
161 //
162 // @param None.
163 //
164 // @remark None.
165 //
166 .macro GENERATE_IDT_STUB Number
167 idt _KiUnexpectedInterrupt&Number, INT_32_DPL0
168 .endm
169
170 //
171 // @name GENERATE_IDT_STUBS
172 //
173 // This macro creates unexpected interrupt IDT entries.
174 //
175 // @param None.
176 //
177 // @remark None.
178 //
179 .altmacro
180 .macro GENERATE_IDT_STUBS
181 .set i, 0
182 .rept 208
183 GENERATE_IDT_STUB %i
184 .set i, i + 1
185 .endr
186 .endm
187
188 //
189 // @name GENERATE_INT_HANDLER
190 //
191 // This macro creates an unexpected interrupt handler.
192 //
193 // @param None.
194 //
195 // @remark None.
196 //
197 .macro GENERATE_INT_HANDLER Number
198 .func KiUnexpectedInterrupt&Number
199 _KiUnexpectedInterrupt&Number:
200 push PRIMARY_VECTOR_BASE + Number
201 jmp _KiEndUnexpectedRange@0
202 .endfunc
203 .endm
204
205 //
206 // @name GENERATE_INT_HANDLERS
207 //
208 // This macro creates the unexpected interrupt handlers.
209 //
210 // @param None.
211 //
212 // @remark None.
213 //
214 .altmacro
215 .macro GENERATE_INT_HANDLERS
216 .set i, 0
217 .rept 208
218 GENERATE_INT_HANDLER %i
219 .set i, i + 1
220 .endr
221 .endm
222
223 //
224 // @name GENERATE_TRAP_HANDLER
225 //
226 // This macro creates a kernel trap handler.
227 //
228 // @param None.
229 //
230 // @remark None.
231 //
232 .macro GENERATE_TRAP_HANDLER Name, ErrorCode=1, FastV86=0
233 .func Name
234 _&Name:
235 /* Some traps generate an error code, some don't (thanks, Intel!) */
236 .if \ErrorCode
237 push 0
238 .endif
239
240 /* Make space for trap frame and save registers before we enter C code */
241 sub esp, KTRAP_FRAME_ERROR_CODE
242 mov [esp+KTRAP_FRAME_EAX], eax
243 mov [esp+KTRAP_FRAME_EBX], ebx
244 mov [esp+KTRAP_FRAME_ECX], ecx
245 mov [esp+KTRAP_FRAME_EDX], edx
246 mov [esp+KTRAP_FRAME_ESI], esi
247 mov [esp+KTRAP_FRAME_EDI], edi
248 mov [esp+KTRAP_FRAME_EBP], ebp
249 mov ecx, esp
250
251 /*
252 * The GPF and Invalid Opcode handlers are performance critical when talking
253 * about V8086 traps, because they control the main flow of execution during
254 * that mode (GPFs will be issued for any privileged instruction we need to
255 * emulate, and invalid opcode might be generated for BOPs).
256 *
257 * Because of this, we employ a fast entry/exit macro into V8086 mode since
258 * we can make certain assumptions. We detect, and use, such scenarios when
259 * the V8086 flag is enabled in EFLAGS.
260 *
261 * However, because we can land in a GPF handler with an invalid DS/ES, as
262 * some V8086 code could trample this during BIOS calls for example, we must
263 * make sure that we are on a valid DS/ES before dereferencing any pointer.
264 *
265 * We fixup DS/ES either in KiEnterTrap (for normal entry/exit) or, for V86,
266 * in KiEnterV86Trap. Notice the problem: we need to detect which of these
267 * to use early on but we can't touch the EFLAGS in the frame because DS/ES
268 * could be invalid.
269 *
270 * Thankfully SS is always guaranteed valid, so stack dereferences are game!
271 *
272 * We therefore read the EFLAGS here, in assembly, where we can touch ESP as
273 * we please. We save this in EDX, which will be used as the second argument
274 * for the FASTCALL C trap entry.
275 *
276 * When we make the fast V86 check, we use the parameter instead of the trap
277 * frame, leading us to using the correct trap entry function, which fixes
278 * up DS/ES and lets us go on our merry way...
279 */
280 .if \FastV86
281 mov edx, [esp+KTRAP_FRAME_EFLAGS]
282 .endif
283
284 /* Normally we just have one parameter, but fast V86 handlers need two */
285 .if \FastV86
286 jmp @&Name&Handler@8
287 .else
288 jmp @&Name&Handler@4
289 .endif
290 .endfunc
291 .endm
292
293 //
294 // @name GENERATE_HAL_INT_HANDLER
295 //
296 // This macro creates a HAL hardware interrupt handler.
297 //
298 // @param None.
299 //
300 // @remark None.
301 //
302 .macro GENERATE_HAL_INT_HANDLER Number
303 .func HalpHardwareInterrupt&Number
304 _HalpHardwareInterrupt&Number:
305 int PRIMARY_VECTOR_BASE + Number
306 ret
307 .endfunc
308 .endm
309
310 //
311 // @name GENERATE_HAL_INT_HANDLERS
312 //
313 // This macro creates the unexpected interrupt handlers.
314 //
315 // @param None.
316 //
317 // @remark None.
318 //
319 .macro GENERATE_HAL_INT_HANDLERS
320 .set i, 0
321 .rept 16
322 GENERATE_HAL_INT_HANDLER %i
323 .set i, i + 1
324 .endr
325 .endm
326
327 //
328 // @name INVALID_V86_OPCODE
329 //
330 // This macro creates one or more entries for unhandled V86 Opcodes
331 // in the V86 Opcode Table.
332 //
333 // @param count.
334 // Number of entries to generate.
335 //
336 // @remark None.
337 //
338 .macro INVALID_V86_OPCODE count
339 .rept \count
340 .byte 0
341 .endr
342 .endm
343
344 //
345 // @name GENERATE_PREFIX_HANDLER
346 //
347 // This macro creates a prefix opcode handler.
348 //
349 // @param None.
350 //
351 // @remark None.
352 //
353 .macro GENERATE_PREFIX_HANDLER Name
354 .func Opcode&Name&PrefixV86
355 _Opcode&Name&PrefixV86:
356 or ebx, PREFIX_FLAG_&Name
357 jmp _OpcodeGenericPrefixV86
358 .endfunc
359 .endm
360
361 //
362 // @name INVALID_V86_OPCODE
363 //
364 // This macro prints out visible message and hangs the computer.
365 //
366 // @param None.
367 //
368 // @remark Temporary debugging use.
369 //
370 .macro UNHANDLED_V86_OPCODE
371 /* Print debug message, breakpoint and freeze */
372 push ecx
373 push offset V86DebugMsg
374 call _DbgPrint
375 add esp, 8
376 jmp $
377 .endm
378
379 //
380 // @name TRAP_FIXUPS
381 //
382 // This macro contains out-of-line code for various Trap Frame Fixups, such as:
383 //
384 // - DR Fixup: Loads and restores DR registers.
385 // - V86 Fixup: Loads and restores V86 segments.
386 // - ABIOS Fixup: Loads and restores the ABIOS state and stack.
387 //
388 // @param None.
389 //
390 // @remark ebp = PKTRAP_FRAME
391 //
392 .macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix
393 Dr_&Label:
394
395 /* Check if this was V86 mode */
396 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
397 jnz 2f
398
399 /* Check if it was user mode */
400 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
401 jz Dr_&EndLabel
402
403 2:
404 /* Get DR0, 1, 2 */
405 mov ebx, dr0
406 mov ecx, dr1
407 mov edi, dr2
408
409 /* Save them */
410 mov [ebp+KTRAP_FRAME_DR0], ebx
411 mov [ebp+KTRAP_FRAME_DR1], ecx
412 mov [ebp+KTRAP_FRAME_DR2], edi
413
414 /* Get DR3, 6, 7 */
415 mov ebx, dr3
416 mov ecx, dr6
417 mov edi, dr7
418
419 /* Save them */
420 mov [ebp+KTRAP_FRAME_DR3], ebx
421 mov [ebp+KTRAP_FRAME_DR6], ecx
422 mov [ebp+KTRAP_FRAME_DR7], edi
423
424 /* Clear DR7 */
425 xor ebx, ebx
426 mov dr7, ebx
427
428 /* Get the PRCB */
429 mov edi, fs:[KPCR_PRCB]
430
431 /* Get DR0, 1 */
432 mov ebx, [edi+KPRCB_DR0]
433 mov ecx, [edi+KPRCB_DR1]
434
435 /* Set them */
436 mov dr0, ebx
437 mov dr1, ecx
438
439 /* Get DR2, 3 */
440 mov ebx, [edi+KPRCB_DR2]
441 mov ecx, [edi+KPRCB_DR3]
442
443 /* Set them */
444 mov dr2, ebx
445 mov dr3, ecx
446
447 /* Get DR6, 7 */
448 mov ebx, [edi+KPRCB_DR6]
449 mov ecx, [edi+KPRCB_DR7]
450
451 /* Set them */
452 mov dr6, ebx
453 mov dr7, ecx
454 jmp Dr_&EndLabel
455
456 .if \AbiosFix
457 Abios_&Label:
458 UNHANDLED_PATH
459 .endif
460
461 .if \V86Fix
462 V86_&Label:
463
464 /* Get V86 segment registers */
465 mov eax, [ebp+KTRAP_FRAME_V86_FS]
466 mov ebx, [ebp+KTRAP_FRAME_V86_GS]
467 mov ecx, [ebp+KTRAP_FRAME_V86_ES]
468 mov edx, [ebp+KTRAP_FRAME_V86_DS]
469
470 /* Restore them into Protected Mode trap frame */
471 mov [ebp+KTRAP_FRAME_FS], ax
472 mov [ebp+KTRAP_FRAME_GS], bx
473 mov [ebp+KTRAP_FRAME_ES], cx
474 mov [ebp+KTRAP_FRAME_DS], dx
475
476 /* Go back to mainline code */
477 jmp V86_&EndLabel
478 .endif
479 .endm
480
481 //
482 // @name SET_TF_DEBUG_HEADER
483 //
484 // This macro sets up the debug header in the trap frame.
485 //
486 // @param None.
487 //
488 // @remark ebp = PKTRAP_FRAME.
489 // edi/ebx = Have been saved and can be used.
490 //
491 .macro SET_TF_DEBUG_HEADER
492 /* Get the Debug Trap Frame EBP/EIP */
493 mov ebx, [ebp+KTRAP_FRAME_EBP]
494 mov edi, [ebp+KTRAP_FRAME_EIP]
495
496 /* Write the debug data */
497 mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
498 mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
499 mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
500 mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
501 .endm
502
503 //
504 // @name CHECK_FOR_APC_DELIVER
505 //
506 // This macro checks if the trapframe indicates a return to user-mode,
507 // and, if so, checks if user-mode APCs should be delivered.
508 //
509 // @param PreserveEax
510 // Determines if EAX should be preserved. Implies that the segment
511 // registers will also be saved.
512 //
513 // @remark ebp = PKTRAP_FRAME.
514 // ebx = Saved and will be used.
515 //
516 .macro CHECK_FOR_APC_DELIVER PreserveEax
517 /* Check for V86 mode */
518 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
519 jnz 1f
520
521 /* Deliver APCs only if we were called from user mode */
522 test byte ptr [ebp+KTRAP_FRAME_CS], 1
523 je 2f
524
525 /* Get the current thread */
526 1:
527 mov ebx, PCR[KPCR_CURRENT_THREAD]
528
529 /* Make it non-alerted */
530 mov byte ptr [ebx+KTHREAD_ALERTED], 0
531
532 /* And only if any are actually pending */
533 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
534 je 2f
535
536 /* Save pointer to Trap Frame */
537 mov ebx, ebp
538
539 .if \PreserveEax
540 /* Save some stuff that raising IRQL will kill */
541 mov [ebx+KTRAP_FRAME_EAX], eax
542 mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK
543 mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
544 mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
545 mov dword ptr [ebx+KTRAP_FRAME_GS], 0
546 .endif
547
548 /* Raise IRQL to APC_LEVEL */
549 mov ecx, 1
550 call @KfRaiseIrql@4
551
552 /* Save old IRQL */
553 push eax
554
555 /* Deliver APCs */
556 sti
557 push ebx
558 push 0
559 push UserMode
560 call _KiDeliverApc@12
561
562 /* Return to old IRQL */
563 pop ecx
564 call @KfLowerIrql@4
565
566 /* Restore EAX (only in volatile case) */
567 .if \PreserveEax
568 mov eax, [ebx+KTRAP_FRAME_EAX]
569 .endif
570 cli
571 jmp 1b
572 2:
573 .endm
574
575 //
576 // @name TRAP_PROLOG
577 //
578 // This macro creates a standard trap entry prologue.
579 // It should be used for entry into any kernel trap (KiTrapXx), but not for
580 // system calls, which require special handling.
581 //
582 // @param Label
583 // Identifying name of the caller function; will be used to append
584 // to the name V86 and DR helper functions, which must already exist.
585 //
586 // @remark Use as follows:
587 // _KiTrap00:
588 // /* Push fake error code */
589 // push 0
590 //
591 // /* Enter common prologue */
592 // TRAP_PROLOG(0)
593 //
594 // /* Handle trap */
595 // <Your Trap Code Here>
596 //
597 .macro TRAP_PROLOG Label EndLabel
598 /* Just to be safe, clear out the HIWORD, since it's reserved */
599 mov word ptr [esp+2], 0
600
601 /* Save the non-volatiles */
602 push ebp
603 push ebx
604 push esi
605 push edi
606
607 /* Save FS and set it to PCR */
608 push fs
609 mov ebx, KGDT_R0_PCR
610 .byte 0x66
611 mov fs, bx
612
613 /* Save exception list and bogus previous mode */
614 push fs:[KPCR_EXCEPTION_LIST]
615 push -1
616
617 /* Save volatiles and segment registers */
618 push eax
619 push ecx
620 push edx
621 push ds
622 push es
623 push gs
624
625 /* Set the R3 data segment */
626 mov ax, KGDT_R3_DATA + RPL_MASK
627
628 /* Skip debug registers and debug stuff */
629 sub esp, 0x30
630
631 /* Load the segment registers */
632 .byte 0x66
633 mov ds, ax
634 .byte 0x66
635 mov es, ax
636
637 /* Check if this interrupt happened in 16-bit mode */
638 cmp esp, 0x10000
639 jb _Ki16BitStackException
640
641 /* Set up frame */
642 mov ebp, esp
643
644 /* Check if this was from V86 Mode */
645 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
646 jnz V86_&Label
647
648 V86_&EndLabel:
649 /* Get current thread */
650 mov ecx, fs:[KPCR_CURRENT_THREAD]
651 cld
652
653 /* Flush DR7 */
654 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
655
656 /* Check if the thread was being debugged */
657 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
658 jnz Dr_&Label
659
660 /* Set the Trap Frame Debug Header */
661 Dr_&EndLabel:
662 SET_TF_DEBUG_HEADER
663 .endm
664
665 //
666 // @name INT_PROLOG
667 //
668 // This macro creates a standard interrupt entry prologue.
669 // It should be used for entry into any interrupt, including software.
670 //
671 // @param Label
672 // Identifying name of the caller function; will be used to append
673 // to the name V86, ABIOS and DR helper functions, which must exist.
674 //
675 // @remark For software interrupts, make sure that a fake INT stack is created.
676 //
677 .macro INT_PROLOG Label EndLabel FakeErrorCode
678
679 .if \FakeErrorCode
680 /* Save fake error code */
681 push esp
682 .endif
683
684 /* Save the non-volatiles */
685 push ebp
686 push ebx
687 push esi
688 push edi
689
690 /* Skip debug registers and other stuff */
691 sub esp, 0x54
692
693 /* Set up frame */
694 mov ebp, esp
695
696 /* Save volatiles */
697 mov [esp+KTRAP_FRAME_EAX], eax
698 mov [esp+KTRAP_FRAME_ECX], ecx
699 mov [esp+KTRAP_FRAME_EDX], edx
700 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
701
702 /* Check if this was from V86 Mode */
703 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
704 jnz V86_&Label
705
706 /* Check if this was kernel mode */
707 V86_&EndLabel:
708 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE
709 jz 1f
710
711 /* Set segments */
712 mov word ptr [esp+KTRAP_FRAME_FS], fs
713 mov word ptr [esp+KTRAP_FRAME_DS], ds
714 mov word ptr [esp+KTRAP_FRAME_ES], es
715 mov [esp+KTRAP_FRAME_GS], gs
716
717 /* Load the segment registers (use OVERRIDE (0x66)) */
718 mov ebx, KGDT_R0_PCR
719 mov eax, KGDT_R3_DATA | RPL_MASK
720 .byte 0x66
721 mov fs, bx
722 .byte 0x66
723 mov ds, ax
724 .byte 0x66
725 mov es, ax
726
727 1:
728 /* Get the previous exception list */
729 mov ebx, fs:[KPCR_EXCEPTION_LIST]
730
731 /* Set the exception handler chain terminator */
732 mov dword ptr fs:[KPCR_EXCEPTION_LIST], -1
733
734 /* Save the previous exception list */
735 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx
736
737 .ifeq \FakeErrorCode
738 /* Setup the 16-bit stack */
739 lea eax, [esp+KTRAP_FRAME_ERROR_CODE]
740 lea ecx, [esp+KTRAP_FRAME_EIP]
741 mov ebx, ss:[eax]
742 mov ss:[eax], ecx
743 .endif
744
745 /* Check if this is the ABIOS stack */
746 /* cmp esp, 0x10000*/
747 /* jb Abios_Label*/
748
749 /* Delete error code */
750 and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0
751
752 /* Get the current thread and clear direction flag */
753 mov ecx, PCR[KPCR_CURRENT_THREAD]
754 cld
755
756 /* Flush DR7 */
757 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
758
759 /* Check if the thread was being debugged */
760 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
761
762 .ifeq \FakeErrorCode
763 /* Push parameter */
764 push ebx
765 .endif
766
767 /* Save DR registers if needed */
768 jnz Dr_&Label
769
770 /* Set the trap frame debug header */
771 Dr_&EndLabel:
772 SET_TF_DEBUG_HEADER
773 .endm
774
775 //
776 // @name SYSCALL_PROLOG
777 //
778 // This macro creates a system call entry prologue.
779 // It should be used for entry into any fast-system call (KiGetTickCount,
780 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
781 // (KiSystemService)
782 //
783 // @param Label
784 // Unique label identifying the name of the caller function; will be
785 // used to append to the name of the DR helper function, which must
786 // already exist.
787 //
788 // @remark None.
789 //
790 .macro SYSCALL_PROLOG Label EndLabel
791 /* Create a trap frame */
792 push 0
793 push ebp
794 push ebx
795 push esi
796 push edi
797 push fs
798
799 /* Load PCR Selector into fs */
800 mov ebx, KGDT_R0_PCR
801 .byte 0x66
802 mov fs, bx
803
804 /* Get a pointer to the current thread */
805 mov esi, PCR[KPCR_CURRENT_THREAD]
806
807 /* Save the previous exception list */
808 push PCR[KPCR_EXCEPTION_LIST]
809
810 /* Set the exception handler chain terminator */
811 mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
812
813 /* Save the old previous mode */
814 push [esi+KTHREAD_PREVIOUS_MODE]
815
816 /* Skip the other registers */
817 sub esp, 0x48
818
819 /* Set the new previous mode based on the saved CS selector */
820 mov ebx, [esp+0x6C]
821 and ebx, 1
822 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl
823
824 /* Go on the Kernel stack frame */
825 mov ebp, esp
826
827 /* Save the old trap frame pointer where EDX would be saved */
828 mov ebx, [esi+KTHREAD_TRAP_FRAME]
829 mov [ebp+KTRAP_FRAME_EDX], ebx
830
831 /* Flush DR7 */
832 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
833
834 /* Check if the thread was being debugged */
835 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
836
837 /* Set the thread's trap frame and clear direction flag */
838 mov [esi+KTHREAD_TRAP_FRAME], ebp
839 cld
840
841 /* Save DR registers if needed */
842 jnz Dr_&Label
843
844 /* Set the trap frame debug header */
845 Dr_&EndLabel:
846 SET_TF_DEBUG_HEADER
847
848 /* Enable interrupts */
849 sti
850 .endm
851
852 //
853 // @name FASTCALL_PROLOG
854 //
855 // TODO
856 //
857 // @param Label
858 // Unique label identifying the name of the caller function; will be
859 // used to append to the name of the DR helper function, which must
860 // already exist.
861 //
862 // @remark None.
863 //
864 .macro FASTCALL_PROLOG Label EndLabel
865
866 /* Set user selector */
867 mov ecx, KGDT_R3_DATA | RPL_MASK
868
869 /* Set FS to PCR */
870 push KGDT_R0_PCR
871 pop fs
872
873 /* Set DS/ES to User Selector */
874 mov ds, cx
875 mov es, cx
876
877 /* Set the current stack to Kernel Stack */
878 mov ecx, PCR[KPCR_TSS]
879 mov esp, [ecx+KTSS_ESP0]
880
881 /* Set up a fake INT Stack. */
882 push KGDT_R3_DATA + RPL_MASK
883 push edx /* Ring 3 SS:ESP */
884 pushf /* Ring 3 EFLAGS */
885 push 2 /* Ring 0 EFLAGS */
886 add edx, 8 /* Skip user parameter list */
887 popf /* Set our EFLAGS */
888 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
889 push KGDT_R3_CODE + RPL_MASK
890 push dword ptr ds:KUSER_SHARED_SYSCALL_RET
891
892 /* Setup the Trap Frame stack */
893 push 0
894 push ebp
895 push ebx
896 push esi
897 push edi
898 push KGDT_R3_TEB + RPL_MASK
899
900 /* Save pointer to our PCR */
901 mov ebx, PCR[KPCR_SELF]
902
903 /* Get a pointer to the current thread */
904 mov esi, [ebx+KPCR_CURRENT_THREAD]
905
906 /* Set the exception handler chain terminator */
907 push [ebx+KPCR_EXCEPTION_LIST]
908 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
909
910 /* Use the thread's stack */
911 mov ebp, [esi+KTHREAD_INITIAL_STACK]
912
913 /* Push previous mode */
914 push UserMode
915
916 /* Skip the other registers */
917 sub esp, 0x48
918
919 /* Make space for us on the stack */
920 sub ebp, 0x29C
921
922 /* Write the previous mode */
923 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
924
925 /* Sanity check */
926 cmp ebp, esp
927 jnz BadStack
928
929 /* Flush DR7 */
930 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
931
932 /* Check if the thread was being debugged */
933 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
934
935 /* Set the thread's trap frame */
936 mov [esi+KTHREAD_TRAP_FRAME], ebp
937
938 /* Save DR registers if needed */
939 jnz Dr_&Label
940
941 /* Set the trap frame debug header */
942 Dr_&EndLabel:
943 SET_TF_DEBUG_HEADER
944
945 /* Enable interrupts */
946 sti
947 .endm
948
949 //
950 // @name V86_TRAP_PROLOG
951 //
952 // This macro creates a V86 Trap entry prologue.
953 // It should be used for entry into any fast-system call (KiGetTickCount,
954 // KiCallbackReturn, KiRaiseAssertion) and the generic system call handler
955 // (KiSystemService)
956 //
957 // @param Label
958 // Unique label identifying the name of the caller function; will be
959 // used to append to the name of the DR helper function, which must
960 // already exist.
961 //
962 // @remark None.
963 //
964 .macro V86_TRAP_PROLOG Label EndLabel
965
966 /* Skip everything to the error code */
967 sub esp, KTRAP_FRAME_ERROR_CODE
968
969 /* Clear the error code */
970 mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
971
972 /* Save the registers we'll trample */
973 mov [esp+KTRAP_FRAME_EBX], ebx
974 mov [esp+KTRAP_FRAME_EAX], eax
975 mov [esp+KTRAP_FRAME_EBP], ebp
976 mov [esp+KTRAP_FRAME_ESI], esi
977 mov [esp+KTRAP_FRAME_EDI], edi
978
979 /* Save PCR and Ring 3 segments */
980 mov ebx, KGDT_R0_PCR
981 mov eax, KGDT_R3_DATA + RPL_MASK
982
983 /* Save ECX and EDX too */
984 mov [esp+KTRAP_FRAME_ECX], ecx
985 mov [esp+KTRAP_FRAME_EDX], edx
986
987 /* Set debugging markers */
988 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
989 mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
990
991 /* Now set segments (use OVERRIDE, 0x66) */
992 .byte 0x66
993 mov fs, bx
994 .byte 0x66
995 mov ds, ax
996 .byte 0x66
997 mov es, ax
998
999 /* Set the trap frame in the stack and clear the direction flag */
1000 mov ebp, esp
1001 cld
1002
1003 /* Save the exception list */
1004 mov eax, fs:[KPCR_EXCEPTION_LIST]
1005 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
1006
1007 /* Check if we need debugging */
1008 mov eax, dr7
1009 test eax, ~DR7_RESERVED_MASK
1010 mov [esp+KTRAP_FRAME_DR7], eax
1011 jnz Dr_&Label
1012
1013 Dr_&EndLabel:
1014 .endm
1015
1016 //
1017 // @name V86_TRAP_EPILOG
1018 //
1019 // This macro creates an epilogue for leaving V86 traps
1020 //
1021 // @param None.
1022 //
1023 // @remark None.
1024 //
1025 .macro V86_TRAP_EPILOG
1026
1027 /* Get the current thread and make it unalerted */
1028 ExitBegin:
1029 mov ebx, PCR[KPCR_CURRENT_THREAD]
1030 mov byte ptr [ebx+KTHREAD_ALERTED], 0
1031
1032 /* Check if it has User-mode APCs pending */
1033 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
1034 jne PendingUserApc
1035
1036 /* It doesn't, pop the frame */
1037 add esp, KTRAP_FRAME_EDX
1038 pop edx
1039 pop ecx
1040 pop eax
1041
1042 /* Check if DR registers should be restored */
1043 test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1044 jnz V86DebugRestore
1045
1046 /* Finish popping the rest of the frame, and return to P-mode */
1047 V86DebugContinue:
1048 add esp, 12
1049 pop edi
1050 pop esi
1051 pop ebx
1052 pop ebp
1053 add esp, 4
1054 iretd
1055
1056 V86DebugRestore:
1057
1058 /* Get DR0, 1 */
1059 xor ebx, ebx
1060 mov esi, [ebp+KTRAP_FRAME_DR0]
1061 mov edi, [ebp+KTRAP_FRAME_DR1]
1062
1063 /* Clear DR 7 */
1064 mov dr7, ebx
1065
1066 /* Get DR2 and load DR0-2 */
1067 mov ebx, [ebp+KTRAP_FRAME_DR2]
1068 mov dr0, esi
1069 mov dr1, edi
1070 mov dr2, ebx
1071
1072 /* Get DR3-7 */
1073 mov esi, [ebp+KTRAP_FRAME_DR0]
1074 mov edi, [ebp+KTRAP_FRAME_DR1]
1075 mov ebx, [ebp+KTRAP_FRAME_DR7]
1076
1077 /* Load them */
1078 mov dr3, esi
1079 mov dr6, edi
1080 mov dr7, ebx
1081 jmp V86DebugContinue
1082
1083 PendingUserApc:
1084
1085 /* Raise to APC level */
1086 mov ecx, APC_LEVEL
1087 call @KfRaiseIrql@4
1088
1089 /* Save KIRQL and deliver APCs */
1090 push eax
1091 sti
1092 push ebp
1093 push 0
1094 push UserMode
1095 call _KiDeliverApc@12
1096
1097 /* Restore IRQL */
1098 pop ecx
1099 call @KfLowerIrql@4
1100 cli
1101
1102 /* Check if we're not in V86 anymore */
1103 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1104 jnz ExitBegin
1105 .endm
1106
1107 //
1108 // @name TRAP_EPILOG
1109 //
1110 // This macro creates an epilogue for leaving any system trap.
1111 // It is used for exiting system calls, exceptions, interrupts and generic
1112 // traps.
1113 //
1114 // @param SystemCall
1115 // Specifies whether this trap will exit a system call. If so, special
1116 // code will be assembled to potentially use SYSEXIT instead of IRETD.
1117 //
1118 // @param RestorePreviousMode
1119 // Specifies if the previous mode should be restored.
1120 //
1121 // @param RestoreSegments
1122 // Specifies if the segment registers should be restored.
1123 //
1124 // @param RestoreVolatiles
1125 // Specifies if the volatile registers should be restored.
1126 //
1127 // @param RestoreAllRegs
1128 // Specifies if volatiles and segments should both be restored.
1129 //
1130 // @remark
1131 //
1132 .macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs
1133 #if DBG
1134 /* Assert the flags */
1135 pushfd
1136 pop edx
1137 test edx, EFLAGS_INTERRUPT_MASK
1138 jnz 6f
1139
1140 /* Assert the stack */
1141 cmp esp, ebp
1142 jnz 6f
1143
1144 /* Assert the trap frame */
1145 #endif
1146 5:
1147 #if DBG
1148 sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1149 jnz 0f
1150
1151 /* Assert FS */
1152 mov bx, fs
1153 cmp bx, KGDT_R0_PCR
1154 jnz 1f
1155
1156 /* Assert exception list */
1157 cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0
1158 jnz 2f
1159
1160 1:
1161 push -1
1162 call _KeBugCheck@4
1163 #endif
1164
1165 2:
1166 /* Get exception list */
1167 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
1168
1169 #if DBG
1170 /* Assert the saved exception list */
1171 or edx, edx
1172 jnz 1f
1173 UNHANDLED_PATH
1174 1:
1175 #endif
1176
1177 /* Restore it */
1178 mov PCR[KPCR_EXCEPTION_LIST], edx
1179
1180 .if \RestorePreviousMode
1181 /* Get previous mode */
1182 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1183
1184 #if DBG
1185 /* Assert the saved previous mode */
1186 cmp ecx, -1
1187 jnz 1f
1188 UNHANDLED_PATH
1189 1:
1190 #endif
1191
1192 /* Restore the previous mode */
1193 mov esi, PCR[KPCR_CURRENT_THREAD]
1194 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
1195 .else
1196
1197 #if DBG
1198 /* Assert the saved previous mode */
1199 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1200 cmp ecx, -1
1201 jz 1f
1202 UNHANDLED_PATH
1203 1:
1204 #endif
1205 .endif
1206
1207 /* Check for debug registers */
1208 test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1209 jnz 2f
1210
1211 /* Check for V86 */
1212 4:
1213 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1214 jnz V86_Exit
1215
1216 /* Check if the frame was edited */
1217 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
1218 jz 7f
1219
1220 .if \RestoreAllRegs
1221 /* Check the old mode */
1222 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1223 bt word ptr [esp+KTRAP_FRAME_CS], 0
1224 cmc
1225 ja 8f
1226 .endif
1227
1228 .if \RestoreVolatiles
1229 /* Restore volatiles */
1230 mov edx, [esp+KTRAP_FRAME_EDX]
1231 mov ecx, [esp+KTRAP_FRAME_ECX]
1232 mov eax, [esp+KTRAP_FRAME_EAX]
1233 .endif
1234
1235 /* Check if we were called from kernel mode */
1236 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1237 jz 9f
1238
1239 .if \RestoreSegments
1240 /* Restore segment registers */
1241 lea esp, [ebp+KTRAP_FRAME_GS]
1242 pop gs
1243 pop es
1244 pop ds
1245 .endif
1246
1247 /* Restore FS */
1248 3:
1249 lea esp, [ebp+KTRAP_FRAME_FS]
1250 pop fs
1251
1252 9:
1253 /* Skip debug information and unsaved registers */
1254 lea esp, [ebp+KTRAP_FRAME_EDI]
1255 pop edi
1256 pop esi
1257 pop ebx
1258 pop ebp
1259
1260 /* Check for ABIOS */
1261 cmp word ptr [esp+8], 0x80
1262 ja AbiosExit
1263
1264 /* Pop error code */
1265 add esp, 4
1266
1267 .if \SystemCall
1268 /* Check if previous CS is from user-mode */
1269 test dword ptr [esp+4], 1
1270
1271 /* It is, so use Fast Exit */
1272 jnz FastExit
1273
1274 /* Jump back to stub */
1275 pop edx
1276 pop ecx
1277 popf
1278 jmp edx
1279
1280 .ret:
1281 .endif
1282 iret
1283
1284 .if \SystemCall
1285 FastExit:
1286 /* Is SYSEXIT Supported/Wanted? */
1287 cmp dword ptr ss:[_KiFastSystemCallDisable], 0
1288 jnz .ret
1289 test dword ptr [esp+8], EFLAGS_TF
1290 jnz .ret
1291
1292 /* Restore FS to TIB */
1293 mov ecx, KGDT_R3_TEB + RPL_MASK
1294 mov fs, ecx
1295
1296 /* We will be cleaning up the stack ourselves */
1297 pop edx /* New Ring 3 EIP */
1298 add esp, 4 /* Skip Ring 3 DS */
1299 and dword ptr [esp], 0xfffffdff /* Remove EFLAGS_INTERRUPT_MASK from EFLAGS */
1300 popf /* Restore old EFLAGS */
1301 pop ecx /* Old Ring 3 SS:ESP */
1302
1303 /*
1304 * At this point:
1305 * ECX points to the old User Stack.
1306 * EDX points to the instruction to execute in usermode after the sysenter
1307 */
1308 sti
1309 sysexit
1310 .endif
1311
1312 .if \RestoreAllRegs
1313 8:
1314 /* Restore EAX */
1315 mov eax, [esp+KTRAP_FRAME_EAX]
1316
1317 /* Skip registers */
1318 add esp, 0x30
1319
1320 /* Restore segments and volatiles */
1321 pop gs
1322 pop es
1323 pop ds
1324 pop edx
1325 pop ecx
1326
1327 /* Jump back to mainline code */
1328 jmp 3b
1329 .endif
1330
1331 #if DBG
1332 0:
1333 /* Fix up the mask */
1334 add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1335
1336 6:
1337 UNHANDLED_PATH
1338 jmp 5b
1339 #endif
1340
1341 2:
1342 /* Check if this was V86 mode */
1343 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1344 jnz 1f
1345
1346 /* Check if it was user mode */
1347 test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK
1348 jz 4b
1349
1350 1:
1351 /* Clear DR7 */
1352 xor ebx, ebx
1353 mov dr7, ebx
1354
1355 /* Get DR0, 1, 2 */
1356 mov esi, [ebp+KTRAP_FRAME_DR0]
1357 mov edi, [ebp+KTRAP_FRAME_DR1]
1358 mov ebx, [ebp+KTRAP_FRAME_DR2]
1359
1360 /* Set them */
1361 mov dr0, esi
1362 mov dr1, edi
1363 mov dr2, ebx
1364
1365 /* Get DR3, 6, 7 */
1366 mov esi, [ebp+KTRAP_FRAME_DR3]
1367 mov edi, [ebp+KTRAP_FRAME_DR6]
1368 mov ebx, [ebp+KTRAP_FRAME_DR7]
1369
1370 /* Set them */
1371 mov dr3, esi
1372 mov dr6, edi
1373 mov dr7, ebx
1374 jmp 4b
1375
1376 7:
1377 /* Restore real CS value */
1378 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
1379 mov [esp+KTRAP_FRAME_CS], ebx
1380
1381 /*
1382 * If ESP was modified, then a special interrupt exit stack
1383 * must be created to "update" ESP's value in a legal manner
1384 */
1385 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
1386 sub ebx, 0xC
1387 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
1388
1389 /* Copy Interrupt Stack */
1390 mov esi, [esp+KTRAP_FRAME_EFLAGS]
1391 mov [ebx+8], esi
1392 mov esi, [esp+KTRAP_FRAME_CS]
1393 mov [ebx+4], esi
1394 mov esi, [esp+KTRAP_FRAME_EIP]
1395 mov [ebx], esi
1396
1397 .if \RestoreVolatiles
1398 /* Restore volatiles */
1399 mov eax, [esp+KTRAP_FRAME_EAX]
1400 mov edx, [esp+KTRAP_FRAME_EDX]
1401 mov ecx, [esp+KTRAP_FRAME_ECX]
1402 .endif
1403
1404 /* Return */
1405 add esp, KTRAP_FRAME_EDI
1406 pop edi
1407 pop esi
1408 pop ebx
1409 pop ebp
1410 mov esp, [esp]
1411 iret
1412 .endm
1413
1414 //
1415 // @name INT_EPILOG
1416 //
1417 // This macro creates an epilogue for leaving any system trap.
1418 // It is used for exiting system calls, exceptions, interrupts and generic
1419 // traps.
1420 //
1421 // @param Spurious - TRUE if the interrupt was unexpected and spurious.
1422 //
1423 // @remark None.
1424 //
1425 .macro INT_EPILOG Spurious
1426
1427 .if \Spurious
1428 /* Just exit the trap */
1429 jmp _Kei386EoiHelper@0
1430 .else
1431 /* Disable interrupts */
1432 cli
1433
1434 /* End the interrupt and do EOI */
1435 call _HalEndSystemInterrupt@8
1436 jmp _Kei386EoiHelper@0
1437 .endif
1438 .endm
1439
1440 #if DBG
1441
1442 .macro VERIFY_INT Label
1443 /* Get the current time and mask it to 192 ticks */
1444 mov eax, _KeTickCount
1445 and eax, 0xC0
1446
1447 /* Check if we're in the same tick area */
1448 cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT]
1449 jg VfRst_&Label
1450 jl VfWrap_&Label
1451
1452 /* If we got here, then our count is too large */
1453 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT]
1454 jz VfOvr_&Label
1455 Vf_&Label:
1456 .endm
1457
1458 .macro VERIFY_INT_END Label, Info
1459 VfOvr_&Label:
1460
1461 /* Decrement the dispatch count and check if we should bug check */
1462 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2]
1463 jz 1f
1464
1465 /* Update the tick count */
1466 add eax, 0x40
1467 mov [edi+KINTERRUPT_TICK_COUNT], eax
1468 jmp VfRstDef_&Label
1469
1470 1:
1471 /* Check if the debugger is enabled */
1472 cmp byte ptr __KdDebuggerEnabled, 0
1473 jnz 1f
1474
1475 /* It isn't, bugcheck */
1476 push Info
1477 push edi
1478 push [edi+KINTERRUPT_SERVICE_CONTEXT]
1479 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1480 push HARDWARE_INTERRUPT_STORM
1481 call _KeBugCheckEx@20
1482
1483 1:
1484 /* Debugger enabled, do a debug print + break instead */
1485 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1486 push offset _IsrOverflowMsg
1487 call _DbgPrint
1488 add esp, 8
1489 int 3
1490
1491 /* Breakpoint handled, get the new tick count */
1492 mov eax, _KeTickCount
1493 and eax, 0xC0
1494
1495 VfRst_&Label:
1496 /* Reset tick count */
1497 mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax
1498 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64
1499
1500 VfRstDef_&Label:
1501 /* Put default overflow count and continue */
1502 mov ax, _KiISROverflow
1503 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax
1504 jmp Vf_&Label
1505
1506 VfWrap_&Label:
1507 /* Check if we wrapped */
1508 add eax, 0x40
1509 cmp eax, [edi+KINTERRUPT_TICK_COUNT]
1510 je Vf_&Label
1511
1512 /* We did, start over */
1513 mov eax, _KeTickCount
1514 jmp VfRst_&Label
1515 .endm
1516
1517 #else
1518
1519 /* We don't verify interrupts on retail builds */
1520 .macro VERIFY_INT Label
1521 .endm
1522 .macro VERIFY_INT_END Label, Info
1523 .endm
1524
1525 #endif
1526
1527