[HEADERS]
[reactos.git] / reactos / ntoskrnl / ke / i386 / traphdlr.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/i386/traphdlr.c
5 * PURPOSE: Kernel Trap Handlers
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 UCHAR KiTrapPrefixTable[] =
18 {
19 0xF2, /* REP */
20 0xF3, /* REP INS/OUTS */
21 0x67, /* ADDR */
22 0xF0, /* LOCK */
23 0x66, /* OP */
24 0x2E, /* SEG */
25 0x3E, /* DS */
26 0x26, /* ES */
27 0x64, /* FS */
28 0x65, /* GS */
29 0x36, /* SS */
30 };
31
32 UCHAR KiTrapIoTable[] =
33 {
34 0xE4, /* IN */
35 0xE5, /* IN */
36 0xEC, /* IN */
37 0xED, /* IN */
38 0x6C, /* INS */
39 0x6D, /* INS */
40 0xE6, /* OUT */
41 0xE7, /* OUT */
42 0xEE, /* OUT */
43 0xEF, /* OUT */
44 0x6E, /* OUTS */
45 0x6F, /* OUTS */
46 };
47
48 BOOLEAN
49 FORCEINLINE
50 KiVdmTrap(IN PKTRAP_FRAME TrapFrame)
51 {
52 /* Either the V8086 flag is on, or this is user-mode with a VDM */
53 return ((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
54 ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects)));
55 }
56
57 BOOLEAN
58 FORCEINLINE
59 KiV86Trap(IN PKTRAP_FRAME TrapFrame)
60 {
61 /* Check if the V8086 flag is on */
62 return ((TrapFrame->EFlags & EFLAGS_V86_MASK) != 0);
63 }
64
65 /* TRAP EXIT CODE *************************************************************/
66
67 VOID
68 FASTCALL
69 DECLSPEC_NORETURN
70 KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
71 {
72 /* Disable interrupts until we return */
73 _disable();
74
75 /* Check for APC delivery */
76 KiCheckForApcDelivery(TrapFrame);
77
78 /* Now exit the trap for real */
79 KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT);
80 }
81
82 VOID
83 FASTCALL
84 DECLSPEC_NORETURN
85 KiServiceExit(IN PKTRAP_FRAME TrapFrame,
86 IN NTSTATUS Status)
87 {
88 /* Disable interrupts until we return */
89 _disable();
90
91 /* Check for APC delivery */
92 KiCheckForApcDelivery(TrapFrame);
93
94 /* Copy the status into EAX */
95 TrapFrame->Eax = Status;
96
97 /* Now exit the trap for real */
98 KiExitTrap(TrapFrame, KTE_SKIP_SEG_BIT | KTE_SKIP_VOL_BIT);
99 }
100
101 VOID
102 FASTCALL
103 DECLSPEC_NORETURN
104 KiServiceExit2(IN PKTRAP_FRAME TrapFrame)
105 {
106 /* Disable interrupts until we return */
107 _disable();
108
109 /* Check for APC delivery */
110 KiCheckForApcDelivery(TrapFrame);
111
112 /* Now exit the trap for real */
113 KiExitTrap(TrapFrame, 0);
114 }
115
116 /* TRAP HANDLERS **************************************************************/
117
118 VOID
119 FASTCALL
120 DECLSPEC_NORETURN
121 KiDebugHandler(IN PKTRAP_FRAME TrapFrame,
122 IN ULONG Parameter1,
123 IN ULONG Parameter2,
124 IN ULONG Parameter3)
125 {
126 /* Check for VDM trap */
127 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
128
129 /* Enable interrupts if the trap came from user-mode */
130 if (KiUserTrap(TrapFrame)) _enable();
131
132 /* Dispatch the exception */
133 KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT,
134 TrapFrame->Eip - 1,
135 3,
136 Parameter1,
137 Parameter2,
138 Parameter3,
139 TrapFrame);
140 }
141
142 VOID
143 FASTCALL
144 DECLSPEC_NORETURN
145 KiNpxHandler(IN PKTRAP_FRAME TrapFrame,
146 IN PKTHREAD Thread,
147 IN PFX_SAVE_AREA SaveArea)
148 {
149 ULONG Cr0, Mask, Error, ErrorOffset, DataOffset;
150
151 /* Check for VDM trap */
152 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
153
154 /* Check for kernel trap */
155 if (!KiUserTrap(TrapFrame))
156 {
157 /* Kernel might've tripped a delayed error */
158 SaveArea->Cr0NpxState |= CR0_TS;
159
160 /* Only valid if it happened during a restore */
161 //if ((PVOID)TrapFrame->Eip == FrRestore)
162 {
163 /* It did, so just skip the instruction */
164 //TrapFrame->Eip += 3; /* sizeof(FRSTOR) */
165 //KiEoiHelper(TrapFrame);
166 }
167 }
168
169 /* User or kernel trap -- get ready to issue an exception */
170 if (Thread->NpxState == NPX_STATE_NOT_LOADED)
171 {
172 /* Update CR0 */
173 Cr0 = __readcr0();
174 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
175 __writecr0(Cr0);
176
177 /* Save FPU state */
178 //Ke386SaveFpuState(SaveArea);
179
180 /* Mark CR0 state dirty */
181 Cr0 |= NPX_STATE_NOT_LOADED;
182 Cr0 |= SaveArea->Cr0NpxState;
183 __writecr0(Cr0);
184
185 /* Update NPX state */
186 Thread->NpxState = NPX_STATE_NOT_LOADED;
187 KeGetCurrentPrcb()->NpxThread = NULL;
188 }
189
190 /* Clear the TS bit and re-enable interrupts */
191 SaveArea->Cr0NpxState &= ~CR0_TS;
192 _enable();
193
194 /* Check if we should get the FN or FX error */
195 if (KeI386FxsrPresent)
196 {
197 /* Get it from FX */
198 Mask = SaveArea->U.FxArea.ControlWord;
199 Error = SaveArea->U.FxArea.StatusWord;
200
201 /* Get the FPU exception address too */
202 ErrorOffset = SaveArea->U.FxArea.ErrorOffset;
203 DataOffset = SaveArea->U.FxArea.DataOffset;
204 }
205 else
206 {
207 /* Get it from FN */
208 Mask = SaveArea->U.FnArea.ControlWord;
209 Error = SaveArea->U.FnArea.StatusWord;
210
211 /* Get the FPU exception address too */
212 ErrorOffset = SaveArea->U.FnArea.ErrorOffset;
213 DataOffset = SaveArea->U.FnArea.DataOffset;
214 }
215
216 /* Get legal exceptions that software should handle */
217 Error &= (FSW_INVALID_OPERATION |
218 FSW_DENORMAL |
219 FSW_ZERO_DIVIDE |
220 FSW_OVERFLOW |
221 FSW_UNDERFLOW |
222 FSW_PRECISION);
223 Error &= ~Mask;
224
225 if (Error & FSW_STACK_FAULT)
226 {
227 /* Issue stack check fault */
228 KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK,
229 ErrorOffset,
230 0,
231 DataOffset,
232 TrapFrame);
233 }
234
235 /* Check for invalid operation */
236 if (Error & FSW_INVALID_OPERATION)
237 {
238 /* Issue fault */
239 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
240 ErrorOffset,
241 0,
242 TrapFrame);
243 }
244
245 /* Check for divide by zero */
246 if (Error & FSW_ZERO_DIVIDE)
247 {
248 /* Issue fault */
249 KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO,
250 ErrorOffset,
251 0,
252 TrapFrame);
253 }
254
255 /* Check for denormal */
256 if (Error & FSW_DENORMAL)
257 {
258 /* Issue fault */
259 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
260 ErrorOffset,
261 0,
262 TrapFrame);
263 }
264
265 /* Check for overflow */
266 if (Error & FSW_OVERFLOW)
267 {
268 /* Issue fault */
269 KiDispatchException1Args(STATUS_FLOAT_OVERFLOW,
270 ErrorOffset,
271 0,
272 TrapFrame);
273 }
274
275 /* Check for underflow */
276 if (Error & FSW_UNDERFLOW)
277 {
278 /* Issue fault */
279 KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW,
280 ErrorOffset,
281 0,
282 TrapFrame);
283 }
284
285 /* Check for precision fault */
286 if (Error & FSW_PRECISION)
287 {
288 /* Issue fault */
289 KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT,
290 ErrorOffset,
291 0,
292 TrapFrame);
293 }
294
295 /* Unknown FPU fault */
296 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 1, Error, 0, 0, TrapFrame);
297 }
298
299 VOID
300 FASTCALL
301 DECLSPEC_NORETURN
302 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame)
303 {
304 /* Save trap frame */
305 KiEnterTrap(TrapFrame);
306
307 /* Check for VDM trap */
308 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
309
310 /* Enable interrupts */
311 _enable();
312
313 /* Dispatch the exception */
314 KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO,
315 TrapFrame->Eip,
316 TrapFrame);
317 }
318
319 VOID
320 FASTCALL
321 DECLSPEC_NORETURN
322 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame)
323 {
324 /* Save trap frame */
325 KiEnterTrap(TrapFrame);
326
327 /* Check for VDM trap */
328 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
329
330 /* Enable interrupts if the trap came from user-mode */
331 if (KiUserTrap(TrapFrame)) _enable();
332
333 /* Mask out trap flag and dispatch the exception */
334 TrapFrame->EFlags &= ~EFLAGS_TF;
335 KiDispatchException0Args(STATUS_SINGLE_STEP,
336 TrapFrame->Eip,
337 TrapFrame);
338 }
339
340 VOID
341 DECLSPEC_NORETURN
342 KiTrap02(VOID)
343 {
344 PKTSS Tss, NmiTss;
345 PKTHREAD Thread;
346 PKPROCESS Process;
347 PKGDTENTRY TssGdt;
348 KTRAP_FRAME TrapFrame;
349 KIRQL OldIrql;
350
351 //
352 // In some sort of strange recursion case, we might end up here with the IF
353 // flag incorrectly on the interrupt frame -- during a normal NMI this would
354 // normally already be set.
355 //
356 // For sanity's sake, make sure interrupts are disabled for sure.
357 // NMIs will already be since the CPU does it for us.
358 //
359 _disable();
360
361 //
362 // Get the current TSS, thread, and process
363 //
364 Tss = PCR->TSS;
365 Thread = ((PKIPCR)PCR)->PrcbData.CurrentThread;
366 Process = Thread->ApcState.Process;
367
368 //
369 // Save data usually not in the TSS
370 //
371 Tss->CR3 = Process->DirectoryTableBase[0];
372 Tss->IoMapBase = Process->IopmOffset;
373 Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0;
374
375 //
376 // Now get the base address of the NMI TSS
377 //
378 TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)];
379 NmiTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow |
380 TssGdt->HighWord.Bytes.BaseMid << 16 |
381 TssGdt->HighWord.Bytes.BaseHi << 24);
382
383 //
384 // Switch to it and activate it, masking off the nested flag
385 //
386 // Note that in reality, we are already on the NMI tss -- we just need to
387 // update the PCR to reflect this
388 //
389 PCR->TSS = NmiTss;
390 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK);
391 TssGdt->HighWord.Bits.Dpl = 0;
392 TssGdt->HighWord.Bits.Pres = 1;
393 TssGdt->HighWord.Bits.Type = I386_TSS;
394
395 //
396 // Now build the trap frame based on the original TSS
397 //
398 // The CPU does a hardware "Context switch" / task switch of sorts and so it
399 // takes care of saving our context in the normal TSS.
400 //
401 // We just have to go get the values...
402 //
403 RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME));
404 TrapFrame.HardwareSegSs = Tss->Ss0;
405 TrapFrame.HardwareEsp = Tss->Esp0;
406 TrapFrame.EFlags = Tss->EFlags;
407 TrapFrame.SegCs = Tss->Cs;
408 TrapFrame.Eip = Tss->Eip;
409 TrapFrame.Ebp = Tss->Ebp;
410 TrapFrame.Ebx = Tss->Ebx;
411 TrapFrame.Esi = Tss->Esi;
412 TrapFrame.Edi = Tss->Edi;
413 TrapFrame.SegFs = Tss->Fs;
414 TrapFrame.ExceptionList = PCR->NtTib.ExceptionList;
415 TrapFrame.PreviousPreviousMode = -1;
416 TrapFrame.Eax = Tss->Eax;
417 TrapFrame.Ecx = Tss->Ecx;
418 TrapFrame.Edx = Tss->Edx;
419 TrapFrame.SegDs = Tss->Ds;
420 TrapFrame.SegEs = Tss->Es;
421 TrapFrame.SegGs = Tss->Gs;
422 TrapFrame.DbgEip = Tss->Eip;
423 TrapFrame.DbgEbp = Tss->Ebp;
424
425 //
426 // Store the trap frame in the KPRCB
427 //
428 KiSaveProcessorState(&TrapFrame, NULL);
429
430 //
431 // Call any registered NMI handlers and see if they handled it or not
432 //
433 if (!KiHandleNmi())
434 {
435 //
436 // They did not, so call the platform HAL routine to bugcheck the system
437 //
438 // Make sure the HAL believes it's running at HIGH IRQL... we can't use
439 // the normal APIs here as playing with the IRQL could change the system
440 // state
441 //
442 OldIrql = PCR->Irql;
443 PCR->Irql = HIGH_LEVEL;
444 HalHandleNMI(NULL);
445 PCR->Irql = OldIrql;
446 }
447
448 //
449 // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
450 // totally changed things.
451 //
452 // We have to make sure we're still in our original NMI -- a nested NMI
453 // will point back to the NMI TSS, and in that case we're hosed.
454 //
455 if (PCR->TSS->Backlink != KGDT_NMI_TSS)
456 {
457 //
458 // Restore original TSS
459 //
460 PCR->TSS = Tss;
461
462 //
463 // Set it back to busy
464 //
465 TssGdt->HighWord.Bits.Dpl = 0;
466 TssGdt->HighWord.Bits.Pres = 1;
467 TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS;
468
469 //
470 // Restore nested flag
471 //
472 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK);
473
474 //
475 // Handled, return from interrupt
476 //
477 __asm__ __volatile__ ("iret\n");
478 }
479
480 //
481 // Unhandled: crash the system
482 //
483 KiSystemFatalException(EXCEPTION_NMI, NULL);
484 }
485
486 VOID
487 FASTCALL
488 DECLSPEC_NORETURN
489 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame)
490 {
491 /* Save trap frame */
492 KiEnterTrap(TrapFrame);
493
494 /* Continue with the common handler */
495 KiDebugHandler(TrapFrame, BREAKPOINT_BREAK, 0, 0);
496 }
497
498 VOID
499 FASTCALL
500 DECLSPEC_NORETURN
501 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame)
502 {
503 /* Save trap frame */
504 KiEnterTrap(TrapFrame);
505
506 /* Check for VDM trap */
507 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
508
509 /* Enable interrupts */
510 _enable();
511
512 /* Dispatch the exception */
513 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW,
514 TrapFrame->Eip - 1,
515 TrapFrame);
516 }
517
518 VOID
519 FASTCALL
520 DECLSPEC_NORETURN
521 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame)
522 {
523 /* Save trap frame */
524 KiEnterTrap(TrapFrame);
525
526 /* Check for VDM trap */
527 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
528
529 /* Check for kernel-mode fault */
530 if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_BOUND_CHECK, TrapFrame);
531
532 /* Enable interrupts */
533 _enable();
534
535 /* Dispatch the exception */
536 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED,
537 TrapFrame->Eip,
538 TrapFrame);
539 }
540
541 VOID
542 FASTCALL
543 DECLSPEC_NORETURN
544 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
545 {
546 PUCHAR Instruction;
547 ULONG i;
548 KIRQL OldIrql;
549
550 /* Check for V86 GPF */
551 if (__builtin_expect(KiV86Trap(TrapFrame), 1))
552 {
553 /* Enter V86 trap */
554 KiEnterV86Trap(TrapFrame);
555
556 /* Must be a VDM process */
557 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
558 {
559 /* Enable interrupts */
560 _enable();
561
562 /* Setup illegal instruction fault */
563 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
564 TrapFrame->Eip,
565 TrapFrame);
566 }
567
568 /* Go to APC level */
569 OldIrql = KfRaiseIrql(APC_LEVEL);
570 _enable();
571
572 /* Check for BOP */
573 if (!VdmDispatchBop(TrapFrame))
574 {
575 /* Should only happen in VDM mode */
576 UNIMPLEMENTED;
577 while (TRUE);
578 }
579
580 /* Bring IRQL back */
581 KfLowerIrql(OldIrql);
582 _disable();
583
584 /* Do a quick V86 exit if possible */
585 if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame);
586
587 /* Exit trap the slow way */
588 KiEoiHelper(TrapFrame);
589 }
590
591 /* Save trap frame */
592 KiEnterTrap(TrapFrame);
593
594 /* Enable interrupts */
595 Instruction = (PUCHAR)TrapFrame->Eip;
596 _enable();
597
598 /* Check for user trap */
599 if (KiUserTrap(TrapFrame))
600 {
601 /* FIXME: Use SEH */
602
603 /* Scan next 4 opcodes */
604 for (i = 0; i < 4; i++)
605 {
606 /* Check for LOCK instruction */
607 if (Instruction[i] == 0xF0)
608 {
609 /* Send invalid lock sequence exception */
610 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE,
611 TrapFrame->Eip,
612 TrapFrame);
613 }
614 }
615
616 /* FIXME: SEH ends here */
617 }
618
619 /* Kernel-mode or user-mode fault (but not LOCK) */
620 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
621 TrapFrame->Eip,
622 TrapFrame);
623
624 }
625
626 VOID
627 FASTCALL
628 DECLSPEC_NORETURN
629 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
630 {
631 PKTHREAD Thread, NpxThread;
632 PFX_SAVE_AREA SaveArea, NpxSaveArea;
633 ULONG Cr0;
634
635 /* Save trap frame */
636 KiEnterTrap(TrapFrame);
637
638 /* Try to handle NPX delay load */
639 while (TRUE)
640 {
641 /* Get the current thread */
642 Thread = KeGetCurrentThread();
643
644 /* Get the NPX frame */
645 SaveArea = KiGetThreadNpxArea(Thread);
646
647 /* Check if emulation is enabled */
648 if (SaveArea->Cr0NpxState & CR0_EM)
649 {
650 /* Not implemented */
651 UNIMPLEMENTED;
652 while (TRUE);
653 }
654
655 /* Save CR0 and check NPX state */
656 Cr0 = __readcr0();
657 if (Thread->NpxState != NPX_STATE_LOADED)
658 {
659 /* Update CR0 */
660 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
661 __writecr0(Cr0);
662
663 /* Get the NPX thread */
664 NpxThread = KeGetCurrentPrcb()->NpxThread;
665 if (NpxThread)
666 {
667 /* Get the NPX frame */
668 NpxSaveArea = KiGetThreadNpxArea(NpxThread);
669
670 /* Save FPU state */
671 //Ke386SaveFpuState(NpxSaveArea);
672
673 /* Update NPX state */
674 Thread->NpxState = NPX_STATE_NOT_LOADED;
675 }
676
677 /* Load FPU state */
678 //Ke386LoadFpuState(SaveArea);
679
680 /* Update NPX state */
681 Thread->NpxState = NPX_STATE_LOADED;
682 KeGetCurrentPrcb()->NpxThread = Thread;
683
684 /* Enable interrupts */
685 _enable();
686
687 /* Check if CR0 needs to be reloaded due to context switch */
688 if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame);
689
690 /* Otherwise, we need to reload CR0, disable interrupts */
691 _disable();
692
693 /* Reload CR0 */
694 Cr0 = __readcr0();
695 Cr0 |= SaveArea->Cr0NpxState;
696 __writecr0(Cr0);
697
698 /* Now restore interrupts and check for TS */
699 _enable();
700 if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame);
701
702 /* We're still here -- clear TS and try again */
703 __writecr0(__readcr0() &~ CR0_TS);
704 _disable();
705 }
706 else
707 {
708 /* This is an actual fault, not a lack of FPU state */
709 break;
710 }
711 }
712
713 /* TS should not be set */
714 if (Cr0 & CR0_TS)
715 {
716 /*
717 * If it's incorrectly set, then maybe the state is actually still valid
718 * but we could've lock track of that due to a BIOS call.
719 * Make sure MP is still set, which should verify the theory.
720 */
721 if (Cr0 & CR0_MP)
722 {
723 /* Indeed, the state is actually still valid, so clear TS */
724 __writecr0(__readcr0() &~ CR0_TS);
725 KiEoiHelper(TrapFrame);
726 }
727
728 /* Otherwise, something strange is going on */
729 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame);
730 }
731
732 /* It's not a delayed load, so process this trap as an NPX fault */
733 KiNpxHandler(TrapFrame, Thread, SaveArea);
734 }
735
736 VOID
737 FASTCALL
738 DECLSPEC_NORETURN
739 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame)
740 {
741 /* FIXME: Not handled */
742 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT, TrapFrame);
743 }
744
745 VOID
746 FASTCALL
747 DECLSPEC_NORETURN
748 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame)
749 {
750 /* Save trap frame */
751 KiEnterTrap(TrapFrame);
752
753 /* Enable interrupts and kill the system */
754 _enable();
755 KiSystemFatalException(EXCEPTION_NPX_OVERRUN, TrapFrame);
756 }
757
758 VOID
759 FASTCALL
760 DECLSPEC_NORETURN
761 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame)
762 {
763 /* Save trap frame */
764 KiEnterTrap(TrapFrame);
765
766 /* Check for VDM trap */
767 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
768
769 /* Kill the system */
770 KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
771 }
772
773 VOID
774 FASTCALL
775 DECLSPEC_NORETURN
776 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame)
777 {
778 /* Save trap frame */
779 KiEnterTrap(TrapFrame);
780
781 /* FIXME: Kill the system */
782 UNIMPLEMENTED;
783 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT, TrapFrame);
784 }
785
786 VOID
787 FASTCALL
788 DECLSPEC_NORETURN
789 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame)
790 {
791 /* Save trap frame */
792 KiEnterTrap(TrapFrame);
793
794 /* FIXME: Kill the system */
795 UNIMPLEMENTED;
796 KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame);
797 }
798
799 VOID
800 FASTCALL
801 DECLSPEC_NORETURN
802 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
803 {
804 ULONG i, j, Iopl;
805 BOOLEAN Privileged = FALSE;
806 PUCHAR Instructions;
807 UCHAR Instruction = 0;
808 KIRQL OldIrql;
809
810 /* Check for V86 GPF */
811 if (__builtin_expect(KiV86Trap(TrapFrame), 1))
812 {
813 /* Enter V86 trap */
814 KiEnterV86Trap(TrapFrame);
815
816 /* Must be a VDM process */
817 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
818 {
819 /* Enable interrupts */
820 _enable();
821
822 /* Setup illegal instruction fault */
823 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
824 TrapFrame->Eip,
825 TrapFrame);
826 }
827
828 /* Go to APC level */
829 OldIrql = KfRaiseIrql(APC_LEVEL);
830 _enable();
831
832 /* Handle the V86 opcode */
833 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0))
834 {
835 /* Should only happen in VDM mode */
836 UNIMPLEMENTED;
837 while (TRUE);
838 }
839
840 /* Bring IRQL back */
841 KfLowerIrql(OldIrql);
842 _disable();
843
844 /* Do a quick V86 exit if possible */
845 if (__builtin_expect(TrapFrame->EFlags & EFLAGS_V86_MASK, 1)) KiExitV86Trap(TrapFrame);
846
847 /* Exit trap the slow way */
848 KiEoiHelper(TrapFrame);
849 }
850
851 /* Save trap frame */
852 KiEnterTrap(TrapFrame);
853
854 /* Check for user-mode GPF */
855 if (KiUserTrap(TrapFrame))
856 {
857 /* Should not be VDM */
858 ASSERT(KiVdmTrap(TrapFrame) == FALSE);
859
860 /* Enable interrupts and check error code */
861 _enable();
862 if (!TrapFrame->ErrCode)
863 {
864 /* FIXME: Use SEH */
865 Instructions = (PUCHAR)TrapFrame->Eip;
866
867 /* Scan next 15 bytes */
868 for (i = 0; i < 15; i++)
869 {
870 /* Skip prefix instructions */
871 for (j = 0; j < sizeof(KiTrapPrefixTable); j++)
872 {
873 /* Is this a prefix instruction? */
874 if (Instructions[i] == KiTrapPrefixTable[j])
875 {
876 /* Stop looking */
877 break;
878 }
879 }
880
881 /* Is this NOT any prefix instruction? */
882 if (j == sizeof(KiTrapPrefixTable))
883 {
884 /* We can go ahead and handle the fault now */
885 Instruction = Instructions[i];
886 break;
887 }
888 }
889
890 /* If all we found was prefixes, then this instruction is too long */
891 if (i == 15)
892 {
893 /* Setup illegal instruction fault */
894 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
895 TrapFrame->Eip,
896 TrapFrame);
897 }
898
899 /* Check for privileged instructions */
900 if (Instruction == 0xF4) // HLT
901 {
902 /* HLT is privileged */
903 Privileged = TRUE;
904 }
905 else if (Instruction == 0x0F)
906 {
907 /* Test if it's any of the privileged two-byte opcodes */
908 if (((Instructions[i + 1] == 0x00) && // LLDT or LTR
909 (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT
910 (Instructions[i + 2] == 0x18))) || // LTR
911 ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW
912 (((Instructions[i + 2] & 0x38) == 0x10) || // LLGT
913 (Instructions[i + 2] == 0x18) || // LIDT
914 (Instructions[i + 2] == 0x30))) || // LMSW
915 (Instructions[i + 1] == 0x08) || // INVD
916 (Instructions[i + 1] == 0x09) || // WBINVD
917 (Instructions[i + 1] == 0x35) || // SYSEXIT
918 (Instructions[i + 1] == 0x26) || // MOV DR, XXX
919 (Instructions[i + 1] == 0x06) || // CLTS
920 (Instructions[i + 1] == 0x20) || // MOV CR, XXX
921 (Instructions[i + 1] == 0x24) || // MOV YYY, DR
922 (Instructions[i + 1] == 0x30) || // WRMSR
923 (Instructions[i + 1] == 0x33)) // RDPMC
924 {
925 /* These are all privileged */
926 Privileged = TRUE;
927 }
928 }
929 else
930 {
931 /* Get the IOPL and compare with the RPL mask */
932 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12;
933 if ((TrapFrame->SegCs & RPL_MASK) > Iopl)
934 {
935 /* I/O privilege error -- check for known instructions */
936 if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI
937 {
938 /* These are privileged */
939 Privileged = TRUE;
940 }
941 else
942 {
943 /* Last hope: an IN/OUT instruction */
944 for (j = 0; j < sizeof(KiTrapIoTable); j++)
945 {
946 /* Is this an I/O instruction? */
947 if (Instruction == KiTrapIoTable[j])
948 {
949 /* Then it's privileged */
950 Privileged = TRUE;
951 break;
952 }
953 }
954 }
955 }
956 }
957
958 /* So now... was the instruction privileged or not? */
959 if (Privileged)
960 {
961 /* Whew! We have a privileged instruction, so dispatch the fault */
962 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION,
963 TrapFrame->Eip,
964 TrapFrame);
965 }
966 }
967
968 /* If we got here, send an access violation */
969 KiDispatchException2Args(STATUS_ACCESS_VIOLATION,
970 TrapFrame->Eip,
971 0,
972 0xFFFFFFFF,
973 TrapFrame);
974 }
975
976 /*
977 * Check for a fault during checking of the user instruction.
978 *
979 * Note that the SEH handler will catch invalid EIP, but we could be dealing
980 * with an invalid CS, which will generate another GPF instead.
981 *
982 */
983 if (((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler) &&
984 ((PVOID)TrapFrame->Eip < (PVOID)KiTrap0DHandler))
985 {
986 /* Not implemented */
987 UNIMPLEMENTED;
988 while (TRUE);
989 }
990
991 /*
992 * NOTE: The ASM trap exit code would restore segment registers by doing
993 * a POP <SEG>, which could cause an invalid segment if someone had messed
994 * with the segment values.
995 *
996 * Another case is a bogus SS, which would hit a GPF when doing the ired.
997 * This could only be done through a buggy or malicious driver, or perhaps
998 * the kernel debugger.
999 *
1000 * The kernel normally restores the "true" segment if this happens.
1001 *
1002 * However, since we're restoring in C, not ASM, we can't detect
1003 * POP <SEG> since the actual instructions will be different.
1004 *
1005 * A better technique would be to check the EIP and somehow edit the
1006 * trap frame before restarting the instruction -- but we would need to
1007 * know the extract instruction that was used first.
1008 *
1009 * We could force a special instrinsic to use stack instructions, or write
1010 * a simple instruction length checker.
1011 *
1012 * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1013 * when the user is purposedly trying to create one from kernel-mode, so
1014 * we should probably table this for now since it's not a "real" issue.
1015 */
1016
1017 /*
1018 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1019 * which will cause a GPF since the trap frame is a total mess (on purpose)
1020 * as built in KiEnterV86Mode.
1021 *
1022 * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1023 * and then manually issue a jump to the V8086 return EIP.
1024 */
1025 Instructions = (PUCHAR)TrapFrame->Eip;
1026 if (Instructions[0] == 0xCF)
1027 {
1028 /*
1029 * Some evil shit is going on here -- this is not the SS:ESP you're
1030 * looking for! Instead, this is actually CS:EIP you're looking at!
1031 * Why? Because part of the trap frame actually corresponds to the IRET
1032 * stack during the trap exit!
1033 */
1034 if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) &&
1035 (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK)))
1036 {
1037 /* Exit the V86 trap! */
1038 Ki386BiosCallReturnAddress(TrapFrame);
1039 }
1040 else
1041 {
1042 /* Otherwise, this is another kind of IRET fault */
1043 UNIMPLEMENTED;
1044 while (TRUE);
1045 }
1046 }
1047
1048 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1049 if ((Instructions[0] == 0xF) && // 2-byte opcode
1050 (((Instructions[1] >> 8) == 0x30) || // RDMSR
1051 ((Instructions[2] >> 8) == 0x32))) // WRMSR
1052 {
1053 /* Unknown CPU MSR, so raise an access violation */
1054 KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
1055 TrapFrame->Eip,
1056 TrapFrame);
1057 }
1058
1059 /* Check for lazy segment load */
1060 if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK))
1061 {
1062 /* Fix it */
1063 TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK);
1064 }
1065 else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK))
1066 {
1067 /* Fix it */
1068 TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK);
1069 }
1070
1071 /* Do a direct trap exit: restore volatiles only */
1072 KiExitTrap(TrapFrame, KTE_SKIP_PM_BIT | KTE_SKIP_SEG_BIT);
1073 }
1074
1075 VOID
1076 FASTCALL
1077 DECLSPEC_NORETURN
1078 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
1079 {
1080 PKTHREAD Thread;
1081 ULONG_PTR Cr2;
1082 NTSTATUS Status;
1083
1084 /* Save trap frame */
1085 KiEnterTrap(TrapFrame);
1086
1087 /* Check if this is the base frame */
1088 Thread = KeGetCurrentThread();
1089 if (KeGetTrapFrame(Thread) != TrapFrame)
1090 {
1091 /* It isn't, check if this is a second nested frame */
1092 if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
1093 FIELD_OFFSET(KTRAP_FRAME, EFlags))
1094 {
1095 /* The stack is somewhere in between frames, we need to fix it */
1096 UNIMPLEMENTED;
1097 while (TRUE);
1098 }
1099 }
1100
1101 /* Save CR2 */
1102 Cr2 = __readcr2();
1103
1104 /* Check for Pentium LOCK errata */
1105 if (KiI386PentiumLockErrataPresent)
1106 {
1107 /* Not yet implemented */
1108 UNIMPLEMENTED;
1109 while (TRUE);
1110 }
1111
1112 /* HACK: Check if interrupts are disabled and enable them */
1113 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1114 {
1115 /* Enable interupts */
1116 _enable();
1117 #ifdef HACK_ABOVE_FIXED
1118 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1119 {
1120 /* This is illegal */
1121 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
1122 Cr2,
1123 -1,
1124 TrapFrame->ErrCode & 1,
1125 TrapFrame->Eip,
1126 TrapFrame);
1127 }
1128 #endif
1129 }
1130
1131 /* Call the access fault handler */
1132 Status = MmAccessFault(TrapFrame->ErrCode & 1,
1133 (PVOID)Cr2,
1134 TrapFrame->SegCs & MODE_MASK,
1135 TrapFrame);
1136 if (Status == STATUS_SUCCESS) KiEoiHelper(TrapFrame);
1137
1138 /* Check for S-LIST fault */
1139 if (TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault)
1140 {
1141 /* Not yet implemented */
1142 UNIMPLEMENTED;
1143 while (TRUE);
1144 }
1145
1146 /* Check for syscall fault */
1147 #if 0
1148 if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
1149 (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
1150 {
1151 /* Not yet implemented */
1152 UNIMPLEMENTED;
1153 while (TRUE);
1154 }
1155 #endif
1156 /* Check for VDM trap */
1157 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
1158
1159 /* Either kernel or user trap (non VDM) so dispatch exception */
1160 if (Status == STATUS_ACCESS_VIOLATION)
1161 {
1162 /* This status code is repurposed so we can recognize it later */
1163 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1164 TrapFrame->Eip,
1165 TrapFrame->ErrCode & 1,
1166 Cr2,
1167 TrapFrame);
1168 }
1169 else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
1170 (Status == STATUS_STACK_OVERFLOW))
1171 {
1172 /* These faults only have two parameters */
1173 KiDispatchException2Args(Status,
1174 TrapFrame->Eip,
1175 TrapFrame->ErrCode & 1,
1176 Cr2,
1177 TrapFrame);
1178 }
1179
1180 /* Only other choice is an in-page error, with 3 parameters */
1181 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
1182 TrapFrame->Eip,
1183 3,
1184 TrapFrame->ErrCode & 1,
1185 Cr2,
1186 Status,
1187 TrapFrame);
1188 }
1189
1190 VOID
1191 FASTCALL
1192 DECLSPEC_NORETURN
1193 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
1194 {
1195 /* Save trap frame */
1196 KiEnterTrap(TrapFrame);
1197
1198 /* FIXME: Kill the system */
1199 UNIMPLEMENTED;
1200 KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
1201 }
1202
1203 VOID
1204 FASTCALL
1205 DECLSPEC_NORETURN
1206 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
1207 {
1208 PKTHREAD Thread;
1209 PFX_SAVE_AREA SaveArea;
1210
1211 /* Save trap frame */
1212 KiEnterTrap(TrapFrame);
1213
1214 /* Check if this is the NPX thrad */
1215 Thread = KeGetCurrentThread();
1216 SaveArea = KiGetThreadNpxArea(Thread);
1217 if (Thread != KeGetCurrentPrcb()->NpxThread)
1218 {
1219 /* It isn't, enable interrupts and set delayed error */
1220 _enable();
1221 SaveArea->Cr0NpxState |= CR0_TS;
1222
1223 /* End trap */
1224 KiEoiHelper(TrapFrame);
1225 }
1226
1227 /* Otherwise, proceed with NPX fault handling */
1228 KiNpxHandler(TrapFrame, Thread, SaveArea);
1229 }
1230
1231 VOID
1232 FASTCALL
1233 DECLSPEC_NORETURN
1234 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
1235 {
1236 /* Save trap frame */
1237 KiEnterTrap(TrapFrame);
1238
1239 /* Enable interrupts and kill the system */
1240 _enable();
1241 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
1242 }
1243
1244 VOID
1245 FASTCALL
1246 DECLSPEC_NORETURN
1247 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
1248 {
1249 PKTHREAD Thread;
1250 PFX_SAVE_AREA SaveArea;
1251 ULONG Cr0, MxCsrMask, Error;
1252
1253 /* Save trap frame */
1254 KiEnterTrap(TrapFrame);
1255
1256 /* Check if this is the NPX thrad */
1257 Thread = KeGetCurrentThread();
1258 if (Thread != KeGetCurrentPrcb()->NpxThread)
1259 {
1260 /* It isn't, kill the system */
1261 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
1262 }
1263
1264 /* Get the NPX frame */
1265 SaveArea = KiGetThreadNpxArea(Thread);
1266
1267 /* Check for VDM trap */
1268 ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
1269
1270 /* Check for user trap */
1271 if (!KiUserTrap(TrapFrame))
1272 {
1273 /* Kernel should not fault on XMMI */
1274 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
1275 }
1276
1277 /* Update CR0 */
1278 Cr0 = __readcr0();
1279 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
1280 __writecr0(Cr0);
1281
1282 /* Save FPU state */
1283 //Ke386SaveFpuState(SaveArea);
1284
1285 /* Mark CR0 state dirty */
1286 Cr0 |= NPX_STATE_NOT_LOADED;
1287 Cr0 |= SaveArea->Cr0NpxState;
1288 __writecr0(Cr0);
1289
1290 /* Update NPX state */
1291 Thread->NpxState = NPX_STATE_NOT_LOADED;
1292 KeGetCurrentPrcb()->NpxThread = NULL;
1293
1294 /* Clear the TS bit and re-enable interrupts */
1295 SaveArea->Cr0NpxState &= ~CR0_TS;
1296 _enable();
1297
1298 /* Now look at MxCsr to get the mask of errors we should care about */
1299 MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
1300
1301 /* Get legal exceptions that software should handle */
1302 Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
1303 FSW_DENORMAL |
1304 FSW_ZERO_DIVIDE |
1305 FSW_OVERFLOW |
1306 FSW_UNDERFLOW |
1307 FSW_PRECISION);
1308 Error &= MxCsrMask;
1309
1310 /* Now handle any of those legal errors */
1311 if (Error & (FSW_INVALID_OPERATION |
1312 FSW_DENORMAL |
1313 FSW_ZERO_DIVIDE |
1314 FSW_OVERFLOW |
1315 FSW_UNDERFLOW |
1316 FSW_PRECISION))
1317 {
1318 /* By issuing an exception */
1319 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
1320 TrapFrame->Eip,
1321 0,
1322 TrapFrame);
1323 }
1324
1325 /* Unknown XMMI fault */
1326 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
1327 }
1328
1329 /* SOFTWARE SERVICES **********************************************************/
1330
1331 VOID
1332 FASTCALL
1333 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
1334 {
1335 UNIMPLEMENTED;
1336 while (TRUE);
1337 }
1338
1339 VOID
1340 FASTCALL
1341 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
1342 {
1343 UNIMPLEMENTED;
1344 while (TRUE);
1345 }
1346
1347 VOID
1348 FASTCALL
1349 DECLSPEC_NORETURN
1350 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
1351 {
1352 /* Save trap frame */
1353 KiEnterTrap(TrapFrame);
1354
1355 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1356 TrapFrame->Eip -= 2;
1357
1358 /* Dispatch the exception */
1359 KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
1360 TrapFrame->Eip,
1361 TrapFrame);
1362 }
1363
1364 VOID
1365 FASTCALL
1366 DECLSPEC_NORETURN
1367 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
1368 {
1369 /* Save trap frame */
1370 KiEnterTrap(TrapFrame);
1371
1372 /* Increment EIP to skip the INT3 instruction */
1373 TrapFrame->Eip++;
1374
1375 /* Continue with the common handler */
1376 KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1377 }
1378
1379 VOID
1380 FASTCALL
1381 DECLSPEC_NORETURN
1382 KiSystemCall(IN ULONG SystemCallNumber,
1383 IN PVOID Arguments)
1384 {
1385 PKTHREAD Thread;
1386 PKTRAP_FRAME TrapFrame;
1387 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
1388 ULONG Id, Offset, StackBytes, Result;
1389 PVOID Handler;
1390
1391 /* Loop because we might need to try this twice in case of a GUI call */
1392 while (TRUE)
1393 {
1394 /* Decode the system call number */
1395 Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
1396 Id = SystemCallNumber & SERVICE_NUMBER_MASK;
1397
1398 /* Get current thread, trap frame, and descriptor table */
1399 Thread = KeGetCurrentThread();
1400 TrapFrame = Thread->TrapFrame;
1401 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
1402
1403 /* Validate the system call number */
1404 if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
1405 {
1406 /* Check if this is a GUI call */
1407 if (__builtin_expect(!(Offset & SERVICE_TABLE_TEST), 0))
1408 {
1409 /* Fail the call */
1410 Result = STATUS_INVALID_SYSTEM_SERVICE;
1411 goto ExitCall;
1412 }
1413
1414 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1415 Result = KiConvertToGuiThread();
1416 if (__builtin_expect(!NT_SUCCESS(Result), 0))
1417 {
1418 /* Figure out how we should fail to the user */
1419 UNIMPLEMENTED;
1420 while (TRUE);
1421 }
1422
1423 /* Try the call again */
1424 continue;
1425 }
1426
1427 /* If we made it here, the call is good */
1428 break;
1429 }
1430
1431 /* Check if this is a GUI call */
1432 if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
1433 {
1434 /* Get the batch count and flush if necessary */
1435 if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
1436 }
1437
1438 /* Increase system call count */
1439 KeGetCurrentPrcb()->KeSystemCalls++;
1440
1441 /* FIXME: Increase individual counts on debug systems */
1442 //KiIncreaseSystemCallCount(DescriptorTable, Id);
1443
1444 /* Get stack bytes */
1445 StackBytes = DescriptorTable->Number[Id];
1446
1447 /* Probe caller stack */
1448 if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
1449 {
1450 /* Access violation */
1451 UNIMPLEMENTED;
1452 while (TRUE);
1453 }
1454
1455 /* Get the handler and make the system call */
1456 Handler = (PVOID)DescriptorTable->Base[Id];
1457 Result = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
1458
1459 /* Make sure we're exiting correctly */
1460 KiExitSystemCallDebugChecks(Id, TrapFrame);
1461
1462 /* Restore the old trap frame */
1463 ExitCall:
1464 Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
1465
1466 /* Exit from system call */
1467 KiServiceExit(TrapFrame, Result);
1468 }
1469
1470 VOID
1471 FORCEINLINE
1472 DECLSPEC_NORETURN
1473 KiSystemCallHandler(IN PKTRAP_FRAME TrapFrame,
1474 IN ULONG ServiceNumber,
1475 IN PVOID Arguments,
1476 IN PKTHREAD Thread,
1477 IN KPROCESSOR_MODE PreviousMode,
1478 IN KPROCESSOR_MODE PreviousPreviousMode,
1479 IN USHORT SegFs)
1480 {
1481 /* No error code */
1482 TrapFrame->ErrCode = 0;
1483
1484 /* Save previous mode and FS segment */
1485 TrapFrame->PreviousPreviousMode = PreviousPreviousMode;
1486 TrapFrame->SegFs = SegFs;
1487
1488 /* Save the SEH chain and terminate it for now */
1489 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1490 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
1491
1492 /* Clear DR7 and check for debugging */
1493 TrapFrame->Dr7 = 0;
1494 if (__builtin_expect(Thread->DispatcherHeader.DebugActive & 0xFF, 0))
1495 {
1496 UNIMPLEMENTED;
1497 while (TRUE);
1498 }
1499
1500 /* Set thread fields */
1501 Thread->TrapFrame = TrapFrame;
1502 Thread->PreviousMode = PreviousMode;
1503
1504 /* Set debug header */
1505 KiFillTrapFrameDebug(TrapFrame);
1506
1507 /* Enable interrupts and make the call */
1508 _enable();
1509 KiSystemCall(ServiceNumber, Arguments);
1510 }
1511
1512 VOID
1513 FASTCALL
1514 DECLSPEC_NORETURN
1515 KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame,
1516 IN PVOID Arguments)
1517 {
1518 PKTHREAD Thread;
1519
1520 /* Set up a fake INT Stack and enable interrupts */
1521 TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
1522 TrapFrame->HardwareEsp = (ULONG_PTR)Arguments;
1523 TrapFrame->EFlags = __readeflags() | EFLAGS_INTERRUPT_MASK;
1524 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
1525 TrapFrame->Eip = SharedUserData->SystemCallReturn;
1526 __writeeflags(0x2);
1527
1528 /* Get the current thread */
1529 Thread = KeGetCurrentThread();
1530
1531 /* Arguments are actually 2 frames down (because of the double indirection) */
1532 Arguments = (PVOID)(TrapFrame->HardwareEsp + 8);
1533
1534 /* Call the shared handler (inline) */
1535 KiSystemCallHandler(TrapFrame,
1536 TrapFrame->Eax,
1537 Arguments,
1538 Thread,
1539 UserMode,
1540 Thread->PreviousMode,
1541 KGDT_R3_TEB | RPL_MASK);
1542 }
1543
1544 VOID
1545 FASTCALL
1546 DECLSPEC_NORETURN
1547 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
1548 IN PVOID Arguments)
1549 {
1550 PKTHREAD Thread;
1551
1552 /* Get the current thread */
1553 Thread = KeGetCurrentThread();
1554
1555 /* Chain trap frames */
1556 TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
1557
1558 /* Call the shared handler (inline) */
1559 KiSystemCallHandler(TrapFrame,
1560 TrapFrame->Eax,
1561 Arguments,
1562 Thread,
1563 KiUserTrap(TrapFrame),
1564 Thread->PreviousMode,
1565 TrapFrame->SegFs);
1566 }
1567
1568 /*
1569 * @implemented
1570 */
1571 VOID
1572 NTAPI
1573 Kei386EoiHelper(VOID)
1574 {
1575 /* We should never see this call happening */
1576 DPRINT1("Mismatched NT/HAL version");
1577 while (TRUE);
1578 }
1579
1580 /* EOF */