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