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