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