xref: /reactos/ntoskrnl/ke/i386/traphdlr.c (revision 019f21ee)
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 VOID
459 __cdecl
460 KiTrap02Handler(VOID)
461 {
462     PKTSS Tss, NmiTss;
463     PKTHREAD Thread;
464     PKPROCESS Process;
465     PKGDTENTRY TssGdt;
466     KTRAP_FRAME TrapFrame;
467     KIRQL OldIrql;
468 
469     /*
470      * In some sort of strange recursion case, we might end up here with the IF
471      * flag incorrectly on the interrupt frame -- during a normal NMI this would
472      * normally already be set.
473      *
474      * For sanity's sake, make sure interrupts are disabled for sure.
475      * NMIs will already be since the CPU does it for us.
476      */
477     _disable();
478 
479     /* Get the current TSS, thread, and process */
480     Tss = KeGetPcr()->TSS;
481     Thread = ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread;
482     Process = Thread->ApcState.Process;
483 
484     /* Save data usually not present in the TSS */
485     Tss->CR3 = Process->DirectoryTableBase[0];
486     Tss->IoMapBase = Process->IopmOffset;
487     Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0;
488 
489     /* Now get the base address of the NMI TSS */
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
499      * need to update the PCR to reflect this.
500      */
501     KeGetPcr()->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
511      * and so it 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 = KeGetPcr()->NtTib.ExceptionList;
527     TrapFrame.PreviousPreviousMode = (ULONG)-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     /* Store the trap frame in the KPRCB */
538     KiSaveProcessorState(&TrapFrame, NULL);
539 
540     /* Call any registered NMI handlers and see if they handled it or not */
541     if (!KiHandleNmi())
542     {
543         /*
544          * They did not, so call the platform HAL routine to bugcheck the system
545          *
546          * Make sure the HAL believes it's running at HIGH IRQL... we can't use
547          * the normal APIs here as playing with the IRQL could change the system
548          * state.
549          */
550         OldIrql = KeGetPcr()->Irql;
551         KeGetPcr()->Irql = HIGH_LEVEL;
552         HalHandleNMI(NULL);
553         KeGetPcr()->Irql = OldIrql;
554     }
555 
556     /*
557      * Although the CPU disabled NMIs, we just did a BIOS call, which could've
558      * totally changed things.
559      *
560      * We have to make sure we're still in our original NMI -- a nested NMI
561      * will point back to the NMI TSS, and in that case we're hosed.
562      */
563     if (KeGetPcr()->TSS->Backlink == KGDT_NMI_TSS)
564     {
565         /* Unhandled: crash the system */
566         KiSystemFatalException(EXCEPTION_NMI, NULL);
567     }
568 
569     /* Restore original TSS */
570     KeGetPcr()->TSS = Tss;
571 
572     /* Set it back to busy */
573     TssGdt->HighWord.Bits.Dpl = 0;
574     TssGdt->HighWord.Bits.Pres = 1;
575     TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS;
576 
577     /* Restore nested flag */
578     __writeeflags(__readeflags() | EFLAGS_NESTED_TASK);
579 
580     /* Handled, return from interrupt */
581 }
582 
583 DECLSPEC_NORETURN
584 VOID
585 FASTCALL
586 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame)
587 {
588     /* Save trap frame */
589     KiEnterTrap(TrapFrame);
590 
591     /* Continue with the common handler */
592     KiDebugHandler(TrapFrame, BREAKPOINT_BREAK, 0, 0);
593 }
594 
595 DECLSPEC_NORETURN
596 VOID
597 FASTCALL
598 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame)
599 {
600     /* Save trap frame */
601     KiEnterTrap(TrapFrame);
602 
603     /* Check for VDM trap */
604     ASSERT(KiVdmTrap(TrapFrame) == FALSE);
605 
606      /* Enable interrupts */
607     _enable();
608 
609     /* Dispatch the exception */
610     KiDispatchException0Args(STATUS_INTEGER_OVERFLOW,
611                              TrapFrame->Eip - 1,
612                              TrapFrame);
613 }
614 
615 DECLSPEC_NORETURN
616 VOID
617 FASTCALL
618 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame)
619 {
620     /* Save trap frame */
621     KiEnterTrap(TrapFrame);
622 
623     /* Check for VDM trap */
624     ASSERT(KiVdmTrap(TrapFrame) == FALSE);
625 
626     /* Check for kernel-mode fault */
627     if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_BOUND_CHECK, TrapFrame);
628 
629     /* Enable interrupts */
630     _enable();
631 
632     /* Dispatch the exception */
633     KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED,
634                              TrapFrame->Eip,
635                              TrapFrame);
636 }
637 
638 DECLSPEC_NORETURN
639 VOID
640 FASTCALL
641 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
642 {
643     PUCHAR Instruction;
644     ULONG i;
645     KIRQL OldIrql;
646 
647     /* Check for V86 GPF */
648     if (__builtin_expect(KiV86Trap(TrapFrame), 1))
649     {
650         /* Enter V86 trap */
651         KiEnterV86Trap(TrapFrame);
652 
653         /* Must be a VDM process */
654         if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
655         {
656             /* Enable interrupts */
657             _enable();
658 
659             /* Setup illegal instruction fault */
660             KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
661                                      TrapFrame->Eip,
662                                      TrapFrame);
663         }
664 
665         /* Go to APC level */
666         KeRaiseIrql(APC_LEVEL, &OldIrql);
667         _enable();
668 
669         /* Check for BOP */
670         if (!VdmDispatchBop(TrapFrame))
671         {
672             /* Should only happen in VDM mode */
673             UNIMPLEMENTED_FATAL();
674         }
675 
676         /* Bring IRQL back */
677         KeLowerIrql(OldIrql);
678         _disable();
679 
680         /* Do a quick V86 exit if possible */
681         KiExitV86Trap(TrapFrame);
682     }
683 
684     /* Save trap frame */
685     KiEnterTrap(TrapFrame);
686 
687     /* Enable interrupts */
688     Instruction = (PUCHAR)TrapFrame->Eip;
689     _enable();
690 
691     /* Check for user trap */
692     if (KiUserTrap(TrapFrame))
693     {
694         /* FIXME: Use SEH */
695 
696         /* Scan next 4 opcodes */
697         for (i = 0; i < 4; i++)
698         {
699             /* Check for LOCK instruction */
700             if (Instruction[i] == 0xF0)
701             {
702                 /* Send invalid lock sequence exception */
703                 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE,
704                                          TrapFrame->Eip,
705                                          TrapFrame);
706             }
707         }
708 
709         /* FIXME: SEH ends here */
710     }
711 
712     /* Kernel-mode or user-mode fault (but not LOCK) */
713     KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
714                              TrapFrame->Eip,
715                              TrapFrame);
716 
717 }
718 
719 DECLSPEC_NORETURN
720 VOID
721 FASTCALL
722 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
723 {
724     PKTHREAD Thread, NpxThread;
725     PFX_SAVE_AREA SaveArea, NpxSaveArea;
726     ULONG Cr0;
727 
728     /* Save trap frame */
729     KiEnterTrap(TrapFrame);
730 
731     /* Try to handle NPX delay load */
732     for (;;)
733     {
734         /* Get the current thread */
735         Thread = KeGetCurrentThread();
736 
737         /* Get the NPX frame */
738         SaveArea = KiGetThreadNpxArea(Thread);
739 
740         /* Check if emulation is enabled */
741         if (SaveArea->Cr0NpxState & CR0_EM)
742         {
743             /* Not implemented */
744             UNIMPLEMENTED_FATAL();
745         }
746 
747         /* Save CR0 and check NPX state */
748         Cr0 = __readcr0();
749         if (Thread->NpxState != NPX_STATE_LOADED)
750         {
751             /* Update CR0 */
752             Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
753             __writecr0(Cr0);
754 
755             /* Get the NPX thread */
756             NpxThread = KeGetCurrentPrcb()->NpxThread;
757             if (NpxThread)
758             {
759                 /* Get the NPX frame */
760                 NpxSaveArea = KiGetThreadNpxArea(NpxThread);
761 
762                 /* Save FPU state */
763                 Ke386SaveFpuState(NpxSaveArea);
764 
765                 /* Update NPX state */
766                 NpxThread->NpxState = NPX_STATE_NOT_LOADED;
767            }
768 
769             /* Load FPU state */
770             Ke386LoadFpuState(SaveArea);
771 
772             /* Update NPX state */
773             Thread->NpxState = NPX_STATE_LOADED;
774             KeGetCurrentPrcb()->NpxThread = Thread;
775 
776             /* Enable interrupts */
777             _enable();
778 
779             /* Check if CR0 needs to be reloaded due to context switch */
780             if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame);
781 
782             /* Otherwise, we need to reload CR0, disable interrupts */
783             _disable();
784 
785             /* Reload CR0 */
786             Cr0 = __readcr0();
787             Cr0 |= SaveArea->Cr0NpxState;
788             __writecr0(Cr0);
789 
790             /* Now restore interrupts and check for TS */
791             _enable();
792             if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame);
793 
794             /* We're still here -- clear TS and try again */
795             __writecr0(__readcr0() &~ CR0_TS);
796             _disable();
797         }
798         else
799         {
800             /* This is an actual fault, not a lack of FPU state */
801             break;
802         }
803     }
804 
805     /* TS should not be set */
806     if (Cr0 & CR0_TS)
807     {
808         /*
809          * If it's incorrectly set, then maybe the state is actually still valid
810          * but we could have lost track of that due to a BIOS call.
811          * Make sure MP is still set, which should verify the theory.
812          */
813         if (Cr0 & CR0_MP)
814         {
815             /* Indeed, the state is actually still valid, so clear TS */
816             __writecr0(__readcr0() &~ CR0_TS);
817             KiEoiHelper(TrapFrame);
818         }
819 
820         /* Otherwise, something strange is going on */
821         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame);
822     }
823 
824     /* It's not a delayed load, so process this trap as an NPX fault */
825     KiNpxHandler(TrapFrame, Thread, SaveArea);
826 }
827 
828 DECLSPEC_NORETURN
829 VOID
830 __cdecl
831 KiTrap08Handler(VOID)
832 {
833     PKTSS Tss, DfTss;
834     PKTHREAD Thread;
835     PKPROCESS Process;
836     PKGDTENTRY TssGdt;
837 
838     /* For sanity's sake, make sure interrupts are disabled */
839     _disable();
840 
841     /* Get the current TSS, thread, and process */
842     Tss = KeGetPcr()->TSS;
843     Thread = ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread;
844     Process = Thread->ApcState.Process;
845 
846     /* Save data usually not present in the TSS */
847     Tss->CR3 = Process->DirectoryTableBase[0];
848     Tss->IoMapBase = Process->IopmOffset;
849     Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0;
850 
851     /* Now get the base address of the double-fault TSS */
852     TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_DF_TSS / sizeof(KGDTENTRY)];
853     DfTss  = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow |
854                                 TssGdt->HighWord.Bytes.BaseMid << 16 |
855                                 TssGdt->HighWord.Bytes.BaseHi << 24);
856 
857     /*
858      * Switch to it and activate it, masking off the nested flag.
859      *
860      * Note that in reality, we are already on the double-fault TSS
861      * -- we just need to update the PCR to reflect this.
862      */
863     KeGetPcr()->TSS = DfTss;
864     __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK);
865     TssGdt->HighWord.Bits.Dpl = 0;
866     TssGdt->HighWord.Bits.Pres = 1;
867     // TssGdt->HighWord.Bits.Type &= ~0x2; /* I386_ACTIVE_TSS --> I386_TSS */
868     TssGdt->HighWord.Bits.Type = I386_TSS; // Busy bit cleared in the TSS selector.
869 
870     /* Bugcheck the system */
871     KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
872                      EXCEPTION_DOUBLE_FAULT,
873                      (ULONG_PTR)Tss,
874                      0,
875                      0,
876                      NULL);
877 }
878 
879 DECLSPEC_NORETURN
880 VOID
881 FASTCALL
882 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame)
883 {
884     /* Save trap frame */
885     KiEnterTrap(TrapFrame);
886 
887     /* Enable interrupts and kill the system */
888     _enable();
889     KiSystemFatalException(EXCEPTION_NPX_OVERRUN, TrapFrame);
890 }
891 
892 DECLSPEC_NORETURN
893 VOID
894 FASTCALL
895 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame)
896 {
897     /* Save trap frame */
898     KiEnterTrap(TrapFrame);
899 
900     /* Check for VDM trap */
901     ASSERT(KiVdmTrap(TrapFrame) == FALSE);
902 
903     /* Kill the system */
904     KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
905 }
906 
907 DECLSPEC_NORETURN
908 VOID
909 FASTCALL
910 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame)
911 {
912     /* Save trap frame */
913     KiEnterTrap(TrapFrame);
914 
915     /* FIXME: Kill the system */
916     UNIMPLEMENTED;
917     KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT, TrapFrame);
918 }
919 
920 DECLSPEC_NORETURN
921 VOID
922 FASTCALL
923 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame)
924 {
925     /* Save trap frame */
926     KiEnterTrap(TrapFrame);
927 
928     /* FIXME: Kill the system */
929     UNIMPLEMENTED;
930     KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame);
931 }
932 
933 /* DECLSPEC_NORETURN VOID FASTCALL KiTrap0DHandler(IN PKTRAP_FRAME); */
934 DECLSPEC_NORETURN VOID FASTCALL KiTrap0EHandler(IN PKTRAP_FRAME);
935 
936 DECLSPEC_NORETURN
937 VOID
938 FASTCALL
939 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
940 {
941     ULONG i, j, Iopl;
942     BOOLEAN Privileged = FALSE;
943     PUCHAR Instructions;
944     UCHAR Instruction = 0;
945     KIRQL OldIrql;
946 
947     /* Check for V86 GPF */
948     if (__builtin_expect(KiV86Trap(TrapFrame), 1))
949     {
950         /* Enter V86 trap */
951         KiEnterV86Trap(TrapFrame);
952 
953         /* Must be a VDM process */
954         if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
955         {
956             /* Enable interrupts */
957             _enable();
958 
959             /* Setup illegal instruction fault */
960             KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
961                                      TrapFrame->Eip,
962                                      TrapFrame);
963         }
964 
965         /* Go to APC level */
966         KeRaiseIrql(APC_LEVEL, &OldIrql);
967         _enable();
968 
969         /* Handle the V86 opcode */
970         if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0))
971         {
972             /* Should only happen in VDM mode */
973             UNIMPLEMENTED_FATAL();
974         }
975 
976         /* Bring IRQL back */
977         KeLowerIrql(OldIrql);
978         _disable();
979 
980         /* Do a quick V86 exit if possible */
981         KiExitV86Trap(TrapFrame);
982     }
983 
984     /* Save trap frame */
985     KiEnterTrap(TrapFrame);
986 
987     /* Check for user-mode GPF */
988     if (KiUserTrap(TrapFrame))
989     {
990         /* Should not be VDM */
991         ASSERT(KiVdmTrap(TrapFrame) == FALSE);
992 
993         /* Enable interrupts and check error code */
994         _enable();
995         if (!TrapFrame->ErrCode)
996         {
997             /* FIXME: Use SEH */
998             Instructions = (PUCHAR)TrapFrame->Eip;
999 
1000             /* Scan next 15 bytes */
1001             for (i = 0; i < 15; i++)
1002             {
1003                 /* Skip prefix instructions */
1004                 for (j = 0; j < sizeof(KiTrapPrefixTable); j++)
1005                 {
1006                     /* Is this a prefix instruction? */
1007                     if (Instructions[i] == KiTrapPrefixTable[j])
1008                     {
1009                         /* Stop looking */
1010                         break;
1011                     }
1012                 }
1013 
1014                 /* Is this NOT any prefix instruction? */
1015                 if (j == sizeof(KiTrapPrefixTable))
1016                 {
1017                     /* We can go ahead and handle the fault now */
1018                     Instruction = Instructions[i];
1019                     break;
1020                 }
1021             }
1022 
1023             /* If all we found was prefixes, then this instruction is too long */
1024             if (i == 15)
1025             {
1026                 /* Setup illegal instruction fault */
1027                 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
1028                                          TrapFrame->Eip,
1029                                          TrapFrame);
1030             }
1031 
1032             /* Check for privileged instructions */
1033             DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n",
1034                     i,
1035                     Instructions[i],
1036                     Instructions[i + 1],
1037                     Instructions[i + 2],
1038                     Instructions[i + 3]);
1039             if (Instruction == 0xF4)                            // HLT
1040             {
1041                 /* HLT is privileged */
1042                 Privileged = TRUE;
1043             }
1044             else if (Instruction == 0x0F)
1045             {
1046                 /* Test if it's any of the privileged two-byte opcodes */
1047                 if (((Instructions[i + 1] == 0x00) &&              // LLDT or LTR
1048                      (((Instructions[i + 2] & 0x38) == 0x10) ||        // LLDT
1049                       (Instructions[i + 2] == 0x18))) ||               // LTR
1050                     ((Instructions[i + 1] == 0x01) &&              // LGDT or LIDT or LMSW
1051                      (((Instructions[i + 2] & 0x38) == 0x10) ||        // LGDT
1052                       (Instructions[i + 2] == 0x18) ||                 // LIDT
1053                       (Instructions[i + 2] == 0x30))) ||               // LMSW
1054                     (Instructions[i + 1] == 0x08) ||               // INVD
1055                     (Instructions[i + 1] == 0x09) ||               // WBINVD
1056                     (Instructions[i + 1] == 0x35) ||               // SYSEXIT
1057                     (Instructions[i + 1] == 0x21) ||               // MOV DR, XXX
1058                     (Instructions[i + 1] == 0x06) ||               // CLTS
1059                     (Instructions[i + 1] == 0x20) ||               // MOV CR, XXX
1060                     (Instructions[i + 1] == 0x22) ||               // MOV XXX, CR
1061                     (Instructions[i + 1] == 0x23) ||               // MOV YYY, DR
1062                     (Instructions[i + 1] == 0x30) ||               // WRMSR
1063                     (Instructions[i + 1] == 0x33))                 // RDPMC
1064                     // INVLPG, INVLPGA, SYSRET
1065                 {
1066                     /* These are all privileged */
1067                     Privileged = TRUE;
1068                 }
1069             }
1070             else
1071             {
1072                 /* Get the IOPL and compare with the RPL mask */
1073                 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12;
1074                 if ((TrapFrame->SegCs & RPL_MASK) > Iopl)
1075                 {
1076                     /* I/O privilege error -- check for known instructions */
1077                     if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI
1078                     {
1079                         /* These are privileged */
1080                         Privileged = TRUE;
1081                     }
1082                     else
1083                     {
1084                         /* Last hope: an IN/OUT instruction */
1085                         for (j = 0; j < sizeof(KiTrapIoTable); j++)
1086                         {
1087                             /* Is this an I/O instruction? */
1088                             if (Instruction == KiTrapIoTable[j])
1089                             {
1090                                 /* Then it's privileged */
1091                                 Privileged = TRUE;
1092                                 break;
1093                             }
1094                         }
1095                     }
1096                 }
1097             }
1098 
1099             /* So now... was the instruction privileged or not? */
1100             if (Privileged)
1101             {
1102                 /* Whew! We have a privileged instruction, so dispatch the fault */
1103                 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION,
1104                                          TrapFrame->Eip,
1105                                          TrapFrame);
1106             }
1107         }
1108 
1109         /* If we got here, send an access violation */
1110         KiDispatchException2Args(STATUS_ACCESS_VIOLATION,
1111                                  TrapFrame->Eip,
1112                                  0,
1113                                  0xFFFFFFFF,
1114                                  TrapFrame);
1115     }
1116 
1117     /*
1118      * Check for a fault during checking of the user instruction.
1119      *
1120      * Note that the SEH handler will catch invalid EIP, but we could be dealing
1121      * with an invalid CS, which will generate another GPF instead.
1122      *
1123      */
1124     if ((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler &&
1125         (PVOID)TrapFrame->Eip <  (PVOID)KiTrap0EHandler)
1126     {
1127         /* Not implemented */
1128         UNIMPLEMENTED_FATAL();
1129     }
1130 
1131     /*
1132      * NOTE: The ASM trap exit code would restore segment registers by doing
1133      * a POP <SEG>, which could cause an invalid segment if someone had messed
1134      * with the segment values.
1135      *
1136      * Another case is a bogus SS, which would hit a GPF when doing the iret.
1137      * This could only be done through a buggy or malicious driver, or perhaps
1138      * the kernel debugger.
1139      *
1140      * The kernel normally restores the "true" segment if this happens.
1141      *
1142      * However, since we're restoring in C, not ASM, we can't detect
1143      * POP <SEG> since the actual instructions will be different.
1144      *
1145      * A better technique would be to check the EIP and somehow edit the
1146      * trap frame before restarting the instruction -- but we would need to
1147      * know the extract instruction that was used first.
1148      *
1149      * We could force a special instrinsic to use stack instructions, or write
1150      * a simple instruction length checker.
1151      *
1152      * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1153      * when the user is purposedly trying to create one from kernel-mode, so
1154      * we should probably table this for now since it's not a "real" issue.
1155      */
1156 
1157     /*
1158      * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1159      * which will cause a GPF since the trap frame is a total mess (on purpose)
1160      * as built in KiEnterV86Mode.
1161      *
1162      * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1163      * and then manually issue a jump to the V8086 return EIP.
1164      */
1165     Instructions = (PUCHAR)TrapFrame->Eip;
1166     if (Instructions[0] == 0xCF)
1167     {
1168         /*
1169          * Some evil shit is going on here -- this is not the SS:ESP you're
1170          * looking for! Instead, this is actually CS:EIP you're looking at!
1171          * Why? Because part of the trap frame actually corresponds to the IRET
1172          * stack during the trap exit!
1173          */
1174         if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) &&
1175             (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK)))
1176         {
1177             /* Exit the V86 trap! */
1178             Ki386BiosCallReturnAddress(TrapFrame);
1179         }
1180         else
1181         {
1182             /* Otherwise, this is another kind of IRET fault */
1183             UNIMPLEMENTED_FATAL();
1184         }
1185     }
1186 
1187      /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1188     if ((Instructions[0] == 0xF) &&            // 2-byte opcode
1189         ((Instructions[1] == 0x32) ||        // RDMSR
1190          (Instructions[1] == 0x30)))         // WRMSR
1191     {
1192         /* Unknown CPU MSR, so raise an access violation */
1193         KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
1194                                  TrapFrame->Eip,
1195                                  TrapFrame);
1196     }
1197 
1198     /* Check for lazy segment load */
1199     if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK))
1200     {
1201         /* Fix it */
1202         TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK);
1203     }
1204     else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK))
1205     {
1206         /* Fix it */
1207         TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK);
1208     }
1209     else
1210     {
1211         /* Whatever it is, we can't handle it */
1212         KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame);
1213     }
1214 
1215     /* Return to where we came from */
1216     KiTrapReturn(TrapFrame);
1217 }
1218 
1219 DECLSPEC_NORETURN
1220 VOID
1221 FASTCALL
1222 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
1223 {
1224     PKTHREAD Thread;
1225     BOOLEAN StoreInstruction;
1226     ULONG_PTR Cr2;
1227     NTSTATUS Status;
1228 
1229     /* Save trap frame */
1230     KiEnterTrap(TrapFrame);
1231 
1232     /* Check if this is the base frame */
1233     Thread = KeGetCurrentThread();
1234     if (KeGetTrapFrame(Thread) != TrapFrame)
1235     {
1236         /* It isn't, check if this is a second nested frame */
1237         if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
1238             FIELD_OFFSET(KTRAP_FRAME, EFlags))
1239         {
1240             /* The stack is somewhere in between frames, we need to fix it */
1241             UNIMPLEMENTED_FATAL();
1242         }
1243     }
1244 
1245     /* Save CR2 */
1246     Cr2 = __readcr2();
1247 
1248     /* Enable interrupts */
1249     _enable();
1250 
1251     /* Interpret the error code */
1252     StoreInstruction = (TrapFrame->ErrCode & 2) != 0;
1253 
1254     /* Check if we came in with interrupts disabled */
1255     if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1256     {
1257         /* This is completely illegal, bugcheck the system */
1258         KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
1259                          Cr2,
1260                          (ULONG_PTR)-1,
1261                          TrapFrame->ErrCode,
1262                          TrapFrame->Eip,
1263                          TrapFrame);
1264     }
1265 
1266     /* Check for S-List fault
1267 
1268        Explanation: An S-List fault can occur due to a race condition between 2
1269        threads simultaneously trying to pop an element from the S-List. After
1270        thread 1 has read the pointer to the top element on the S-List it is
1271        preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List,
1272        removing the top element and freeing it's memory. After that thread 1
1273        resumes and tries to read the address of the Next pointer from the top
1274        element, which it assumes will be the next top element.
1275        But since that memory has been freed, we get a page fault. To handle this
1276        race condition, we let thread 1 repeat the operation.
1277        We do NOT invoke the page fault handler in this case, since we do not
1278        want to trigger any side effects, like paging or a guard page fault.
1279 
1280        Sequence of operations:
1281 
1282            Thread 1 : mov eax, [ebp] <= eax now points to the first element
1283            Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence
1284             *** preempted ***
1285            Thread 2 : calls InterlockedPopEntrySlist, changing the top element
1286            Thread 2 : frees the memory of the element that was popped
1287             *** preempted ***
1288            Thread 1 : checks if eax is NULL
1289            Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults
1290 
1291         To be sure that we are dealing with exactly the case described above, we
1292         check whether the ListHeader has changed. If Thread 2 only popped one
1293         entry, the Next field in the S-List-header has changed.
1294         If after thread 1 has faulted, thread 2 allocates a new element, by
1295         chance getting the same address as the previously freed element and
1296         pushes it on the list again, we will see the same top element, but the
1297         Sequence member of the S-List header has changed. Therefore we check
1298         both fields to make sure we catch any concurrent modification of the
1299         S-List-header.
1300     */
1301     if ((TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault) ||
1302         (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault))
1303     {
1304         ULARGE_INTEGER SListHeader;
1305         PVOID ResumeAddress;
1306 
1307         /* Sanity check that the assembly is correct:
1308            This must be mov ebx, [eax]
1309            Followed by cmpxchg8b [ebp] */
1310         ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) &&
1311                (((UCHAR*)TrapFrame->Eip)[1] == 0x18) &&
1312                (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) &&
1313                (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) &&
1314                (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) &&
1315                (((UCHAR*)TrapFrame->Eip)[5] == 0x00));
1316 
1317         /* Check if this is a user fault */
1318         if (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault)
1319         {
1320             /* EBP points to the S-List-header. Copy it inside SEH, to protect
1321                against a bogus pointer from user mode */
1322             _SEH2_TRY
1323             {
1324                 ProbeForRead((PVOID)TrapFrame->Ebp,
1325                              sizeof(ULARGE_INTEGER),
1326                              TYPE_ALIGNMENT(SLIST_HEADER));
1327                 SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp;
1328             }
1329             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1330             {
1331                 /* The S-List pointer is not valid! */
1332                 goto NotSListFault;
1333             }
1334             _SEH2_END;
1335             ResumeAddress = KeUserPopEntrySListResume;
1336         }
1337         else
1338         {
1339             SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp;
1340             ResumeAddress = ExpInterlockedPopEntrySListResume;
1341         }
1342 
1343         /* Check if either the Next pointer or the Sequence member in the
1344            S-List-header has changed. If any of these has changed, we restart
1345            the operation. Otherwise we only have a bogus pointer and let the
1346            page fault handler deal with it. */
1347         if ((SListHeader.LowPart != TrapFrame->Eax) ||
1348             (SListHeader.HighPart != TrapFrame->Edx))
1349         {
1350             DPRINT1("*** Got an S-List-Fault ***\n");
1351             KeGetCurrentThread()->SListFaultCount++;
1352 
1353             /* Restart the operation */
1354             TrapFrame->Eip = (ULONG_PTR)ResumeAddress;
1355 
1356             /* Continue execution */
1357             KiEoiHelper(TrapFrame);
1358         }
1359     }
1360 NotSListFault:
1361 
1362     /* Call the access fault handler */
1363     Status = MmAccessFault(TrapFrame->ErrCode,
1364                            (PVOID)Cr2,
1365                            KiUserTrap(TrapFrame),
1366                            TrapFrame);
1367     if (NT_SUCCESS(Status))
1368     {
1369 #ifdef _WINKD_
1370         /* Check whether the kernel debugger has owed breakpoints to be inserted */
1371         KdSetOwedBreakpoints();
1372 #endif
1373         /* We succeeded, return */
1374         KiEoiHelper(TrapFrame);
1375     }
1376 
1377     /* Check for syscall fault */
1378 #if 0
1379     if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
1380         (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
1381     {
1382         /* Not yet implemented */
1383         UNIMPLEMENTED_FATAL();
1384     }
1385 #endif
1386 
1387     /* Check for VDM trap */
1388     if (KiVdmTrap(TrapFrame))
1389     {
1390         DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1391                 TrapFrame->SegCs, TrapFrame->Eip, Cr2);
1392         if (VdmDispatchPageFault(TrapFrame))
1393         {
1394             /* Return and end VDM execution */
1395             DPRINT1("VDM page fault with status 0x%lx resolved\n", Status);
1396             KiEoiHelper(TrapFrame);
1397         }
1398         DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status);
1399     }
1400 
1401     /* Either kernel or user trap (non VDM) so dispatch exception */
1402     if (Status == STATUS_ACCESS_VIOLATION)
1403     {
1404         /* This status code is repurposed so we can recognize it later */
1405         KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1406                                  TrapFrame->Eip,
1407                                  StoreInstruction,
1408                                  Cr2,
1409                                  TrapFrame);
1410     }
1411     else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
1412              (Status == STATUS_STACK_OVERFLOW))
1413     {
1414         /* These faults only have two parameters */
1415         KiDispatchException2Args(Status,
1416                                  TrapFrame->Eip,
1417                                  StoreInstruction,
1418                                  Cr2,
1419                                  TrapFrame);
1420     }
1421 
1422     /* Only other choice is an in-page error, with 3 parameters */
1423     KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
1424                                      0,
1425                                      TrapFrame->Eip,
1426                                      3,
1427                                      StoreInstruction,
1428                                      Cr2,
1429                                      Status,
1430                                      TrapFrame);
1431 }
1432 
1433 DECLSPEC_NORETURN
1434 VOID
1435 FASTCALL
1436 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
1437 {
1438     /* Save trap frame */
1439     KiEnterTrap(TrapFrame);
1440 
1441     /* FIXME: Kill the system */
1442     UNIMPLEMENTED;
1443     KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
1444 }
1445 
1446 DECLSPEC_NORETURN
1447 VOID
1448 FASTCALL
1449 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
1450 {
1451     PKTHREAD Thread;
1452     PFX_SAVE_AREA SaveArea;
1453 
1454     /* Save trap frame */
1455     KiEnterTrap(TrapFrame);
1456 
1457     /* Check if this is the NPX thrad */
1458     Thread = KeGetCurrentThread();
1459     SaveArea = KiGetThreadNpxArea(Thread);
1460     if (Thread != KeGetCurrentPrcb()->NpxThread)
1461     {
1462         /* It isn't, enable interrupts and set delayed error */
1463         _enable();
1464         SaveArea->Cr0NpxState |= CR0_TS;
1465 
1466         /* End trap */
1467         KiEoiHelper(TrapFrame);
1468     }
1469 
1470     /* Otherwise, proceed with NPX fault handling */
1471     KiNpxHandler(TrapFrame, Thread, SaveArea);
1472 }
1473 
1474 DECLSPEC_NORETURN
1475 VOID
1476 FASTCALL
1477 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
1478 {
1479     /* Save trap frame */
1480     KiEnterTrap(TrapFrame);
1481 
1482     /* Enable interrupts and kill the system */
1483     _enable();
1484     KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
1485 }
1486 
1487 DECLSPEC_NORETURN
1488 VOID
1489 FASTCALL
1490 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
1491 {
1492     PKTHREAD Thread;
1493     PFX_SAVE_AREA SaveArea;
1494     ULONG Cr0, MxCsrMask, Error;
1495 
1496     /* Save trap frame */
1497     KiEnterTrap(TrapFrame);
1498 
1499     /* Check if this is the NPX thrad */
1500     Thread = KeGetCurrentThread();
1501     if (Thread != KeGetCurrentPrcb()->NpxThread)
1502     {
1503         /* It isn't, kill the system */
1504         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
1505     }
1506 
1507     /* Get the NPX frame */
1508     SaveArea = KiGetThreadNpxArea(Thread);
1509 
1510     /* Check for VDM trap */
1511     ASSERT(KiVdmTrap(TrapFrame) == FALSE);
1512 
1513     /* Check for user trap */
1514     if (!KiUserTrap(TrapFrame))
1515     {
1516         /* Kernel should not fault on XMMI */
1517         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
1518     }
1519 
1520     /* Update CR0 */
1521     Cr0 = __readcr0();
1522     Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
1523     __writecr0(Cr0);
1524 
1525     /* Save FPU state */
1526     Ke386SaveFpuState(SaveArea);
1527 
1528     /* Mark CR0 state dirty */
1529     Cr0 |= NPX_STATE_NOT_LOADED;
1530     Cr0 |= SaveArea->Cr0NpxState;
1531      __writecr0(Cr0);
1532 
1533     /* Update NPX state */
1534     Thread->NpxState = NPX_STATE_NOT_LOADED;
1535     KeGetCurrentPrcb()->NpxThread = NULL;
1536 
1537     /* Clear the TS bit and re-enable interrupts */
1538     SaveArea->Cr0NpxState &= ~CR0_TS;
1539     _enable();
1540 
1541     /* Now look at MxCsr to get the mask of errors we should care about */
1542     MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
1543 
1544     /* Get legal exceptions that software should handle */
1545     Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
1546                                                 FSW_DENORMAL |
1547                                                 FSW_ZERO_DIVIDE |
1548                                                 FSW_OVERFLOW |
1549                                                 FSW_UNDERFLOW |
1550                                                 FSW_PRECISION);
1551     Error &= MxCsrMask;
1552 
1553     /* Now handle any of those legal errors */
1554     if (Error & (FSW_INVALID_OPERATION |
1555                  FSW_DENORMAL |
1556                  FSW_ZERO_DIVIDE |
1557                  FSW_OVERFLOW |
1558                  FSW_UNDERFLOW |
1559                  FSW_PRECISION))
1560     {
1561         /* By issuing an exception */
1562         KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
1563                                  TrapFrame->Eip,
1564                                  0,
1565                                  TrapFrame);
1566     }
1567 
1568     /* Unknown XMMI fault */
1569     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
1570 }
1571 
1572 /* SOFTWARE SERVICES **********************************************************/
1573 
1574 VOID
1575 FASTCALL
1576 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame)
1577 {
1578     /* Save trap frame */
1579     KiEnterTrap(TrapFrame);
1580 
1581     /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1582     TrapFrame->Eip -= 2;
1583 
1584     /* Check if this is a user trap */
1585     if (KiUserTrap(TrapFrame))
1586     {
1587         /* Dispatch exception to user mode */
1588         KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN,
1589                                          EXCEPTION_NONCONTINUABLE,
1590                                          TrapFrame->Eip,
1591                                          1,
1592                                          TrapFrame->Ecx,
1593                                          0,
1594                                          0,
1595                                          TrapFrame);
1596     }
1597     else
1598     {
1599         EXCEPTION_RECORD ExceptionRecord;
1600 
1601         /* Bugcheck the system */
1602         ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1603         ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
1604         ExceptionRecord.ExceptionRecord = NULL;
1605         ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Eip;
1606         ExceptionRecord.NumberParameters = 1;
1607         ExceptionRecord.ExceptionInformation[0] = TrapFrame->Ecx;
1608 
1609         KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE,
1610                          TrapFrame->Ecx,
1611                          (ULONG_PTR)TrapFrame,
1612                          (ULONG_PTR)&ExceptionRecord,
1613                          0,
1614                          TrapFrame);
1615     }
1616 }
1617 
1618 VOID
1619 FASTCALL
1620 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
1621 {
1622     /* Save trap frame */
1623     KiEnterTrap(TrapFrame);
1624 
1625     /*
1626      * Just fail the request
1627      */
1628     DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1629     TrapFrame->Eax = 0;
1630 
1631     /* Exit the trap */
1632     KiEoiHelper(TrapFrame);
1633 }
1634 
1635 VOID
1636 FASTCALL
1637 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
1638 {
1639     PKTHREAD Thread;
1640     NTSTATUS Status;
1641 
1642     /* Save the SEH chain, NtCallbackReturn will restore this */
1643     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1644 
1645     /* Set thread fields */
1646     Thread = KeGetCurrentThread();
1647     Thread->TrapFrame = TrapFrame;
1648     Thread->PreviousMode = KiUserTrap(TrapFrame);
1649     ASSERT(Thread->PreviousMode != KernelMode);
1650 
1651     /* Pass the register parameters to NtCallbackReturn.
1652        Result pointer is in ecx, result length in edx, status in eax */
1653     Status = NtCallbackReturn((PVOID)TrapFrame->Ecx,
1654                               TrapFrame->Edx,
1655                               TrapFrame->Eax);
1656 
1657     /* If we got here, something went wrong. Return an error to the caller */
1658     KiServiceExit(TrapFrame, Status);
1659 }
1660 
1661 DECLSPEC_NORETURN
1662 VOID
1663 FASTCALL
1664 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
1665 {
1666     /* Save trap frame */
1667     KiEnterTrap(TrapFrame);
1668 
1669     /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1670     TrapFrame->Eip -= 2;
1671 
1672     /* Dispatch the exception */
1673     KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
1674                              TrapFrame->Eip,
1675                              TrapFrame);
1676 }
1677 
1678 DECLSPEC_NORETURN
1679 VOID
1680 FASTCALL
1681 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
1682 {
1683     /* Save trap frame */
1684     KiEnterTrap(TrapFrame);
1685 
1686     /* Increment EIP to skip the INT3 instruction */
1687     TrapFrame->Eip++;
1688 
1689     /* Continue with the common handler */
1690     KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1691 }
1692 
1693 
1694 FORCEINLINE
1695 VOID
1696 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments)
1697 {
1698 #if DBG && !defined(_WINKD_)
1699     if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook)
1700         KeWin32PreServiceHook(SystemCallNumber, Arguments);
1701 #endif
1702 }
1703 
1704 FORCEINLINE
1705 ULONG_PTR
1706 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
1707 {
1708 #if DBG && !defined(_WINKD_)
1709     if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook)
1710         return KeWin32PostServiceHook(SystemCallNumber, Result);
1711 #endif
1712     return Result;
1713 }
1714 
1715 DECLSPEC_NORETURN
1716 VOID
1717 FASTCALL
1718 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
1719                        IN PVOID Arguments)
1720 {
1721     PKTHREAD Thread;
1722     PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
1723     ULONG Id, Offset, StackBytes;
1724     NTSTATUS Status;
1725     PVOID Handler;
1726     ULONG SystemCallNumber = TrapFrame->Eax;
1727 
1728     /* Get the current thread */
1729     Thread = KeGetCurrentThread();
1730 
1731     /* Set debug header */
1732     KiFillTrapFrameDebug(TrapFrame);
1733 
1734     /* Chain trap frames */
1735     TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
1736 
1737     /* No error code */
1738     TrapFrame->ErrCode = 0;
1739 
1740     /* Save previous mode */
1741     TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
1742 
1743     /* Save the SEH chain and terminate it for now */
1744     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1745     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
1746 
1747     /* Default to debugging disabled */
1748     TrapFrame->Dr7 = 0;
1749 
1750     /* Check if the frame was from user mode */
1751     if (KiUserTrap(TrapFrame))
1752     {
1753         /* Check for active debugging */
1754         if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
1755         {
1756             /* Handle debug registers */
1757             KiHandleDebugRegistersOnTrapEntry(TrapFrame);
1758         }
1759     }
1760 
1761     /* Set thread fields */
1762     Thread->TrapFrame = TrapFrame;
1763     Thread->PreviousMode = KiUserTrap(TrapFrame);
1764 
1765     /* Enable interrupts */
1766     _enable();
1767 
1768     /* Decode the system call number */
1769     Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
1770     Id = SystemCallNumber & SERVICE_NUMBER_MASK;
1771 
1772     /* Get descriptor table */
1773     DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
1774 
1775     /* Validate the system call number */
1776     if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
1777     {
1778         /* Check if this is a GUI call */
1779         if (!(Offset & SERVICE_TABLE_TEST))
1780         {
1781             /* Fail the call */
1782             Status = STATUS_INVALID_SYSTEM_SERVICE;
1783             goto ExitCall;
1784         }
1785 
1786         /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1787         Status = KiConvertToGuiThread();
1788 
1789         /* Reload trap frame and descriptor table pointer from new stack */
1790         TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
1791         DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
1792 
1793         if (!NT_SUCCESS(Status))
1794         {
1795             /* Set the last error and fail */
1796             goto ExitCall;
1797         }
1798 
1799         /* Validate the system call number again */
1800         if (Id >= DescriptorTable->Limit)
1801         {
1802             /* Fail the call */
1803             Status = STATUS_INVALID_SYSTEM_SERVICE;
1804             goto ExitCall;
1805         }
1806     }
1807 
1808     /* Check if this is a GUI call */
1809     if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
1810     {
1811         /* Get the batch count and flush if necessary */
1812         if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
1813     }
1814 
1815     /* Increase system call count */
1816     KeGetCurrentPrcb()->KeSystemCalls++;
1817 
1818     /* FIXME: Increase individual counts on debug systems */
1819     //KiIncreaseSystemCallCount(DescriptorTable, Id);
1820 
1821     /* Get stack bytes */
1822     StackBytes = DescriptorTable->Number[Id];
1823 
1824     /* Probe caller stack */
1825     if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
1826     {
1827         /* Access violation */
1828         UNIMPLEMENTED_FATAL();
1829     }
1830 
1831     /* Call pre-service debug hook */
1832     KiDbgPreServiceHook(SystemCallNumber, Arguments);
1833 
1834     /* Get the handler and make the system call */
1835     Handler = (PVOID)DescriptorTable->Base[Id];
1836     Status = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
1837 
1838     /* Call post-service debug hook */
1839     Status = KiDbgPostServiceHook(SystemCallNumber, Status);
1840 
1841     /* Make sure we're exiting correctly */
1842     KiExitSystemCallDebugChecks(Id, TrapFrame);
1843 
1844     /* Restore the old trap frame */
1845 ExitCall:
1846     Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
1847 
1848     /* Exit from system call */
1849     KiServiceExit(TrapFrame, Status);
1850 }
1851 
1852 VOID
1853 FASTCALL
1854 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame)
1855 {
1856     UNIMPLEMENTED;
1857 }
1858 
1859 /*
1860  * @implemented
1861  */
1862 VOID
1863 NTAPI
1864 Kei386EoiHelper(VOID)
1865 {
1866     /* We should never see this call happening */
1867     KeBugCheck(MISMATCHED_HAL);
1868 }
1869 
1870 /* EOF */
1871