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