8b02df443c94822622eb246282b7192983af7268
[reactos.git] / reactos / ntoskrnl / ke / i386 / syscall.S
1 /*
2 * FILE: ntoskrnl/ke/i386/syscall.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: System Call Handler
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
6 */
7
8 #include <roscfg.h>
9 #include <internal/i386/ke.h>
10 #include <ndk/asm.h>
11
12 #define UserMode (1)
13 #define STATUS_INVALID_SYSTEM_SERVICE 0xC000001C
14
15 .globl _KiServiceExit
16 .globl _KiServiceExit2
17 .globl _KiFastCallEntry
18 .globl _KiSystemService
19 .globl _KiDebugService
20 .intel_syntax noprefix
21
22 /*
23 * NOTE: I will create some macros for trap entry and exit,
24 * DR* register restoration, modified frame exit, etc, if GAS
25 * allows it/I find a way how. This would remove a lot of
26 * duplicated code in this file plus the other irq/trap asm files.
27 * I think this is similar to what NT does, if you look at teh
28 * Dr_kit*_a functions which look auto-generated.
29 */
30
31 /*
32 * There are 3 main types of Trap Exits:
33 *
34 * - KiServiceExit
35 * - Clear interrupt flag
36 * - Common User APC Dispatching
37 * - Common exit code; segments and volatiles are not restored
38 * You use this for System Call return, when volatiles are irrelevant.
39 * (NtContinue, NtRaiseException, KiCallUserMode and all System Call returns)
40 *
41 * - KiServiceExit2
42 * - Clear interrupt flag
43 * - Common User APC Dispatching
44 * - Common exit code; the entire frame is restored.
45 * You use this when volatiles and other registers need to be restored.
46 * For example, if debugging is active (NtContinue, NtRaiseException).
47 *
48 * - Kei386EoiHelper
49 * - Clear interrupt flag
50 * - Common User APC Dispatching
51 * - Common exit code; the entire frame is restored but *NOT* the Previous Mode
52 * You use this in the same context as KiServiceExit2, but when the Previous Mode
53 * should be tampered with. Clearly, as its name suggests, this routine is mostly
54 * useful for End Of Interrupts.
55 * Note that this routine is EXPORTED.
56 * Note that this routine must called by a JMP, not a CALL.
57 */
58
59 /*
60 * The common exit code has 3 modes of operation:
61 * - Whether or not to restore segments
62 * - Whether or not to restore volatiles
63 * - Whether or not to restore the previous mode
64 * All these are exemplified by the 3 trap exits shown above
65 */
66
67 /*
68 * There is also common Debug Code present in the common exit code, which
69 * in turn calls common code to save the debug registers
70 */
71
72 /*
73 * FIXMEs:
74 * - Dig in trap code and see why we need to push/pop the segments,
75 * which -shouldn't- be needed on syscalls; one of the things
76 * missing for this to work is lazy loading in the GPF handler,
77 * but there are other things to consider.
78 * - Use macros and merge with trap.s nicely
79 */
80
81 /*
82 * Entries will be discussed later.
83 */
84
85 /*** This file is a mess; it is being worked on. Please contact Alex:
86 *** alex@relsoft.net if you want to make any changes to it before this
87 *** message goes away
88 */
89
90 /* FUNCTIONS ***************************************************************/
91
92 BadStack:
93
94 /* Restore ESP0 stack */
95 mov ecx, [fs:KPCR_TSS]
96 mov esp, ss:[ecx+KTSS_ESP0]
97
98 /* Generate V86M Stack for Trap 6 */
99 push 0
100 push 0
101 push 0
102 push 0
103
104 /* Generate interrupt stack for Trap 6 */
105 push KGDT_R3_DATA + RPL_MASK
106 push 0
107 push 0x20202
108 push KGDT_R3_CODE + RPL_MASK
109 push 0
110 jmp _KiTrap6
111
112 _KiFastCallEntry:
113
114 // ==================== UNIQUE SYSENTER STUB. DO NOT DUPLICATE ============//
115 /* Set FS to PCR */
116 mov ecx, KGDT_R0_PCR
117 mov fs, cx
118
119 /* Set DS/ES to Kernel Selector */
120 mov ecx, KGDT_R0_DATA
121 mov ds, cx
122 mov es, cx
123
124 /* Set the current stack to Kernel Stack */
125 mov ecx, [fs:KPCR_TSS]
126 mov esp, ss:[ecx+KTSS_ESP0]
127
128 /* Set up a fake INT Stack. */
129 push KGDT_R3_DATA + RPL_MASK
130 push edx /* Ring 3 SS:ESP */
131 pushf /* Ring 3 EFLAGS */
132 push 2 /* Ring 0 EFLAGS */
133 add edx, 8 /* Skip user parameter list */
134 popf /* Set our EFLAGS */
135 or dword ptr [esp], X86_EFLAGS_IF /* Re-enable IRQs in EFLAGS, to fake INT */
136 push KGDT_R3_CODE + RPL_MASK
137 push KUSER_SHARED_SYSCALL_RET
138
139 /* Setup the Trap Frame stack */
140 push 0
141 push ebp
142 push ebx
143 push esi
144 push edi
145 push KGDT_R3_TEB + RPL_MASK
146
147 /* Save pointer to our PCR */
148 mov ebx, [fs:KPCR_SELF]
149
150 /* Get a pointer to the current thread */
151 mov esi, [ebx+KPCR_CURRENT_THREAD]
152
153 /* Set the exception handler chain terminator */
154 push [ebx+KPCR_EXCEPTION_LIST]
155 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
156
157 /* Use the thread's stack */
158 mov ebp, [esi+KTHREAD_INITIAL_STACK]
159
160 /* Push previous mode */
161 push UserMode
162
163 .att_syntax
164 /* Save other registers */
165 sub $0xC, %esp // + 0x70
166 pushl $KGDT_R3_DATA + RPL_MASK // + 0x40
167 pushl $KGDT_R3_DATA + RPL_MASK // + 0x44
168 pushl $0 // + 0x48
169 sub $0x30, %esp // + 0x70
170 .intel_syntax noprefix
171
172 /* Make space for us on the stack */
173 sub ebp, 0x29C
174
175 /* Write the previous mode */
176 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
177
178 /* Sanity check */
179 cmp ebp, esp
180 jnz BadStack
181
182 /* Flush DR7 */
183 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
184
185 /* Check if the thread was being debugged */
186 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
187
188 /* Jump to shared code or DR Save */
189 //jnz Dr_FastCallDrSave
190 jmp SharedCode
191
192 _KiSystemService:
193
194 // ==================== UNIQUE SYSCALL TRAP ENTRY DO NOT DUPLICATE ============//
195 /* Create a trap frame */
196 push 0
197 push ebp
198 push ebx
199 push esi
200 push edi
201 push fs
202
203 /* Load PCR Selector into fs */
204 mov ebx, KGDT_R0_PCR
205 mov fs, bx
206
207 /* Get a pointer to the current thread */
208 mov esi, [fs:KPCR_CURRENT_THREAD]
209
210 /* Save the previous exception list */
211 push [fs:KPCR_EXCEPTION_LIST]
212
213 /* Set the exception handler chain terminator */
214 mov dword ptr [fs:KPCR_EXCEPTION_LIST], -1
215
216 /* Save the old previous mode */
217 push ss:[esi+KTHREAD_PREVIOUS_MODE]
218
219 .att_syntax
220 /* Save other registers */
221 sub $0xC, %esp // + 0x70
222 pushl %ds // + 0x40
223 pushl %es // + 0x44
224 pushl %gs // + 0x48
225 sub $0x30, %esp // + 0x70
226 .intel_syntax noprefix
227
228 /* Set the new previous mode based on the saved CS selector */
229 mov ebx, [esp+0x6C]
230 and ebx, 1
231 mov byte ptr ss:[esi+KTHREAD_PREVIOUS_MODE], bl
232
233 /* Go on the Kernel stack frame */
234 mov ebp, esp
235
236 /* Save the old trap frame pointer where EDX would be saved */
237 mov ebx, [esi+KTHREAD_TRAP_FRAME]
238 mov [ebp+KTRAP_FRAME_EDX], ebx
239
240 // ==================== COMMON DR SAVE CHECK.AND DEBUG FRAME SETUP ============//
241 /* Flush DR7 */
242 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
243
244 /* Check if the thread was being debugged */
245 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
246 cld
247 //jnz Dr_kss_a
248
249 /* Save a pointer to the trap frame in the TCB */
250 SharedCode:
251 mov [esi+KTHREAD_TRAP_FRAME], ebp
252
253 /* Get the Debug Trap Frame EBP/EIP */
254 mov ebx, [ebp+KTRAP_FRAME_EBP]
255 mov edi, [ebp+KTRAP_FRAME_EIP]
256
257 #ifdef DBG
258 /*
259 * We want to know the address from where the syscall stub was called.
260 * If PrevMode is KernelMode, that address is stored in our own (kernel)
261 * stack, at location KTRAP_FRAME_ESP.
262 * If we're coming from UserMode, we load the usermode stack pointer
263 * and go back two frames (first frame is the syscall stub, second call
264 * is the caller of the stub).
265 */
266 mov edi, [ebp+KTRAP_FRAME_ESP]
267 test byte ptr [esi+KTHREAD_PREVIOUS_MODE], 0x01
268 jz PrevWasKernelMode
269 mov edi, [edi+4]
270 PrevWasKernelMode:
271 #endif
272
273 /* Write the debug data */
274 mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
275 mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
276 mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
277 mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
278
279 // ============= END OF COMMON DR SAVE CHECK.AND DEBUG FRAME SETUP ============//
280 /* Enable interrupts */
281 sti
282
283 CheckValidCall:
284
285 /*
286 * Find out which table offset to use. Converts 0x1124 into 0x10.
287 * The offset is related to the Table Index as such: Offset = TableIndex x 10
288 */
289 mov edi, eax
290 shr edi, 8
291 and edi, 0x10
292 mov ecx, edi
293
294 /* Now add the thread's base system table to the offset */
295 add edi, [esi+KTHREAD_SERVICE_TABLE]
296
297 /* Get the true syscall ID and check it */
298 mov ebx, eax
299 and eax, 0xFFF
300 cmp eax, [edi+8]
301
302 /* Invalid ID, try to load Win32K Table */
303 jnb KiBBTUnexpectedRange
304
305 #if 0 // <== Disabled for two reasons: We don't save TEB in 0x18, but KPCR.
306 // <== We don't have a KeGdiFlushUserBatch callback yet (needs to be
307 // sent through the PsInitializeWin32Callouts structure)
308 /* Check if this was Win32K */
309 cmp ecx, 0x10
310 jnz NotWin32K
311
312 /* Get the TEB */
313 mov ecx, [fs:KPCR_TEB]
314
315 /* Check if we should flush the User Batch */
316 xor ebx, ebx
317 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
318 jz NoWin32K
319
320 /* Flush it */
321 push edx
322 push eax
323 call [_KeGdiFlushUserBatch]
324 pop eax
325 pop edx
326 #endif
327
328 NotWin32K:
329 /* Users's current stack frame pointer is source */
330 mov esi, edx
331
332 /* Allocate room for argument list from kernel stack */
333 mov ebx, [edi+12]
334 xor ecx, ecx
335 mov cl, [eax+ebx]
336
337 /* Get pointer to function */
338 mov edi, [edi]
339 mov ebx, [edi+eax*4]
340
341 /* Allocate space on our stack */
342 sub esp, ecx
343
344 /*
345 * Copy the arguments from the user stack to our stack
346 * FIXME: This needs to be probed with MmSystemRangeStart
347 */
348 shr ecx, 2
349 mov edi, esp
350 rep movsd
351
352 #ifdef DBG
353 /*
354 * The following lines are for the benefit of GDB. It will see the return
355 * address of the "call ebx" below, find the last label before it and
356 * thinks that that's the start of the function. It will then check to see
357 * if it starts with a standard function prolog (push ebp, mov ebp,esp).
358 * When that standard function prolog is not found, it will stop the
359 * stack backtrace. Since we do want to backtrace into usermode, let's
360 * make GDB happy and create a standard prolog.
361 */
362 KiSystemService:
363 push ebp
364 mov ebp,esp
365 pop ebp
366 #endif
367
368 /* Do the System Call */
369 call ebx
370
371 /* Deallocate the kernel stack frame */
372 mov esp, ebp
373
374 KeReturnFromSystemCall:
375
376 /* Get the Current Thread */
377 mov ecx, [fs:KPCR_CURRENT_THREAD]
378
379 /* Restore the old trap frame pointer */
380 mov edx, [ebp+KTRAP_FRAME_EDX]
381 mov [ecx+KTHREAD_TRAP_FRAME], edx
382
383 _KiServiceExit:
384 /* Disable interrupts */
385 cli
386
387 // ================= COMMON USER-MODE APC DELIVERY CHECK ============//
388 /* Check for V86 mode */
389 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
390 jnz ApcLoop
391
392 /* Deliver APCs only if we were called from user mode */
393 test byte ptr [ebp+KTRAP_FRAME_CS], 1
394 je KiRosTrapReturn
395
396 /* Get the current thread */
397 ApcLoop:
398 mov ebx, [fs:KPCR_CURRENT_THREAD]
399
400 /* Make it non-alerted */
401 mov byte ptr [ebx+KTHREAD_ALERTED], 0
402
403 /* And only if any are actually pending */
404 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
405 je KiRosTrapReturn
406
407 /* Save pointer to Trap Frame */
408 mov ebx, ebp
409
410 // ================= PRESENT ONLY IF VOLATILES NEEDED ============//
411 /* Save some stuff that raising IRQL will kill */
412 mov [ebx+KTRAP_FRAME_EAX], eax
413 mov dword ptr [ebx+KTRAP_FRAME_FS], KGDT_R3_TEB + RPL_MASK
414 mov dword ptr [ebx+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
415 mov dword ptr [ebx+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
416 mov dword ptr [ebx+KTRAP_FRAME_GS], 0
417 // ============= END PRESENT ONLY IF VOLATILES NEEDED ============//
418
419 /* Raise IRQL to APC_LEVEL */
420 mov ecx, 1
421 call @KfRaiseIrql@4
422
423 /* Save old IRQL */
424 push eax
425
426 /* Deliver APCs */
427 sti
428 push ebx
429 push 0
430 push UserMode
431 call _KiDeliverApc@12
432
433 /* Return to old IRQL */
434 pop ecx
435 call @KfLowerIrql@4
436
437 /* Restore EAX (only in volatile case) */
438 mov eax, [ebx+KTRAP_FRAME_EAX]
439 cli
440 jmp ApcLoop
441 // ============== END COMMON USER-MODE APC DELIVERY CHECK ============//
442
443 KiRosTrapReturn:
444 // ========================= COMMON TRAP EXIT CODE ===================//
445 /* Restore exception list */
446 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
447 mov [fs:KPCR_EXCEPTION_LIST], edx
448
449 // ==================== ONLY IF PREVIOUS MODE NEEDED ==================//
450 /* Restore previous mode */
451 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
452 mov esi, [fs:KPCR_CURRENT_THREAD]
453 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
454 // ==================== END IF PREVIOUS MODE NEEDED ===================//
455
456 /* Check for V86 */
457 test dword ptr [esp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
458 jnz V86_Exit
459
460 /* Check if the frame was edited */
461 V86_Exit_Return:
462 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
463 jz EditedFrame
464
465 // ==================== ONLY IF FULL RESTORE NEEDED ===================//
466 /* Check the old mode */
467 cmp word ptr [esp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
468 bt word ptr [esp+KTRAP_FRAME_CS], 0
469 cmc
470 ja RestoreAll
471 // ==================== END IF FULL RESTORE NEEDED ====================//
472
473 /* Skip debug information and unsaved registers */
474 //badbadbad
475 add esp, 0x30
476 pop gs
477 pop es
478 pop ds
479 add esp, 0x14
480 //badbadbad
481
482 /* Restore FS */
483 RestoreFs:
484 //lea esp, [ebp+KTRAP_FRAME_FS] <= BUG IN WIN32K CALLBACKS! STACK GETS SMASHED
485 pop fs
486
487 CommonStackClean:
488 /* Skip debug information and unsaved registers */
489 //lea esp, [ebp+KTRAP_FRAME_EDI] <= BUG IN WIN32K CALLBACKS! STACK GETS SMASHED
490 pop edi
491 pop esi
492 pop ebx
493 pop ebp
494
495 /* Check for ABIOS */
496 cmp word ptr [esp+8], 0x80
497 ja AbiosExit
498
499 AbiosReturn:
500 /* Pop error code */
501 add esp, 4
502
503 /* Check if previous CS is from user-mode */
504 test dword ptr [esp+4], 1
505
506 /* It is, so use Fast Exit */
507 jnz FastRet
508
509 /* Jump back to stub */
510 pop edx
511 pop ecx
512 popf
513 jmp edx
514
515 IntRet:
516
517 iret
518
519 FastRet:
520 /* Is SYSEXIT Supported/Wanted? */
521 cmp dword ptr ss:[_KiFastSystemCallDisable], 0
522 jnz IntRet
523 test dword ptr [esp+8], X86_EFLAGS_TF
524 jnz IntRet
525
526 /* Restore FS to TIB */
527 mov ecx, KGDT_R3_TEB + RPL_MASK
528 mov fs, ecx
529
530 /* We will be cleaning up the stack ourselves */
531 pop edx /* New Ring 3 EIP */
532 add esp, 4 /* Skip Ring 3 DS */
533 /* and dword ptr [esp], ~X86_EFLAGS_IF Line below is equivalent to this,
534 but older binutils versions don't understand ~ */
535 and dword ptr [esp], 0xfffffdff /* Remove IRQ hack from EFLAGS */
536 popf /* Restore old EFLAGS */
537 pop ecx /* Old Ring 3 SS:ESP */
538
539 /*
540 * At this point:
541 * ECX points to the old User Stack.
542 * EDX points to the instruction to execute in usermode after the sysenter
543 */
544 sti
545 sysexit
546
547 V86_Exit:
548 /* Move to EDX position */
549 add esp, KTRAP_FRAME_EDX
550
551 /* Restore volatiles */
552 pop edx
553 pop ecx
554 pop eax
555 jmp V86_Exit_Return
556
557 AbiosExit:
558 /* Not yet supported */
559 int 3
560
561 RestoreAll:
562 /* Restore EAX */
563 mov eax, [esp+KTRAP_FRAME_EAX]
564
565 /* Skip registers */
566 add esp, 0x30
567
568 /* Restore segments and volatiles */
569 pop gs
570 pop es
571 pop ds
572 pop edx
573 pop ecx
574
575 /* Jump back to mainline code */
576 jmp RestoreFs
577
578 EditedFrame:
579 /* Restore real CS value */
580 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
581 mov [esp+KTRAP_FRAME_CS], ebx
582
583 /*
584 * If ESP was modified, then a special interrupt exit stack
585 * must be created to "update" ESP's value in a legal manner
586 */
587 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
588 sub ebx, 0xC
589 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
590
591 /* Copy Interrupt Stack */
592 mov esi, [esp+KTRAP_FRAME_EFLAGS]
593 mov [ebx+8], esi
594 mov esi, [esp+KTRAP_FRAME_CS]
595 mov [ebx+4], esi
596 mov esi, [esp+KTRAP_FRAME_EIP]
597 mov [ebx], esi
598
599 /* Return */
600 add esp, KTRAP_FRAME_EDI
601 pop edi
602 pop esi
603 pop ebx
604 pop ebp
605 mov esp, [esp]
606 iret
607
608 KiBBTUnexpectedRange:
609
610 /* If this isn't a Win32K call, fail */
611 cmp ecx, 0x10
612 jne InvalidCall
613
614 /* Set up Win32K Table */
615 push edx
616 push ebx
617 call _PsConvertToGuiThread@0
618
619 /* FIXME: Handle failure */
620 pop eax
621 pop edx
622
623 /* Reset trap frame address */
624 mov ebp, esp
625 mov [esi+KTHREAD_TRAP_FRAME], ebp
626
627 /* Try the Call again */
628 jmp CheckValidCall
629
630 InvalidCall:
631
632 /* Invalid System Call */
633 mov eax, STATUS_INVALID_SYSTEM_SERVICE
634 jmp KeReturnFromSystemCall
635
636 _KiServiceExit2:
637
638 /* Disable interrupts */
639 cli
640
641 /* Check for V86 mode */
642 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
643 jnz ApcLoop2
644
645 /* Deliver APCs only if we were called from user mode */
646 test byte ptr [ebp+KTRAP_FRAME_CS], 1
647 je KiRosTrapReturn2
648
649 /* Get the current thread */
650 ApcLoop2:
651 mov ebx, [fs:KPCR_CURRENT_THREAD]
652
653 /* Make it non-alerted */
654 mov byte ptr [ebx+KTHREAD_ALERTED], 0
655
656 /* And only if any are actually pending */
657 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
658 je KiRosTrapReturn2
659
660 /* Save pointer to Trap Frame */
661 mov ebx, ebp
662
663 /* Raise IRQL to APC_LEVEL */
664 mov ecx, 1
665 call @KfRaiseIrql@4
666
667 /* Save old IRQL */
668 push eax
669
670 /* Deliver APCs */
671 sti
672 push ebx
673 push 0
674 push UserMode
675 call _KiDeliverApc@12
676
677 /* Return to old IRQL */
678 pop ecx
679 call @KfLowerIrql@4
680 cli
681 jmp ApcLoop2
682
683 KiRosTrapReturn2:
684
685 /* Restore exception list */
686 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
687 mov [fs:KPCR_EXCEPTION_LIST], edx
688
689 /* Restore previous mode */
690 mov ecx, [esp+KTRAP_FRAME_PREVIOUS_MODE]
691 mov esi, [fs:KPCR_CURRENT_THREAD]
692 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], cl
693
694 /* Check for V86 */
695 test dword ptr [esp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
696 jnz V86_Exit2
697
698 /* Check if the frame was edited */
699 V86_Exit_Return2:
700 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
701 jz EditedFrame2
702
703 /* Restore volatiles */
704 mov edx, [esp+KTRAP_FRAME_EDX]
705 mov ecx, [esp+KTRAP_FRAME_ECX]
706 mov eax, [esp+KTRAP_FRAME_EAX]
707
708 /* Check if it was kernel */
709 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
710 jz CommonStackClean2
711
712 /* Skip registers */
713 lea esp, [ebp+KTRAP_FRAME_GS]
714
715 /* Restore segments and volatiles */
716 pop gs
717 pop es
718 pop ds
719 lea esp, [ebp+KTRAP_FRAME_FS]
720 pop fs
721
722 CommonStackClean2:
723 /* Skip debug information and unsaved registers */
724 lea esp, [ebp+KTRAP_FRAME_EDI]
725 pop edi
726 pop esi
727 pop ebx
728 pop ebp
729
730 /* Check for ABIOS */
731 cmp word ptr [esp+8], 0x80
732 ja AbiosExit
733
734 /* Pop error code and return */
735 add esp, 4
736 iret
737
738 V86_Exit2:
739 /* Move to EDX position */
740 add esp, KTRAP_FRAME_EDX
741
742 /* Restore volatiles */
743 pop edx
744 pop ecx
745 pop eax
746 jmp V86_Exit_Return
747
748 EditedFrame2:
749 /* Restore real CS value */
750 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
751 mov [esp+KTRAP_FRAME_CS], ebx
752
753 /*
754 * If ESP was modified, then a special interrupt exit stack
755 * must be created to "update" ESP's value in a legal manner
756 */
757 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
758 sub ebx, 0xC
759 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
760
761 /* Copy Interrupt Stack */
762 mov esi, [esp+KTRAP_FRAME_EFLAGS]
763 mov [ebx+8], esi
764 mov esi, [esp+KTRAP_FRAME_CS]
765 mov [ebx+4], esi
766 mov esi, [esp+KTRAP_FRAME_EIP]
767 mov [ebx], esi
768
769 /* Restore volatiles */
770 mov eax, [esp+KTRAP_FRAME_EAX]
771 mov edx, [esp+KTRAP_FRAME_EDX]
772 mov ecx, [esp+KTRAP_FRAME_ECX]
773
774 /* Return */
775 add esp, KTRAP_FRAME_EDI
776 pop edi
777 pop esi
778 pop ebx
779 pop ebp
780 mov esp, [esp]
781 iret
782
783 _KiDebugService:
784
785 /* Create the Trap Frame */
786 push 0
787 push ebp
788 push ebx
789 push esi
790 push edi
791 push fs
792
793 /* Switch to correct FS */
794 mov bx, KGDT_R0_PCR
795 mov fs, bx
796
797 /* Save Exception List */
798 push fs:[KPCR_EXCEPTION_LIST]
799
800 /* Traps don't need the previous mode */
801 sub esp, 4
802
803 /* Continue building the Trap Frame */
804 push eax
805 push ecx
806 push edx
807 push ds
808 push es
809 push gs
810 sub esp, 0x30
811
812 /* Switch Segments to Kernel */
813 mov ax, KGDT_R0_DATA
814 mov ds, ax
815 mov es, ax
816
817 /* Set up frame */
818 mov ebp, esp
819
820 /* Check if this was from V86 Mode */
821 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
822 //jnz V86_kids
823
824 /* Get current thread */
825 mov ecx, [fs:KPCR_CURRENT_THREAD]
826 cld
827
828 /* Flush DR7 */
829 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
830
831 /* Check if the thread was being debugged */
832 test byte ptr [ecx+KTHREAD_DEBUG_ACTIVE], 0xFF
833 //jnz Dr_kids
834
835 /* Get the Debug Trap Frame EBP/EIP */
836 mov ebx, [ebp+KTRAP_FRAME_EBP]
837 mov edi, [ebp+KTRAP_FRAME_EIP]
838
839 /* Write the debug data */
840 mov [ebp+KTRAP_FRAME_DEBUGPOINTER], edx
841 mov dword ptr [ebp+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
842 mov [ebp+KTRAP_FRAME_DEBUGEBP], ebx
843 mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
844
845 /* Increase EIP so we skip the INT3 */
846 //inc dword ptr [ebp+KTRAP_FRAME_EIP]
847
848 /* Call debug service dispatcher */
849 mov eax, [ebp+KTRAP_FRAME_EAX]
850 mov ecx, [ebp+KTRAP_FRAME_ECX]
851 mov edx, [ebp+KTRAP_FRAME_EAX]
852
853 /* Check for V86 mode */
854 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
855 jnz NotUserMode
856
857 /* Check if this is kernel or user-mode */
858 test byte ptr [ebp+KTRAP_FRAME_CS], 1
859 jz CallDispatch
860 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
861 jnz NotUserMode
862
863 /* Re-enable interrupts */
864 VdmProc:
865 sti
866
867 /* Call the debug routine */
868 CallDispatch:
869 mov esi, ecx
870 mov edi, edx
871 mov edx, eax
872 mov ecx, 3
873 push edi
874 push esi
875 push edx
876 call _KdpServiceDispatcher@12
877
878 NotUserMode:
879
880 /* Get the current process */
881 mov ebx, [fs:KPCR_CURRENT_THREAD]
882 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
883
884 /* Check if this is a VDM Process */
885 //cmp dword ptr [ebx+KPROCESS_VDM_OBJECTS], 0
886 //jz VdmProc
887
888 /* Exit through common routine */
889 jmp Kei386EoiHelper@0
890
891 Kei386EoiHelper@0:
892
893 /* Disable interrupts */
894 cli
895
896 /* Check for V86 mode */
897 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
898 jnz ApcLoop3
899
900 /* Deliver APCs only if we were called from user mode */
901 test byte ptr [ebp+KTRAP_FRAME_CS], 1
902 je KiRosTrapReturn3
903
904 /* Get the current thread */
905 ApcLoop3:
906 mov ebx, [fs:KPCR_CURRENT_THREAD]
907
908 /* Make it non-alerted */
909 mov byte ptr [ebx+KTHREAD_ALERTED], 0
910
911 /* And only if any are actually pending */
912 cmp byte ptr [ebx+KTHREAD_PENDING_USER_APC], 0
913 je KiRosTrapReturn3
914
915 /* Save pointer to Trap Frame */
916 mov ebx, ebp
917
918 /* Raise IRQL to APC_LEVEL */
919 mov ecx, 1
920 call @KfRaiseIrql@4
921
922 /* Save old IRQL */
923 push eax
924
925 /* Deliver APCs */
926 sti
927 push ebx
928 push 0
929 push UserMode
930 call _KiDeliverApc@12
931
932 /* Return to old IRQL */
933 pop ecx
934 call @KfLowerIrql@4
935 cli
936 jmp ApcLoop3
937
938 KiRosTrapReturn3:
939
940 /* Restore exception list */
941 mov edx, [esp+KTRAP_FRAME_EXCEPTION_LIST]
942 mov [fs:KPCR_EXCEPTION_LIST], edx
943
944 /* Check for V86 */
945 test dword ptr [esp+KTRAP_FRAME_EFLAGS], X86_EFLAGS_VM
946 jnz V86_Exit3
947
948 /* Check if the frame was edited */
949 V86_Exit_Return3:
950 test word ptr [esp+KTRAP_FRAME_CS], FRAME_EDITED
951 jz EditedFrame3
952
953 /* Restore volatiles */
954 mov edx, [esp+KTRAP_FRAME_EDX]
955 mov ecx, [esp+KTRAP_FRAME_ECX]
956 mov eax, [esp+KTRAP_FRAME_EAX]
957
958 /* Check if it was kernel */
959 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
960 jz CommonStackClean3
961
962 /* Skip registers */
963 lea esp, [ebp+KTRAP_FRAME_GS]
964
965 /* Restore segments and volatiles */
966 pop gs
967 pop es
968 pop ds
969 lea esp, [ebp+KTRAP_FRAME_FS]
970 pop fs
971
972 CommonStackClean3:
973 /* Skip debug information and unsaved registers */
974 lea esp, [ebp+KTRAP_FRAME_EDI]
975 pop edi
976 pop esi
977 pop ebx
978 pop ebp
979
980 /* Check for ABIOS */
981 cmp word ptr [esp+8], 0x80
982 ja AbiosExit
983
984 /* Pop error code and return */
985 add esp, 4
986 iret
987
988 V86_Exit3:
989 /* Move to EDX position */
990 add esp, KTRAP_FRAME_EDX
991
992 /* Restore volatiles */
993 pop edx
994 pop ecx
995 pop eax
996 jmp V86_Exit_Return
997
998 EditedFrame3:
999 /* Restore real CS value */
1000 mov ebx, [esp+KTRAP_FRAME_TEMPCS]
1001 mov [esp+KTRAP_FRAME_CS], ebx
1002
1003 /*
1004 * If ESP was modified, then a special interrupt exit stack
1005 * must be created to "update" ESP's value in a legal manner
1006 */
1007 mov ebx, [esp+KTRAP_FRAME_TEMPESP]
1008 sub ebx, 0xC
1009 mov [esp+KTRAP_FRAME_ERROR_CODE], ebx
1010
1011 /* Copy Interrupt Stack */
1012 mov esi, [esp+KTRAP_FRAME_EFLAGS]
1013 mov [ebx+8], esi
1014 mov esi, [esp+KTRAP_FRAME_CS]
1015 mov [ebx+4], esi
1016 mov esi, [esp+KTRAP_FRAME_EIP]
1017 mov [ebx], esi
1018
1019 /* Restore volatiles */
1020 mov eax, [esp+KTRAP_FRAME_EAX]
1021 mov edx, [esp+KTRAP_FRAME_EDX]
1022 mov ecx, [esp+KTRAP_FRAME_ECX]
1023
1024 /* Return */
1025 add esp, KTRAP_FRAME_EDI
1026 pop edi
1027 pop esi
1028 pop ebx
1029 pop ebp
1030 mov esp, [esp]
1031 iret
1032
1033 .globl _NtRaiseException@12
1034 _NtRaiseException@12:
1035
1036 /* NOTE: We -must- be called by Zw* to have the right frame! */
1037 /* Push the stack frame */
1038 push ebp
1039
1040 /* Get the current thread and restore its trap frame */
1041 mov ebx, [fs:KPCR_CURRENT_THREAD]
1042 mov edx, [ebp+KTRAP_FRAME_EDX]
1043 mov [ebx+KTHREAD_TRAP_FRAME], edx
1044
1045 /* Set up stack frame */
1046 mov ebp, esp
1047
1048 /* Get the Trap Frame in EBX */
1049 mov ebx, [ebp+0]
1050
1051 /* Get the exception list and restore */
1052 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
1053 mov [fs:KPCR_EXCEPTION_LIST], eax
1054
1055 /* Get the parameters */
1056 mov edx, [ebp+16] /* Search frames */
1057 mov ecx, [ebp+12] /* Context */
1058 mov eax, [ebp+8] /* Exception Record */
1059
1060 /* Raise the exception */
1061 push edx
1062 push ebx
1063 push 0
1064 push ecx
1065 push eax
1066 call _KiRaiseException@20
1067
1068 /* Restore trap frame in EBP */
1069 pop ebp
1070 mov esp, ebp
1071
1072 /* Check the result */
1073 or eax, eax
1074 jz _KiServiceExit2
1075
1076 /* Restore debug registers too */
1077 jmp _KiServiceExit
1078
1079 .globl _NtContinue@8
1080 _NtContinue@8:
1081
1082 /* NOTE: We -must- be called by Zw* to have the right frame! */
1083 /* Push the stack frame */
1084 push ebp
1085
1086 /* Get the current thread and restore its trap frame */
1087 mov ebx, [fs:KPCR_CURRENT_THREAD]
1088 mov edx, [ebp+KTRAP_FRAME_EDX]
1089 mov [ebx+KTHREAD_TRAP_FRAME], edx
1090
1091 /* Set up stack frame */
1092 mov ebp, esp
1093
1094 /* Save the parameters */
1095 mov eax, [ebp+0]
1096 mov ecx, [ebp+8]
1097
1098 /* Call KiContinue */
1099 push eax
1100 push 0
1101 push ecx
1102 call _KiContinue@12
1103
1104 /* Check if we failed (bad context record) */
1105 or eax, eax
1106 jnz Error
1107
1108 /* Check if test alert was requested */
1109 cmp dword ptr [ebp+12], 0
1110 je DontTest
1111
1112 /* Test alert for the thread */
1113 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
1114 push eax
1115 call _KeTestAlertThread@4
1116
1117 DontTest:
1118 /* Return to previous context */
1119 pop ebp
1120 mov esp, ebp
1121 jmp _KiServiceExit2
1122
1123 Error:
1124 pop ebp
1125 mov esp, ebp
1126 jmp _KiServiceExit
1127