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