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