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