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