xref: /reactos/ntoskrnl/ke/i386/traphdlr.c (revision 3435c3b5)
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
934 VOID
935 FASTCALL
936 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
937 {
938     ULONG i, j, Iopl;
939     BOOLEAN Privileged = FALSE;
940     PUCHAR Instructions;
941     UCHAR Instruction = 0;
942     KIRQL OldIrql;
943 
944     /* Check for V86 GPF */
945     if (__builtin_expect(KiV86Trap(TrapFrame), 1))
946     {
947         /* Enter V86 trap */
948         KiEnterV86Trap(TrapFrame);
949 
950         /* Must be a VDM process */
951         if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
952         {
953             /* Enable interrupts */
954             _enable();
955 
956             /* Setup illegal instruction fault */
957             KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
958                                      TrapFrame->Eip,
959                                      TrapFrame);
960         }
961 
962         /* Go to APC level */
963         KeRaiseIrql(APC_LEVEL, &OldIrql);
964         _enable();
965 
966         /* Handle the V86 opcode */
967         if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0))
968         {
969             /* Should only happen in VDM mode */
970             UNIMPLEMENTED_FATAL();
971         }
972 
973         /* Bring IRQL back */
974         KeLowerIrql(OldIrql);
975         _disable();
976 
977         /* Do a quick V86 exit if possible */
978         KiExitV86Trap(TrapFrame);
979     }
980 
981     /* Save trap frame */
982     KiEnterTrap(TrapFrame);
983 
984     /* Check for user-mode GPF */
985     if (KiUserTrap(TrapFrame))
986     {
987         /* Should not be VDM */
988         ASSERT(KiVdmTrap(TrapFrame) == FALSE);
989 
990         /* Enable interrupts and check error code */
991         _enable();
992         if (!TrapFrame->ErrCode)
993         {
994             /* FIXME: Use SEH */
995             Instructions = (PUCHAR)TrapFrame->Eip;
996 
997             /* Scan next 15 bytes */
998             for (i = 0; i < 15; i++)
999             {
1000                 /* Skip prefix instructions */
1001                 for (j = 0; j < sizeof(KiTrapPrefixTable); j++)
1002                 {
1003                     /* Is this a prefix instruction? */
1004                     if (Instructions[i] == KiTrapPrefixTable[j])
1005                     {
1006                         /* Stop looking */
1007                         break;
1008                     }
1009                 }
1010 
1011                 /* Is this NOT any prefix instruction? */
1012                 if (j == sizeof(KiTrapPrefixTable))
1013                 {
1014                     /* We can go ahead and handle the fault now */
1015                     Instruction = Instructions[i];
1016                     break;
1017                 }
1018             }
1019 
1020             /* If all we found was prefixes, then this instruction is too long */
1021             if (i == 15)
1022             {
1023                 /* Setup illegal instruction fault */
1024                 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
1025                                          TrapFrame->Eip,
1026                                          TrapFrame);
1027             }
1028 
1029             /* Check for privileged instructions */
1030             DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n",
1031                     i,
1032                     Instructions[i],
1033                     Instructions[i + 1],
1034                     Instructions[i + 2],
1035                     Instructions[i + 3]);
1036             if (Instruction == 0xF4)                            // HLT
1037             {
1038                 /* HLT is privileged */
1039                 Privileged = TRUE;
1040             }
1041             else if (Instruction == 0x0F)
1042             {
1043                 /* Test if it's any of the privileged two-byte opcodes */
1044                 if (((Instructions[i + 1] == 0x00) &&              // LLDT or LTR
1045                      (((Instructions[i + 2] & 0x38) == 0x10) ||        // LLDT
1046                       (Instructions[i + 2] == 0x18))) ||               // LTR
1047                     ((Instructions[i + 1] == 0x01) &&              // LGDT or LIDT or LMSW
1048                      (((Instructions[i + 2] & 0x38) == 0x10) ||        // LGDT
1049                       (Instructions[i + 2] == 0x18) ||                 // LIDT
1050                       (Instructions[i + 2] == 0x30))) ||               // LMSW
1051                     (Instructions[i + 1] == 0x08) ||               // INVD
1052                     (Instructions[i + 1] == 0x09) ||               // WBINVD
1053                     (Instructions[i + 1] == 0x35) ||               // SYSEXIT
1054                     (Instructions[i + 1] == 0x21) ||               // MOV DR, XXX
1055                     (Instructions[i + 1] == 0x06) ||               // CLTS
1056                     (Instructions[i + 1] == 0x20) ||               // MOV CR, XXX
1057                     (Instructions[i + 1] == 0x22) ||               // MOV XXX, CR
1058                     (Instructions[i + 1] == 0x23) ||               // MOV YYY, DR
1059                     (Instructions[i + 1] == 0x30) ||               // WRMSR
1060                     (Instructions[i + 1] == 0x33))                 // RDPMC
1061                     // INVLPG, INVLPGA, SYSRET
1062                 {
1063                     /* These are all privileged */
1064                     Privileged = TRUE;
1065                 }
1066             }
1067             else
1068             {
1069                 /* Get the IOPL and compare with the RPL mask */
1070                 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12;
1071                 if ((TrapFrame->SegCs & RPL_MASK) > Iopl)
1072                 {
1073                     /* I/O privilege error -- check for known instructions */
1074                     if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI
1075                     {
1076                         /* These are privileged */
1077                         Privileged = TRUE;
1078                     }
1079                     else
1080                     {
1081                         /* Last hope: an IN/OUT instruction */
1082                         for (j = 0; j < sizeof(KiTrapIoTable); j++)
1083                         {
1084                             /* Is this an I/O instruction? */
1085                             if (Instruction == KiTrapIoTable[j])
1086                             {
1087                                 /* Then it's privileged */
1088                                 Privileged = TRUE;
1089                                 break;
1090                             }
1091                         }
1092                     }
1093                 }
1094             }
1095 
1096             /* So now... was the instruction privileged or not? */
1097             if (Privileged)
1098             {
1099                 /* Whew! We have a privileged instruction, so dispatch the fault */
1100                 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION,
1101                                          TrapFrame->Eip,
1102                                          TrapFrame);
1103             }
1104         }
1105 
1106         /* If we got here, send an access violation */
1107         KiDispatchException2Args(STATUS_ACCESS_VIOLATION,
1108                                  TrapFrame->Eip,
1109                                  0,
1110                                  0xFFFFFFFF,
1111                                  TrapFrame);
1112     }
1113 
1114     /*
1115      * Check for a fault during checking of the user instruction.
1116      *
1117      * Note that the SEH handler will catch invalid EIP, but we could be dealing
1118      * with an invalid CS, which will generate another GPF instead.
1119      *
1120      */
1121     if (((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler) &&
1122         ((PVOID)TrapFrame->Eip < (PVOID)KiTrap0DHandler))
1123     {
1124         /* Not implemented */
1125         UNIMPLEMENTED_FATAL();
1126     }
1127 
1128     /*
1129      * NOTE: The ASM trap exit code would restore segment registers by doing
1130      * a POP <SEG>, which could cause an invalid segment if someone had messed
1131      * with the segment values.
1132      *
1133      * Another case is a bogus SS, which would hit a GPF when doing the iret.
1134      * This could only be done through a buggy or malicious driver, or perhaps
1135      * the kernel debugger.
1136      *
1137      * The kernel normally restores the "true" segment if this happens.
1138      *
1139      * However, since we're restoring in C, not ASM, we can't detect
1140      * POP <SEG> since the actual instructions will be different.
1141      *
1142      * A better technique would be to check the EIP and somehow edit the
1143      * trap frame before restarting the instruction -- but we would need to
1144      * know the extract instruction that was used first.
1145      *
1146      * We could force a special instrinsic to use stack instructions, or write
1147      * a simple instruction length checker.
1148      *
1149      * Nevertheless, this is a lot of work for the purpose of avoiding a crash
1150      * when the user is purposedly trying to create one from kernel-mode, so
1151      * we should probably table this for now since it's not a "real" issue.
1152      */
1153 
1154     /*
1155      * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
1156      * which will cause a GPF since the trap frame is a total mess (on purpose)
1157      * as built in KiEnterV86Mode.
1158      *
1159      * The idea is to scan for IRET, scan for the known EIP adress, validate CS
1160      * and then manually issue a jump to the V8086 return EIP.
1161      */
1162     Instructions = (PUCHAR)TrapFrame->Eip;
1163     if (Instructions[0] == 0xCF)
1164     {
1165         /*
1166          * Some evil shit is going on here -- this is not the SS:ESP you're
1167          * looking for! Instead, this is actually CS:EIP you're looking at!
1168          * Why? Because part of the trap frame actually corresponds to the IRET
1169          * stack during the trap exit!
1170          */
1171         if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) &&
1172             (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK)))
1173         {
1174             /* Exit the V86 trap! */
1175             Ki386BiosCallReturnAddress(TrapFrame);
1176         }
1177         else
1178         {
1179             /* Otherwise, this is another kind of IRET fault */
1180             UNIMPLEMENTED_FATAL();
1181         }
1182     }
1183 
1184      /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
1185     if ((Instructions[0] == 0xF) &&            // 2-byte opcode
1186         ((Instructions[1] == 0x32) ||        // RDMSR
1187          (Instructions[1] == 0x30)))         // WRMSR
1188     {
1189         /* Unknown CPU MSR, so raise an access violation */
1190         KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
1191                                  TrapFrame->Eip,
1192                                  TrapFrame);
1193     }
1194 
1195     /* Check for lazy segment load */
1196     if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK))
1197     {
1198         /* Fix it */
1199         TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK);
1200     }
1201     else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK))
1202     {
1203         /* Fix it */
1204         TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK);
1205     }
1206     else
1207     {
1208         /* Whatever it is, we can't handle it */
1209         KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame);
1210     }
1211 
1212     /* Return to where we came from */
1213     KiTrapReturn(TrapFrame);
1214 }
1215 
1216 DECLSPEC_NORETURN
1217 VOID
1218 FASTCALL
1219 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
1220 {
1221     PKTHREAD Thread;
1222     BOOLEAN StoreInstruction;
1223     ULONG_PTR Cr2;
1224     NTSTATUS Status;
1225 
1226     /* Save trap frame */
1227     KiEnterTrap(TrapFrame);
1228 
1229     /* Check if this is the base frame */
1230     Thread = KeGetCurrentThread();
1231     if (KeGetTrapFrame(Thread) != TrapFrame)
1232     {
1233         /* It isn't, check if this is a second nested frame */
1234         if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
1235             FIELD_OFFSET(KTRAP_FRAME, EFlags))
1236         {
1237             /* The stack is somewhere in between frames, we need to fix it */
1238             UNIMPLEMENTED_FATAL();
1239         }
1240     }
1241 
1242     /* Save CR2 */
1243     Cr2 = __readcr2();
1244 
1245     /* Enable interrupts */
1246     _enable();
1247 
1248     /* Interpret the error code */
1249     StoreInstruction = (TrapFrame->ErrCode & 2) != 0;
1250 
1251     /* Check if we came in with interrupts disabled */
1252     if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1253     {
1254         /* This is completely illegal, bugcheck the system */
1255         KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
1256                          Cr2,
1257                          (ULONG_PTR)-1,
1258                          TrapFrame->ErrCode,
1259                          TrapFrame->Eip,
1260                          TrapFrame);
1261     }
1262 
1263     /* Check for S-List fault
1264 
1265        Explanation: An S-List fault can occur due to a race condition between 2
1266        threads simultaneously trying to pop an element from the S-List. After
1267        thread 1 has read the pointer to the top element on the S-List it is
1268        preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List,
1269        removing the top element and freeing it's memory. After that thread 1
1270        resumes and tries to read the address of the Next pointer from the top
1271        element, which it assumes will be the next top element.
1272        But since that memory has been freed, we get a page fault. To handle this
1273        race condition, we let thread 1 repeat the operation.
1274        We do NOT invoke the page fault handler in this case, since we do not
1275        want to trigger any side effects, like paging or a guard page fault.
1276 
1277        Sequence of operations:
1278 
1279            Thread 1 : mov eax, [ebp] <= eax now points to the first element
1280            Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence
1281             *** preempted ***
1282            Thread 2 : calls InterlockedPopEntrySlist, changing the top element
1283            Thread 2 : frees the memory of the element that was popped
1284             *** preempted ***
1285            Thread 1 : checks if eax is NULL
1286            Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults
1287 
1288         To be sure that we are dealing with exactly the case described above, we
1289         check whether the ListHeader has changed. If Thread 2 only popped one
1290         entry, the Next field in the S-List-header has changed.
1291         If after thread 1 has faulted, thread 2 allocates a new element, by
1292         chance getting the same address as the previously freed element and
1293         pushes it on the list again, we will see the same top element, but the
1294         Sequence member of the S-List header has changed. Therefore we check
1295         both fields to make sure we catch any concurrent modification of the
1296         S-List-header.
1297     */
1298     if ((TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault) ||
1299         (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault))
1300     {
1301         ULARGE_INTEGER SListHeader;
1302         PVOID ResumeAddress;
1303 
1304         /* Sanity check that the assembly is correct:
1305            This must be mov ebx, [eax]
1306            Followed by cmpxchg8b [ebp] */
1307         ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) &&
1308                (((UCHAR*)TrapFrame->Eip)[1] == 0x18) &&
1309                (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) &&
1310                (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) &&
1311                (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) &&
1312                (((UCHAR*)TrapFrame->Eip)[5] == 0x00));
1313 
1314         /* Check if this is a user fault */
1315         if (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault)
1316         {
1317             /* EBP points to the S-List-header. Copy it inside SEH, to protect
1318                against a bogus pointer from user mode */
1319             _SEH2_TRY
1320             {
1321                 ProbeForRead((PVOID)TrapFrame->Ebp,
1322                              sizeof(ULARGE_INTEGER),
1323                              TYPE_ALIGNMENT(SLIST_HEADER));
1324                 SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp;
1325             }
1326             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1327             {
1328                 /* The S-List pointer is not valid! */
1329                 goto NotSListFault;
1330             }
1331             _SEH2_END;
1332             ResumeAddress = KeUserPopEntrySListResume;
1333         }
1334         else
1335         {
1336             SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp;
1337             ResumeAddress = ExpInterlockedPopEntrySListResume;
1338         }
1339 
1340         /* Check if either the Next pointer or the Sequence member in the
1341            S-List-header has changed. If any of these has changed, we restart
1342            the operation. Otherwise we only have a bogus pointer and let the
1343            page fault handler deal with it. */
1344         if ((SListHeader.LowPart != TrapFrame->Eax) ||
1345             (SListHeader.HighPart != TrapFrame->Edx))
1346         {
1347             DPRINT1("*** Got an S-List-Fault ***\n");
1348             KeGetCurrentThread()->SListFaultCount++;
1349 
1350             /* Restart the operation */
1351             TrapFrame->Eip = (ULONG_PTR)ResumeAddress;
1352 
1353             /* Continue execution */
1354             KiEoiHelper(TrapFrame);
1355         }
1356     }
1357 NotSListFault:
1358 
1359     /* Call the access fault handler */
1360     Status = MmAccessFault(TrapFrame->ErrCode,
1361                            (PVOID)Cr2,
1362                            KiUserTrap(TrapFrame),
1363                            TrapFrame);
1364     if (NT_SUCCESS(Status))
1365     {
1366 #ifdef _WINKD_
1367         /* Check whether the kernel debugger has owed breakpoints to be inserted */
1368         KdSetOwedBreakpoints();
1369 #endif
1370         /* We succeeded, return */
1371         KiEoiHelper(TrapFrame);
1372     }
1373 
1374     /* Check for syscall fault */
1375 #if 0
1376     if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
1377         (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
1378     {
1379         /* Not yet implemented */
1380         UNIMPLEMENTED_FATAL();
1381     }
1382 #endif
1383 
1384     /* Check for VDM trap */
1385     if (KiVdmTrap(TrapFrame))
1386     {
1387         DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1388                 TrapFrame->SegCs, TrapFrame->Eip, Cr2);
1389         if (VdmDispatchPageFault(TrapFrame))
1390         {
1391             /* Return and end VDM execution */
1392             DPRINT1("VDM page fault with status 0x%lx resolved\n", Status);
1393             KiEoiHelper(TrapFrame);
1394         }
1395         DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status);
1396     }
1397 
1398     /* Either kernel or user trap (non VDM) so dispatch exception */
1399     if (Status == STATUS_ACCESS_VIOLATION)
1400     {
1401         /* This status code is repurposed so we can recognize it later */
1402         KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1403                                  TrapFrame->Eip,
1404                                  StoreInstruction,
1405                                  Cr2,
1406                                  TrapFrame);
1407     }
1408     else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
1409              (Status == STATUS_STACK_OVERFLOW))
1410     {
1411         /* These faults only have two parameters */
1412         KiDispatchException2Args(Status,
1413                                  TrapFrame->Eip,
1414                                  StoreInstruction,
1415                                  Cr2,
1416                                  TrapFrame);
1417     }
1418 
1419     /* Only other choice is an in-page error, with 3 parameters */
1420     KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
1421                                      0,
1422                                      TrapFrame->Eip,
1423                                      3,
1424                                      StoreInstruction,
1425                                      Cr2,
1426                                      Status,
1427                                      TrapFrame);
1428 }
1429 
1430 DECLSPEC_NORETURN
1431 VOID
1432 FASTCALL
1433 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
1434 {
1435     /* Save trap frame */
1436     KiEnterTrap(TrapFrame);
1437 
1438     /* FIXME: Kill the system */
1439     UNIMPLEMENTED;
1440     KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
1441 }
1442 
1443 DECLSPEC_NORETURN
1444 VOID
1445 FASTCALL
1446 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
1447 {
1448     PKTHREAD Thread;
1449     PFX_SAVE_AREA SaveArea;
1450 
1451     /* Save trap frame */
1452     KiEnterTrap(TrapFrame);
1453 
1454     /* Check if this is the NPX thrad */
1455     Thread = KeGetCurrentThread();
1456     SaveArea = KiGetThreadNpxArea(Thread);
1457     if (Thread != KeGetCurrentPrcb()->NpxThread)
1458     {
1459         /* It isn't, enable interrupts and set delayed error */
1460         _enable();
1461         SaveArea->Cr0NpxState |= CR0_TS;
1462 
1463         /* End trap */
1464         KiEoiHelper(TrapFrame);
1465     }
1466 
1467     /* Otherwise, proceed with NPX fault handling */
1468     KiNpxHandler(TrapFrame, Thread, SaveArea);
1469 }
1470 
1471 DECLSPEC_NORETURN
1472 VOID
1473 FASTCALL
1474 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
1475 {
1476     /* Save trap frame */
1477     KiEnterTrap(TrapFrame);
1478 
1479     /* Enable interrupts and kill the system */
1480     _enable();
1481     KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
1482 }
1483 
1484 DECLSPEC_NORETURN
1485 VOID
1486 FASTCALL
1487 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
1488 {
1489     PKTHREAD Thread;
1490     PFX_SAVE_AREA SaveArea;
1491     ULONG Cr0, MxCsrMask, Error;
1492 
1493     /* Save trap frame */
1494     KiEnterTrap(TrapFrame);
1495 
1496     /* Check if this is the NPX thrad */
1497     Thread = KeGetCurrentThread();
1498     if (Thread != KeGetCurrentPrcb()->NpxThread)
1499     {
1500         /* It isn't, kill the system */
1501         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
1502     }
1503 
1504     /* Get the NPX frame */
1505     SaveArea = KiGetThreadNpxArea(Thread);
1506 
1507     /* Check for VDM trap */
1508     ASSERT(KiVdmTrap(TrapFrame) == FALSE);
1509 
1510     /* Check for user trap */
1511     if (!KiUserTrap(TrapFrame))
1512     {
1513         /* Kernel should not fault on XMMI */
1514         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
1515     }
1516 
1517     /* Update CR0 */
1518     Cr0 = __readcr0();
1519     Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
1520     __writecr0(Cr0);
1521 
1522     /* Save FPU state */
1523     Ke386SaveFpuState(SaveArea);
1524 
1525     /* Mark CR0 state dirty */
1526     Cr0 |= NPX_STATE_NOT_LOADED;
1527     Cr0 |= SaveArea->Cr0NpxState;
1528      __writecr0(Cr0);
1529 
1530     /* Update NPX state */
1531     Thread->NpxState = NPX_STATE_NOT_LOADED;
1532     KeGetCurrentPrcb()->NpxThread = NULL;
1533 
1534     /* Clear the TS bit and re-enable interrupts */
1535     SaveArea->Cr0NpxState &= ~CR0_TS;
1536     _enable();
1537 
1538     /* Now look at MxCsr to get the mask of errors we should care about */
1539     MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
1540 
1541     /* Get legal exceptions that software should handle */
1542     Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
1543                                                 FSW_DENORMAL |
1544                                                 FSW_ZERO_DIVIDE |
1545                                                 FSW_OVERFLOW |
1546                                                 FSW_UNDERFLOW |
1547                                                 FSW_PRECISION);
1548     Error &= MxCsrMask;
1549 
1550     /* Now handle any of those legal errors */
1551     if (Error & (FSW_INVALID_OPERATION |
1552                  FSW_DENORMAL |
1553                  FSW_ZERO_DIVIDE |
1554                  FSW_OVERFLOW |
1555                  FSW_UNDERFLOW |
1556                  FSW_PRECISION))
1557     {
1558         /* By issuing an exception */
1559         KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
1560                                  TrapFrame->Eip,
1561                                  0,
1562                                  TrapFrame);
1563     }
1564 
1565     /* Unknown XMMI fault */
1566     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
1567 }
1568 
1569 /* SOFTWARE SERVICES **********************************************************/
1570 
1571 VOID
1572 FASTCALL
1573 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame)
1574 {
1575     /* Save trap frame */
1576     KiEnterTrap(TrapFrame);
1577 
1578     /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1579     TrapFrame->Eip -= 2;
1580 
1581     /* Check if this is a user trap */
1582     if (KiUserTrap(TrapFrame))
1583     {
1584         /* Dispatch exception to user mode */
1585         KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN,
1586                                          EXCEPTION_NONCONTINUABLE,
1587                                          TrapFrame->Eip,
1588                                          1,
1589                                          TrapFrame->Ecx,
1590                                          0,
1591                                          0,
1592                                          TrapFrame);
1593     }
1594     else
1595     {
1596         EXCEPTION_RECORD ExceptionRecord;
1597 
1598         /* Bugcheck the system */
1599         ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1600         ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
1601         ExceptionRecord.ExceptionRecord = NULL;
1602         ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Eip;
1603         ExceptionRecord.NumberParameters = 1;
1604         ExceptionRecord.ExceptionInformation[0] = TrapFrame->Ecx;
1605 
1606         KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE,
1607                          TrapFrame->Ecx,
1608                          (ULONG_PTR)TrapFrame,
1609                          (ULONG_PTR)&ExceptionRecord,
1610                          0,
1611                          TrapFrame);
1612     }
1613 }
1614 
1615 VOID
1616 FASTCALL
1617 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
1618 {
1619     /* Save trap frame */
1620     KiEnterTrap(TrapFrame);
1621 
1622     /*
1623      * Just fail the request
1624      */
1625     DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1626     TrapFrame->Eax = 0;
1627 
1628     /* Exit the trap */
1629     KiEoiHelper(TrapFrame);
1630 }
1631 
1632 VOID
1633 FASTCALL
1634 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
1635 {
1636     PKTHREAD Thread;
1637     NTSTATUS Status;
1638 
1639     /* Save the SEH chain, NtCallbackReturn will restore this */
1640     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1641 
1642     /* Set thread fields */
1643     Thread = KeGetCurrentThread();
1644     Thread->TrapFrame = TrapFrame;
1645     Thread->PreviousMode = KiUserTrap(TrapFrame);
1646     ASSERT(Thread->PreviousMode != KernelMode);
1647 
1648     /* Pass the register parameters to NtCallbackReturn.
1649        Result pointer is in ecx, result length in edx, status in eax */
1650     Status = NtCallbackReturn((PVOID)TrapFrame->Ecx,
1651                               TrapFrame->Edx,
1652                               TrapFrame->Eax);
1653 
1654     /* If we got here, something went wrong. Return an error to the caller */
1655     KiServiceExit(TrapFrame, Status);
1656 }
1657 
1658 DECLSPEC_NORETURN
1659 VOID
1660 FASTCALL
1661 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
1662 {
1663     /* Save trap frame */
1664     KiEnterTrap(TrapFrame);
1665 
1666     /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1667     TrapFrame->Eip -= 2;
1668 
1669     /* Dispatch the exception */
1670     KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
1671                              TrapFrame->Eip,
1672                              TrapFrame);
1673 }
1674 
1675 DECLSPEC_NORETURN
1676 VOID
1677 FASTCALL
1678 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
1679 {
1680     /* Save trap frame */
1681     KiEnterTrap(TrapFrame);
1682 
1683     /* Increment EIP to skip the INT3 instruction */
1684     TrapFrame->Eip++;
1685 
1686     /* Continue with the common handler */
1687     KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1688 }
1689 
1690 
1691 FORCEINLINE
1692 VOID
1693 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments)
1694 {
1695 #if DBG && !defined(_WINKD_)
1696     if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook)
1697         KeWin32PreServiceHook(SystemCallNumber, Arguments);
1698 #endif
1699 }
1700 
1701 FORCEINLINE
1702 ULONG_PTR
1703 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
1704 {
1705 #if DBG && !defined(_WINKD_)
1706     if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook)
1707         return KeWin32PostServiceHook(SystemCallNumber, Result);
1708 #endif
1709     return Result;
1710 }
1711 
1712 DECLSPEC_NORETURN
1713 VOID
1714 FASTCALL
1715 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
1716                        IN PVOID Arguments)
1717 {
1718     PKTHREAD Thread;
1719     PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
1720     ULONG Id, Offset, StackBytes;
1721     NTSTATUS Status;
1722     PVOID Handler;
1723     ULONG SystemCallNumber = TrapFrame->Eax;
1724 
1725     /* Get the current thread */
1726     Thread = KeGetCurrentThread();
1727 
1728     /* Set debug header */
1729     KiFillTrapFrameDebug(TrapFrame);
1730 
1731     /* Chain trap frames */
1732     TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
1733 
1734     /* No error code */
1735     TrapFrame->ErrCode = 0;
1736 
1737     /* Save previous mode */
1738     TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
1739 
1740     /* Save the SEH chain and terminate it for now */
1741     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1742     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
1743 
1744     /* Default to debugging disabled */
1745     TrapFrame->Dr7 = 0;
1746 
1747     /* Check if the frame was from user mode */
1748     if (KiUserTrap(TrapFrame))
1749     {
1750         /* Check for active debugging */
1751         if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
1752         {
1753             /* Handle debug registers */
1754             KiHandleDebugRegistersOnTrapEntry(TrapFrame);
1755         }
1756     }
1757 
1758     /* Set thread fields */
1759     Thread->TrapFrame = TrapFrame;
1760     Thread->PreviousMode = KiUserTrap(TrapFrame);
1761 
1762     /* Enable interrupts */
1763     _enable();
1764 
1765     /* Decode the system call number */
1766     Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
1767     Id = SystemCallNumber & SERVICE_NUMBER_MASK;
1768 
1769     /* Get descriptor table */
1770     DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
1771 
1772     /* Validate the system call number */
1773     if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
1774     {
1775         /* Check if this is a GUI call */
1776         if (!(Offset & SERVICE_TABLE_TEST))
1777         {
1778             /* Fail the call */
1779             Status = STATUS_INVALID_SYSTEM_SERVICE;
1780             goto ExitCall;
1781         }
1782 
1783         /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1784         Status = KiConvertToGuiThread();
1785 
1786         /* Reload trap frame and descriptor table pointer from new stack */
1787         TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
1788         DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
1789 
1790         if (!NT_SUCCESS(Status))
1791         {
1792             /* Set the last error and fail */
1793             goto ExitCall;
1794         }
1795 
1796         /* Validate the system call number again */
1797         if (Id >= DescriptorTable->Limit)
1798         {
1799             /* Fail the call */
1800             Status = STATUS_INVALID_SYSTEM_SERVICE;
1801             goto ExitCall;
1802         }
1803     }
1804 
1805     /* Check if this is a GUI call */
1806     if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
1807     {
1808         /* Get the batch count and flush if necessary */
1809         if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
1810     }
1811 
1812     /* Increase system call count */
1813     KeGetCurrentPrcb()->KeSystemCalls++;
1814 
1815     /* FIXME: Increase individual counts on debug systems */
1816     //KiIncreaseSystemCallCount(DescriptorTable, Id);
1817 
1818     /* Get stack bytes */
1819     StackBytes = DescriptorTable->Number[Id];
1820 
1821     /* Probe caller stack */
1822     if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
1823     {
1824         /* Access violation */
1825         UNIMPLEMENTED_FATAL();
1826     }
1827 
1828     /* Call pre-service debug hook */
1829     KiDbgPreServiceHook(SystemCallNumber, Arguments);
1830 
1831     /* Get the handler and make the system call */
1832     Handler = (PVOID)DescriptorTable->Base[Id];
1833     Status = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
1834 
1835     /* Call post-service debug hook */
1836     Status = KiDbgPostServiceHook(SystemCallNumber, Status);
1837 
1838     /* Make sure we're exiting correctly */
1839     KiExitSystemCallDebugChecks(Id, TrapFrame);
1840 
1841     /* Restore the old trap frame */
1842 ExitCall:
1843     Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
1844 
1845     /* Exit from system call */
1846     KiServiceExit(TrapFrame, Status);
1847 }
1848 
1849 VOID
1850 FASTCALL
1851 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame)
1852 {
1853     UNIMPLEMENTED;
1854 }
1855 
1856 /*
1857  * @implemented
1858  */
1859 VOID
1860 NTAPI
1861 Kei386EoiHelper(VOID)
1862 {
1863     /* We should never see this call happening */
1864     KeBugCheck(MISMATCHED_HAL);
1865 }
1866 
1867 /* EOF */
1868