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