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