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