[PERF]: Optimize nested interrupt cases (where a pending interrupt exists at the...
[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 TRAP_HANDLER_PROLOG
225 //
226 // This macro creates a kernel trap handler.
227 //
228 // @param None.
229 //
230 // @remark None.
231 //
232 .macro TRAP_HANDLER_PROLOG ErrorCode=1, Software=0
233
234 /* What kind of trap is it */
235 .if \Software
236 /* Software traps need a fake interrupt stack */
237 pop eax
238 sub esp, KTRAP_FRAME_ESP
239 .elseif \ErrorCode
240 /* Some traps generate an error code, some don't (thanks, Intel!) */
241 sub esp, KTRAP_FRAME_EIP
242 .else
243 sub esp, KTRAP_FRAME_ERROR_CODE
244 .endif
245
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
254 mov ecx, esp
255 .endm
256
257 //
258 // @name GENERATE_TRAP_HANDLER
259 //
260 // This macro creates a kernel trap handler.
261 //
262 // @param None.
263 //
264 // @remark None.
265 //
266 .macro GENERATE_TRAP_HANDLER Name, ErrorCode=1, FastV86=0, Software=0
267 .globl _&Name
268 .func Name
269 _&Name:
270 TRAP_HANDLER_PROLOG ErrorCode, Software
271 /*
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).
276 *
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.
280 *
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.
284 *
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
288 * could be invalid.
289 *
290 * Thankfully SS is always guaranteed valid, so stack dereferences are game!
291 *
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.
295 *
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...
299 */
300 .if \FastV86
301 mov edx, [esp+KTRAP_FRAME_EFLAGS]
302 .endif
303
304 /* Normally we just have one parameter, but fast V86 handlers need two */
305 .if \FastV86
306 jmp @&Name&Handler@8
307 .else
308 jmp @&Name&Handler@4
309 .endif
310 .endfunc
311 .endm
312
313 //
314 // @name GENERATE_HAL_INT_HANDLER
315 //
316 // This macro creates a HAL hardware interrupt handler.
317 //
318 // @param None.
319 //
320 // @remark None.
321 //
322 .macro GENERATE_HAL_INT_HANDLER Number
323 .func HalpHardwareInterrupt&Number
324 _HalpHardwareInterrupt&Number:
325 int PRIMARY_VECTOR_BASE + Number
326 ret
327 .endfunc
328 .endm
329
330 //
331 // @name GENERATE_HAL_INT_HANDLERS
332 //
333 // This macro creates the unexpected interrupt handlers.
334 //
335 // @param None.
336 //
337 // @remark None.
338 //
339 .macro GENERATE_HAL_INT_HANDLERS
340 .set i, 0
341 .rept 16
342 GENERATE_HAL_INT_HANDLER %i
343 .set i, i + 1
344 .endr
345 .endm
346
347 //
348 // @name INVALID_V86_OPCODE
349 //
350 // This macro creates one or more entries for unhandled V86 Opcodes
351 // in the V86 Opcode Table.
352 //
353 // @param count.
354 // Number of entries to generate.
355 //
356 // @remark None.
357 //
358 .macro INVALID_V86_OPCODE count
359 .rept \count
360 .byte 0
361 .endr
362 .endm
363
364 //
365 // @name GENERATE_PREFIX_HANDLER
366 //
367 // This macro creates a prefix opcode handler.
368 //
369 // @param None.
370 //
371 // @remark None.
372 //
373 .macro GENERATE_PREFIX_HANDLER Name
374 .func Opcode&Name&PrefixV86
375 _Opcode&Name&PrefixV86:
376 or ebx, PREFIX_FLAG_&Name
377 jmp _OpcodeGenericPrefixV86
378 .endfunc
379 .endm
380
381 //
382 // @name INVALID_V86_OPCODE
383 //
384 // This macro prints out visible message and hangs the computer.
385 //
386 // @param None.
387 //
388 // @remark Temporary debugging use.
389 //
390 .macro UNHANDLED_V86_OPCODE
391 /* Print debug message, breakpoint and freeze */
392 push ecx
393 push offset V86DebugMsg
394 call _DbgPrint
395 add esp, 8
396 jmp $
397 .endm
398
399 //
400 // @name TRAP_FIXUPS
401 //
402 // This macro contains out-of-line code for various Trap Frame Fixups, such as:
403 //
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.
407 //
408 // @param None.
409 //
410 // @remark ebp = PKTRAP_FRAME
411 //
412 .macro TRAP_FIXUPS Label, EndLabel, V86Fix, AbiosFix
413 Dr_&Label:
414
415 /* Check if this was V86 mode */
416 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
417 jnz 2f
418
419 /* Check if it was user mode */
420 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
421 jz Dr_&EndLabel
422
423 2:
424 /* Get DR0, 1, 2 */
425 mov ebx, dr0
426 mov ecx, dr1
427 mov edi, dr2
428
429 /* Save them */
430 mov [ebp+KTRAP_FRAME_DR0], ebx
431 mov [ebp+KTRAP_FRAME_DR1], ecx
432 mov [ebp+KTRAP_FRAME_DR2], edi
433
434 /* Get DR3, 6, 7 */
435 mov ebx, dr3
436 mov ecx, dr6
437 mov edi, dr7
438
439 /* Save them */
440 mov [ebp+KTRAP_FRAME_DR3], ebx
441 mov [ebp+KTRAP_FRAME_DR6], ecx
442 mov [ebp+KTRAP_FRAME_DR7], edi
443
444 /* Clear DR7 */
445 xor ebx, ebx
446 mov dr7, ebx
447
448 /* Get the PRCB */
449 mov edi, fs:[KPCR_PRCB]
450
451 /* Get DR0, 1 */
452 mov ebx, [edi+KPRCB_DR0]
453 mov ecx, [edi+KPRCB_DR1]
454
455 /* Set them */
456 mov dr0, ebx
457 mov dr1, ecx
458
459 /* Get DR2, 3 */
460 mov ebx, [edi+KPRCB_DR2]
461 mov ecx, [edi+KPRCB_DR3]
462
463 /* Set them */
464 mov dr2, ebx
465 mov dr3, ecx
466
467 /* Get DR6, 7 */
468 mov ebx, [edi+KPRCB_DR6]
469 mov ecx, [edi+KPRCB_DR7]
470
471 /* Set them */
472 mov dr6, ebx
473 mov dr7, ecx
474 jmp Dr_&EndLabel
475
476 .if \AbiosFix
477 Abios_&Label:
478 UNHANDLED_PATH
479 .endif
480
481 .if \V86Fix
482 V86_&Label:
483
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]
489
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
495
496 /* Go back to mainline code */
497 jmp V86_&EndLabel
498 .endif
499 .endm
500
501 //
502 // @name SET_TF_DEBUG_HEADER
503 //
504 // This macro sets up the debug header in the trap frame.
505 //
506 // @param None.
507 //
508 // @remark ebp = PKTRAP_FRAME.
509 // edi/ebx = Have been saved and can be used.
510 //
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]
515
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
521 .endm
522
523 //
524 // @name CHECK_FOR_APC_DELIVER
525 //
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.
528 //
529 // @param PreserveEax
530 // Determines if EAX should be preserved. Implies that the segment
531 // registers will also be saved.
532 //
533 // @remark ebp = PKTRAP_FRAME.
534 // ebx = Saved and will be used.
535 //
536 .macro CHECK_FOR_APC_DELIVER PreserveEax
537 /* Check for V86 mode */
538 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
539 jnz 1f
540
541 /* Deliver APCs only if we were called from user mode */
542 test byte ptr [ebp+KTRAP_FRAME_CS], 1
543 je 2f
544
545 /* Get the current thread */
546 1:
547 mov ebx, PCR[KPCR_CURRENT_THREAD]
548
549 /* Make it non-alerted */
550 mov byte ptr [ebx+KTHREAD_ALERTED], 0
551
552 /* And only if any are actually pending */
553 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
554 je 2f
555
556 /* Save pointer to Trap Frame */
557 mov ebx, ebp
558
559 .if \PreserveEax
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
566 .endif
567
568 /* Raise IRQL to APC_LEVEL */
569 mov ecx, 1
570 call @KfRaiseIrql@4
571
572 /* Save old IRQL */
573 push eax
574
575 /* Deliver APCs */
576 sti
577 push ebx
578 push 0
579 push UserMode
580 call _KiDeliverApc@12
581
582 /* Return to old IRQL */
583 pop ecx
584 call @KfLowerIrql@4
585
586 /* Restore EAX (only in volatile case) */
587 .if \PreserveEax
588 mov eax, [ebx+KTRAP_FRAME_EAX]
589 .endif
590 cli
591 jmp 1b
592 2:
593 .endm
594
595 //
596 // @name TRAP_PROLOG
597 //
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.
601 //
602 // @param Label
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.
605 //
606 // @remark Use as follows:
607 // _KiTrap00:
608 // /* Push fake error code */
609 // push 0
610 //
611 // /* Enter common prologue */
612 // TRAP_PROLOG(0)
613 //
614 // /* Handle trap */
615 // <Your Trap Code Here>
616 //
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
620
621 /* Save the non-volatiles */
622 push ebp
623 push ebx
624 push esi
625 push edi
626
627 /* Save FS and set it to PCR */
628 push fs
629 mov ebx, KGDT_R0_PCR
630 .byte 0x66
631 mov fs, bx
632
633 /* Save exception list and bogus previous mode */
634 push fs:[KPCR_EXCEPTION_LIST]
635 push -1
636
637 /* Save volatiles and segment registers */
638 push eax
639 push ecx
640 push edx
641 push ds
642 push es
643 push gs
644
645 /* Set the R3 data segment */
646 mov ax, KGDT_R3_DATA + RPL_MASK
647
648 /* Skip debug registers and debug stuff */
649 sub esp, 0x30
650
651 /* Load the segment registers */
652 .byte 0x66
653 mov ds, ax
654 .byte 0x66
655 mov es, ax
656
657 /* Check if this interrupt happened in 16-bit mode */
658 cmp esp, 0x10000
659 jb _Ki16BitStackException
660
661 /* Set up frame */
662 mov ebp, esp
663
664 /* Check if this was from V86 Mode */
665 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
666 jnz V86_&Label
667
668 V86_&EndLabel:
669 /* Get current thread */
670 mov ecx, fs:[KPCR_CURRENT_THREAD]
671 cld
672
673 /* Flush DR7 */
674 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
675
676 /* Check if the thread was being debugged */
677 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
678 jnz Dr_&Label
679
680 /* Set the Trap Frame Debug Header */
681 Dr_&EndLabel:
682 SET_TF_DEBUG_HEADER
683 .endm
684
685 //
686 // @name INT_PROLOG
687 //
688 // This macro creates a standard interrupt entry prologue.
689 // It should be used for entry into any interrupt, including software.
690 //
691 // @param Label
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.
694 //
695 // @remark For software interrupts, make sure that a fake INT stack is created.
696 //
697 .macro INT_PROLOG Label EndLabel FakeErrorCode
698
699 .if \FakeErrorCode
700 /* Save fake error code */
701 push esp
702 .endif
703
704 /* Save the non-volatiles */
705 push ebp
706 push ebx
707 push esi
708 push edi
709
710 /* Skip debug registers and other stuff */
711 sub esp, 0x54
712
713 /* Set up frame */
714 mov ebp, esp
715
716 /* Save volatiles */
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
721
722 /* Check if this was from V86 Mode */
723 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
724 jnz V86_&Label
725
726 /* Check if this was kernel mode */
727 V86_&EndLabel:
728 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R0_CODE
729 jz 1f
730
731 /* Set segments */
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
736
737 /* Load the segment registers (use OVERRIDE (0x66)) */
738 mov ebx, KGDT_R0_PCR
739 mov eax, KGDT_R3_DATA | RPL_MASK
740 .byte 0x66
741 mov fs, bx
742 .byte 0x66
743 mov ds, ax
744 .byte 0x66
745 mov es, ax
746
747 1:
748 /* Get the previous exception list */
749 mov ebx, fs:[KPCR_EXCEPTION_LIST]
750
751 /* Set the exception handler chain terminator */
752 mov dword ptr fs:[KPCR_EXCEPTION_LIST], -1
753
754 /* Save the previous exception list */
755 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], ebx
756
757 .ifeq \FakeErrorCode
758 /* Setup the 16-bit stack */
759 lea eax, [esp+KTRAP_FRAME_ERROR_CODE]
760 lea ecx, [esp+KTRAP_FRAME_EIP]
761 mov ebx, ss:[eax]
762 mov ss:[eax], ecx
763 .endif
764
765 /* Check if this is the ABIOS stack */
766 /* cmp esp, 0x10000*/
767 /* jb Abios_Label*/
768
769 /* Delete error code */
770 and dword ptr [esp+KTRAP_FRAME_ERROR_CODE], 0
771
772 /* Get the current thread and clear direction flag */
773 mov ecx, PCR[KPCR_CURRENT_THREAD]
774 cld
775
776 /* Flush DR7 */
777 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
778
779 /* Check if the thread was being debugged */
780 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
781
782 .ifeq \FakeErrorCode
783 /* Push parameter */
784 push ebx
785 .endif
786
787 /* Save DR registers if needed */
788 jnz Dr_&Label
789
790 /* Set the trap frame debug header */
791 Dr_&EndLabel:
792 SET_TF_DEBUG_HEADER
793 .endm
794
795 //
796 // @name SYSCALL_PROLOG
797 //
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
801 // (KiSystemService)
802 //
803 // @param Label
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
806 // already exist.
807 //
808 // @remark None.
809 //
810 .macro SYSCALL_PROLOG Label EndLabel
811 /* Create a trap frame */
812 push 0
813 push ebp
814 push ebx
815 push esi
816 push edi
817 push fs
818
819 /* Load PCR Selector into fs */
820 mov ebx, KGDT_R0_PCR
821 .byte 0x66
822 mov fs, bx
823
824 /* Get a pointer to the current thread */
825 mov esi, PCR[KPCR_CURRENT_THREAD]
826
827 /* Save the previous exception list */
828 push PCR[KPCR_EXCEPTION_LIST]
829
830 /* Set the exception handler chain terminator */
831 mov dword ptr PCR[KPCR_EXCEPTION_LIST], -1
832
833 /* Save the old previous mode */
834 push [esi+KTHREAD_PREVIOUS_MODE]
835
836 /* Skip the other registers */
837 sub esp, 0x48
838
839 /* Set the new previous mode based on the saved CS selector */
840 mov ebx, [esp+0x6C]
841 and ebx, 1
842 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], bl
843
844 /* Go on the Kernel stack frame */
845 mov ebp, esp
846
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
850
851 /* Flush DR7 */
852 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
853
854 /* Check if the thread was being debugged */
855 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
856
857 /* Set the thread's trap frame and clear direction flag */
858 mov [esi+KTHREAD_TRAP_FRAME], ebp
859 cld
860
861 /* Save DR registers if needed */
862 jnz Dr_&Label
863
864 /* Set the trap frame debug header */
865 Dr_&EndLabel:
866 SET_TF_DEBUG_HEADER
867
868 /* Enable interrupts */
869 sti
870 .endm
871
872 //
873 // @name FASTCALL_PROLOG
874 //
875 // TODO
876 //
877 // @param Label
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
880 // already exist.
881 //
882 // @remark None.
883 //
884 .macro FASTCALL_PROLOG Label EndLabel
885
886 /* Set user selector */
887 mov ecx, KGDT_R3_DATA | RPL_MASK
888
889 /* Set FS to PCR */
890 push KGDT_R0_PCR
891 pop fs
892
893 /* Set DS/ES to User Selector */
894 mov ds, cx
895 mov es, cx
896
897 /* Set the current stack to Kernel Stack */
898 mov ecx, PCR[KPCR_TSS]
899 mov esp, [ecx+KTSS_ESP0]
900
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
911
912 /* Setup the Trap Frame stack */
913 push 0
914 push ebp
915 push ebx
916 push esi
917 push edi
918 push KGDT_R3_TEB + RPL_MASK
919
920 /* Save pointer to our PCR */
921 mov ebx, PCR[KPCR_SELF]
922
923 /* Get a pointer to the current thread */
924 mov esi, [ebx+KPCR_CURRENT_THREAD]
925
926 /* Set the exception handler chain terminator */
927 push [ebx+KPCR_EXCEPTION_LIST]
928 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
929
930 /* Use the thread's stack */
931 mov ebp, [esi+KTHREAD_INITIAL_STACK]
932
933 /* Push previous mode */
934 push UserMode
935
936 /* Skip the other registers */
937 sub esp, 0x48
938
939 /* Make space for us on the stack */
940 sub ebp, 0x29C
941
942 /* Write the previous mode */
943 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
944
945 /* Sanity check */
946 cmp ebp, esp
947 jnz BadStack
948
949 /* Flush DR7 */
950 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
951
952 /* Check if the thread was being debugged */
953 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
954
955 /* Set the thread's trap frame */
956 mov [esi+KTHREAD_TRAP_FRAME], ebp
957
958 /* Save DR registers if needed */
959 jnz Dr_&Label
960
961 /* Set the trap frame debug header */
962 Dr_&EndLabel:
963 SET_TF_DEBUG_HEADER
964
965 /* Enable interrupts */
966 sti
967 .endm
968
969 //
970 // @name V86_TRAP_PROLOG
971 //
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
975 // (KiSystemService)
976 //
977 // @param Label
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
980 // already exist.
981 //
982 // @remark None.
983 //
984 .macro V86_TRAP_PROLOG Label EndLabel
985
986 /* Skip everything to the error code */
987 sub esp, KTRAP_FRAME_ERROR_CODE
988
989 /* Clear the error code */
990 mov word ptr [esp+KTRAP_FRAME_ERROR_CODE+2], 0
991
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
998
999 /* Save PCR and Ring 3 segments */
1000 mov ebx, KGDT_R0_PCR
1001 mov eax, KGDT_R3_DATA + RPL_MASK
1002
1003 /* Save ECX and EDX too */
1004 mov [esp+KTRAP_FRAME_ECX], ecx
1005 mov [esp+KTRAP_FRAME_EDX], edx
1006
1007 /* Set debugging markers */
1008 mov dword ptr [esp+KTRAP_FRAME_PREVIOUS_MODE], -1
1009 mov dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1010
1011 /* Now set segments (use OVERRIDE, 0x66) */
1012 .byte 0x66
1013 mov fs, bx
1014 .byte 0x66
1015 mov ds, ax
1016 .byte 0x66
1017 mov es, ax
1018
1019 /* Set the trap frame in the stack and clear the direction flag */
1020 mov ebp, esp
1021 cld
1022
1023 /* Save the exception list */
1024 mov eax, fs:[KPCR_EXCEPTION_LIST]
1025 mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
1026
1027 /* Check if we need debugging */
1028 mov eax, dr7
1029 test eax, ~DR7_RESERVED_MASK
1030 mov [esp+KTRAP_FRAME_DR7], eax
1031 jnz Dr_&Label
1032
1033 Dr_&EndLabel:
1034 .endm
1035
1036 //
1037 // @name V86_TRAP_EPILOG
1038 //
1039 // This macro creates an epilogue for leaving V86 traps
1040 //
1041 // @param None.
1042 //
1043 // @remark None.
1044 //
1045 .macro V86_TRAP_EPILOG
1046
1047 /* Get the current thread and make it unalerted */
1048 ExitBegin:
1049 mov ebx, PCR[KPCR_CURRENT_THREAD]
1050 mov byte ptr [ebx+KTHREAD_ALERTED], 0
1051
1052 /* Check if it has User-mode APCs pending */
1053 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
1054 jne PendingUserApc
1055
1056 /* It doesn't, pop the frame */
1057 add esp, KTRAP_FRAME_EDX
1058 pop edx
1059 pop ecx
1060 pop eax
1061
1062 /* Check if DR registers should be restored */
1063 test dword ptr [ebp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1064 jnz V86DebugRestore
1065
1066 /* Finish popping the rest of the frame, and return to P-mode */
1067 V86DebugContinue:
1068 add esp, 12
1069 pop edi
1070 pop esi
1071 pop ebx
1072 pop ebp
1073 add esp, 4
1074 iretd
1075
1076 V86DebugRestore:
1077
1078 /* Get DR0, 1 */
1079 xor ebx, ebx
1080 mov esi, [ebp+KTRAP_FRAME_DR0]
1081 mov edi, [ebp+KTRAP_FRAME_DR1]
1082
1083 /* Clear DR 7 */
1084 mov dr7, ebx
1085
1086 /* Get DR2 and load DR0-2 */
1087 mov ebx, [ebp+KTRAP_FRAME_DR2]
1088 mov dr0, esi
1089 mov dr1, edi
1090 mov dr2, ebx
1091
1092 /* Get DR3-7 */
1093 mov esi, [ebp+KTRAP_FRAME_DR0]
1094 mov edi, [ebp+KTRAP_FRAME_DR1]
1095 mov ebx, [ebp+KTRAP_FRAME_DR7]
1096
1097 /* Load them */
1098 mov dr3, esi
1099 mov dr6, edi
1100 mov dr7, ebx
1101 jmp V86DebugContinue
1102
1103 PendingUserApc:
1104
1105 /* Raise to APC level */
1106 mov ecx, APC_LEVEL
1107 call @KfRaiseIrql@4
1108
1109 /* Save KIRQL and deliver APCs */
1110 push eax
1111 sti
1112 push ebp
1113 push 0
1114 push UserMode
1115 call _KiDeliverApc@12
1116
1117 /* Restore IRQL */
1118 pop ecx
1119 call @KfLowerIrql@4
1120 cli
1121
1122 /* Check if we're not in V86 anymore */
1123 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1124 jnz ExitBegin
1125 .endm
1126
1127 //
1128 // @name TRAP_EPILOG
1129 //
1130 // This macro creates an epilogue for leaving any system trap.
1131 // It is used for exiting system calls, exceptions, interrupts and generic
1132 // traps.
1133 //
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.
1137 //
1138 // @param RestorePreviousMode
1139 // Specifies if the previous mode should be restored.
1140 //
1141 // @param RestoreSegments
1142 // Specifies if the segment registers should be restored.
1143 //
1144 // @param RestoreVolatiles
1145 // Specifies if the volatile registers should be restored.
1146 //
1147 // @param RestoreAllRegs
1148 // Specifies if volatiles and segments should both be restored.
1149 //
1150 // @remark
1151 //
1152 .macro TRAP_EPILOG SystemCall, RestorePreviousMode, RestoreSegments, RestoreVolatiles, RestoreAllRegs
1153 #if DBG
1154 /* Assert the flags */
1155 pushfd
1156 pop edx
1157 test edx, EFLAGS_INTERRUPT_MASK
1158 jnz 6f
1159
1160 /* Assert the stack */
1161 cmp esp, ebp
1162 jnz 6f
1163
1164 /* Assert the trap frame */
1165 #endif
1166 5:
1167 #if DBG
1168 sub dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1169 jnz 0f
1170
1171 /* Assert FS */
1172 mov bx, fs
1173 cmp bx, KGDT_R0_PCR
1174 jnz 1f
1175
1176 /* Assert exception list */
1177 cmp dword ptr PCR[KPCR_EXCEPTION_LIST], 0
1178 jnz 2f
1179
1180 1:
1181 push -1
1182 call _KeBugCheck@4
1183 #endif
1184
1185 2:
1186 /* Get exception list */
1187 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
1188
1189 #if DBG
1190 /* Assert the saved exception list */
1191 or edx, edx
1192 jnz 1f
1193 UNHANDLED_PATH
1194 1:
1195 #endif
1196
1197 /* Restore it */
1198 mov PCR[KPCR_EXCEPTION_LIST], edx
1199
1200 .if \RestorePreviousMode
1201 /* Get previous mode */
1202 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1203
1204 #if DBG
1205 /* Assert the saved previous mode */
1206 cmp ecx, -1
1207 jnz 1f
1208 UNHANDLED_PATH
1209 1:
1210 #endif
1211
1212 /* Restore the previous mode */
1213 mov esi, PCR[KPCR_CURRENT_THREAD]
1214 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
1215 .else
1216
1217 #if DBG
1218 /* Assert the saved previous mode */
1219 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
1220 cmp ecx, -1
1221 jz 1f
1222 UNHANDLED_PATH
1223 1:
1224 #endif
1225 .endif
1226
1227 /* Check for debug registers */
1228 test dword ptr [esp+KTRAP_FRAME_DR7], ~DR7_RESERVED_MASK
1229 jnz 2f
1230
1231 /* Check for V86 */
1232 4:
1233 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1234 jnz V86_Exit
1235
1236 /* Check if the frame was edited */
1237 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
1238 jz 7f
1239
1240 .if \RestoreAllRegs
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
1244 cmc
1245 ja 8f
1246 .endif
1247
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]
1253 .endif
1254
1255 /* Check if we were called from kernel mode */
1256 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1257 jz 9f
1258
1259 .if \RestoreSegments
1260 /* Restore segment registers */
1261 lea esp, [ebp+KTRAP_FRAME_GS]
1262 pop gs
1263 pop es
1264 pop ds
1265 .endif
1266
1267 /* Restore FS */
1268 3:
1269 lea esp, [ebp+KTRAP_FRAME_FS]
1270 pop fs
1271
1272 9:
1273 /* Skip debug information and unsaved registers */
1274 lea esp, [ebp+KTRAP_FRAME_EDI]
1275 pop edi
1276 pop esi
1277 pop ebx
1278 pop ebp
1279
1280 /* Check for ABIOS */
1281 cmp word ptr [esp+8], 0x80
1282 ja AbiosExit
1283
1284 /* Pop error code */
1285 add esp, 4
1286
1287 .if \SystemCall
1288 /* Check if previous CS is from user-mode */
1289 test dword ptr [esp+4], 1
1290
1291 /* It is, so use Fast Exit */
1292 jnz FastExit
1293
1294 /* Jump back to stub */
1295 pop edx
1296 pop ecx
1297 popf
1298 jmp edx
1299
1300 .ret:
1301 .endif
1302 iret
1303
1304 .if \SystemCall
1305 FastExit:
1306 /* Is SYSEXIT Supported/Wanted? */
1307 cmp dword ptr ss:[_KiFastSystemCallDisable], 0
1308 jnz .ret
1309 test dword ptr [esp+8], EFLAGS_TF
1310 jnz .ret
1311
1312 /* Restore FS to TIB */
1313 mov ecx, KGDT_R3_TEB + RPL_MASK
1314 mov fs, ecx
1315
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 */
1322
1323 /*
1324 * At this point:
1325 * ECX points to the old User Stack.
1326 * EDX points to the instruction to execute in usermode after the sysenter
1327 */
1328 sti
1329 sysexit
1330 .endif
1331
1332 .if \RestoreAllRegs
1333 8:
1334 /* Restore EAX */
1335 mov eax, [esp+KTRAP_FRAME_EAX]
1336
1337 /* Skip registers */
1338 add esp, 0x30
1339
1340 /* Restore segments and volatiles */
1341 pop gs
1342 pop es
1343 pop ds
1344 pop edx
1345 pop ecx
1346
1347 /* Jump back to mainline code */
1348 jmp 3b
1349 .endif
1350
1351 #if DBG
1352 0:
1353 /* Fix up the mask */
1354 add dword ptr [esp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
1355
1356 6:
1357 UNHANDLED_PATH
1358 jmp 5b
1359 #endif
1360
1361 2:
1362 /* Check if this was V86 mode */
1363 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1364 jnz 1f
1365
1366 /* Check if it was user mode */
1367 test word ptr [esp+KTRAP_FRAME_CS], MODE_MASK
1368 jz 4b
1369
1370 1:
1371 /* Clear DR7 */
1372 xor ebx, ebx
1373 mov dr7, ebx
1374
1375 /* Get DR0, 1, 2 */
1376 mov esi, [ebp+KTRAP_FRAME_DR0]
1377 mov edi, [ebp+KTRAP_FRAME_DR1]
1378 mov ebx, [ebp+KTRAP_FRAME_DR2]
1379
1380 /* Set them */
1381 mov dr0, esi
1382 mov dr1, edi
1383 mov dr2, ebx
1384
1385 /* Get DR3, 6, 7 */
1386 mov esi, [ebp+KTRAP_FRAME_DR3]
1387 mov edi, [ebp+KTRAP_FRAME_DR6]
1388 mov ebx, [ebp+KTRAP_FRAME_DR7]
1389
1390 /* Set them */
1391 mov dr3, esi
1392 mov dr6, edi
1393 mov dr7, ebx
1394 jmp 4b
1395
1396 7:
1397 /* Restore real CS value */
1398 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
1399 mov [esp+KTRAP_FRAME_CS], ebx
1400
1401 /*
1402 * If ESP was modified, then a special interrupt exit stack
1403 * must be created to "update" ESP's value in a legal manner
1404 */
1405 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
1406 sub ebx, 0xC
1407 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
1408
1409 /* Copy Interrupt Stack */
1410 mov esi, [esp+KTRAP_FRAME_EFLAGS]
1411 mov [ebx+8], esi
1412 mov esi, [esp+KTRAP_FRAME_CS]
1413 mov [ebx+4], esi
1414 mov esi, [esp+KTRAP_FRAME_EIP]
1415 mov [ebx], esi
1416
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]
1422 .endif
1423
1424 /* Return */
1425 add esp, KTRAP_FRAME_EDI
1426 pop edi
1427 pop esi
1428 pop ebx
1429 pop ebp
1430 mov esp, [esp]
1431 iret
1432 .endm
1433
1434 //
1435 // @name INT_EPILOG
1436 //
1437 // This macro creates an epilogue for leaving any system trap.
1438 // It is used for exiting system calls, exceptions, interrupts and generic
1439 // traps.
1440 //
1441 // @param Spurious - TRUE if the interrupt was unexpected and spurious.
1442 //
1443 // @remark None.
1444 //
1445 .macro INT_EPILOG Spurious
1446
1447 .if \Spurious
1448 /* Just exit the trap */
1449 jmp _Kei386EoiHelper@0
1450 .else
1451 /* Disable interrupts */
1452 cli
1453
1454 /* End the interrupt and do EOI */
1455 lea eax, [esp+8]
1456 mov PCR[KPCR_VDM_ALERT], eax
1457 call _HalEndSystemInterrupt@8
1458 jmp _Kei386EoiHelper@0
1459 .endif
1460 .endm
1461
1462 #if DBG
1463
1464 .macro VERIFY_INT Label
1465 /* Get the current time and mask it to 192 ticks */
1466 mov eax, _KeTickCount
1467 and eax, 0xC0
1468
1469 /* Check if we're in the same tick area */
1470 cmp eax, dword ptr [edi+KINTERRUPT_TICK_COUNT]
1471 jg VfRst_&Label
1472 jl VfWrap_&Label
1473
1474 /* If we got here, then our count is too large */
1475 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT]
1476 jz VfOvr_&Label
1477 Vf_&Label:
1478 .endm
1479
1480 .macro VERIFY_INT_END Label, Info
1481 VfOvr_&Label:
1482
1483 /* Decrement the dispatch count and check if we should bug check */
1484 dec word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2]
1485 jz 1f
1486
1487 /* Update the tick count */
1488 add eax, 0x40
1489 mov [edi+KINTERRUPT_TICK_COUNT], eax
1490 jmp VfRstDef_&Label
1491
1492 1:
1493 /* Check if the debugger is enabled */
1494 cmp byte ptr __KdDebuggerEnabled, 0
1495 jnz 1f
1496
1497 /* It isn't, bugcheck */
1498 push Info
1499 push edi
1500 push [edi+KINTERRUPT_SERVICE_CONTEXT]
1501 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1502 push HARDWARE_INTERRUPT_STORM
1503 call _KeBugCheckEx@20
1504
1505 1:
1506 /* Debugger enabled, do a debug print + break instead */
1507 push [edi+KINTERRUPT_SERVICE_ROUTINE]
1508 push offset _IsrOverflowMsg
1509 call _DbgPrint
1510 add esp, 8
1511 int 3
1512
1513 /* Breakpoint handled, get the new tick count */
1514 mov eax, _KeTickCount
1515 and eax, 0xC0
1516
1517 VfRst_&Label:
1518 /* Reset tick count */
1519 mov dword ptr [edi+KINTERRUPT_TICK_COUNT], eax
1520 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT+2], 64
1521
1522 VfRstDef_&Label:
1523 /* Put default overflow count and continue */
1524 mov ax, _KiISROverflow
1525 mov word ptr [edi+KINTERRUPT_DISPATCH_COUNT], ax
1526 jmp Vf_&Label
1527
1528 VfWrap_&Label:
1529 /* Check if we wrapped */
1530 add eax, 0x40
1531 cmp eax, [edi+KINTERRUPT_TICK_COUNT]
1532 je Vf_&Label
1533
1534 /* We did, start over */
1535 mov eax, _KeTickCount
1536 jmp VfRst_&Label
1537 .endm
1538
1539 #else
1540
1541 /* We don't verify interrupts on retail builds */
1542 .macro VERIFY_INT Label
1543 .endm
1544 .macro VERIFY_INT_END Label, Info
1545 .endm
1546
1547 #endif
1548
1549