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