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