xref: /reactos/ntoskrnl/ke/i386/traphdlr.c (revision 34593d93)
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. Fix EIP in case its a break breakpoint (sic) */
231     KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT,
232                                      0,
233                                      TrapFrame->Eip - (Parameter1 == BREAKPOINT_BREAK),
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 BOOLEAN
1220 FASTCALL
1221 KiCheckForSListFault(PKTRAP_FRAME TrapFrame)
1222 {
1223     /* Explanation: An S-List fault can occur due to a race condition between 2
1224        threads simultaneously trying to pop an element from the S-List. After
1225        thread 1 has read the pointer to the top element on the S-List it is
1226        preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List,
1227        removing the top element and freeing it's memory. After that thread 1
1228        resumes and tries to read the address of the Next pointer from the top
1229        element, which it assumes will be the next top element.
1230        But since that memory has been freed, we get a page fault. To handle this
1231        race condition, we let thread 1 repeat the operation.
1232        We do NOT invoke the page fault handler in this case, since we do not
1233        want to trigger any side effects, like paging or a guard page fault.
1234 
1235        Sequence of operations:
1236 
1237            Thread 1 : mov eax, [ebp] <= eax now points to the first element
1238            Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence
1239             *** preempted ***
1240            Thread 2 : calls InterlockedPopEntrySlist, changing the top element
1241            Thread 2 : frees the memory of the element that was popped
1242             *** preempted ***
1243            Thread 1 : checks if eax is NULL
1244            Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults
1245 
1246         To be sure that we are dealing with exactly the case described above, we
1247         check whether the ListHeader has changed. If Thread 2 only popped one
1248         entry, the Next field in the S-List-header has changed.
1249         If after thread 1 has faulted, thread 2 allocates a new element, by
1250         chance getting the same address as the previously freed element and
1251         pushes it on the list again, we will see the same top element, but the
1252         Sequence member of the S-List header has changed. Therefore we check
1253         both fields to make sure we catch any concurrent modification of the
1254         S-List-header.
1255     */
1256     if ((TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault) ||
1257         (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault))
1258     {
1259         ULARGE_INTEGER SListHeader;
1260         PVOID ResumeAddress;
1261 
1262         /* Sanity check that the assembly is correct:
1263            This must be mov ebx, [eax]
1264            Followed by cmpxchg8b [ebp] */
1265         ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) &&
1266                (((UCHAR*)TrapFrame->Eip)[1] == 0x18) &&
1267                (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) &&
1268                (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) &&
1269                (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) &&
1270                (((UCHAR*)TrapFrame->Eip)[5] == 0x00));
1271 
1272         /* Check if this is a user fault */
1273         if (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault)
1274         {
1275             /* EBP points to the S-List-header. Copy it inside SEH, to protect
1276                against a bogus pointer from user mode */
1277             _SEH2_TRY
1278             {
1279                 ProbeForRead((PVOID)TrapFrame->Ebp,
1280                              sizeof(ULARGE_INTEGER),
1281                              TYPE_ALIGNMENT(SLIST_HEADER));
1282                 SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp;
1283             }
1284             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1285             {
1286                 /* The S-List pointer is not valid! */
1287                 return FALSE;
1288             }
1289             _SEH2_END;
1290             ResumeAddress = KeUserPopEntrySListResume;
1291         }
1292         else
1293         {
1294             SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp;
1295             ResumeAddress = ExpInterlockedPopEntrySListResume;
1296         }
1297 
1298         /* Check if either the Next pointer or the Sequence member in the
1299            S-List-header has changed. If any of these has changed, we restart
1300            the operation. Otherwise we only have a bogus pointer and let the
1301            page fault handler deal with it. */
1302         if ((SListHeader.LowPart != TrapFrame->Eax) ||
1303             (SListHeader.HighPart != TrapFrame->Edx))
1304         {
1305             DPRINT1("*** Got an S-List-Fault ***\n");
1306             KeGetCurrentThread()->SListFaultCount++;
1307 
1308             /* Restart the operation */
1309             TrapFrame->Eip = (ULONG_PTR)ResumeAddress;
1310 
1311             return TRUE;
1312         }
1313     }
1314 
1315     return FALSE;
1316 }
1317 
1318 DECLSPEC_NORETURN
1319 VOID
1320 FASTCALL
1321 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
1322 {
1323     PKTHREAD Thread;
1324     BOOLEAN StoreInstruction;
1325     ULONG_PTR Cr2;
1326     NTSTATUS Status;
1327 
1328     /* Save trap frame */
1329     KiEnterTrap(TrapFrame);
1330 
1331     /* Check if this is the base frame */
1332     Thread = KeGetCurrentThread();
1333     if (KeGetTrapFrame(Thread) != TrapFrame)
1334     {
1335         /* It isn't, check if this is a second nested frame */
1336         if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
1337             FIELD_OFFSET(KTRAP_FRAME, EFlags))
1338         {
1339             /* The stack is somewhere in between frames, we need to fix it */
1340             UNIMPLEMENTED_FATAL();
1341         }
1342     }
1343 
1344     /* Save CR2 */
1345     Cr2 = __readcr2();
1346 
1347     /* Enable interrupts */
1348     _enable();
1349 
1350     /* Interpret the error code */
1351     StoreInstruction = (TrapFrame->ErrCode & 2) != 0;
1352 
1353     /* Check if we came in with interrupts disabled */
1354     if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1355     {
1356         /* This is completely illegal, bugcheck the system */
1357         KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
1358                          Cr2,
1359                          (ULONG_PTR)-1,
1360                          TrapFrame->ErrCode,
1361                          TrapFrame->Eip,
1362                          TrapFrame);
1363     }
1364 
1365     /* Check for S-List fault */
1366     if (KiCheckForSListFault(TrapFrame))
1367     {
1368         /* Continue execution */
1369         KiEoiHelper(TrapFrame);
1370     }
1371 
1372     /* Call the access fault handler */
1373     Status = MmAccessFault(TrapFrame->ErrCode,
1374                            (PVOID)Cr2,
1375                            KiUserTrap(TrapFrame),
1376                            TrapFrame);
1377     if (NT_SUCCESS(Status))
1378     {
1379         /* Check whether the kernel debugger has owed breakpoints to be inserted */
1380         KdSetOwedBreakpoints();
1381         /* We succeeded, return */
1382         KiEoiHelper(TrapFrame);
1383     }
1384 
1385     /* Check for syscall fault */
1386 #if 0
1387     if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
1388         (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
1389     {
1390         /* Not yet implemented */
1391         UNIMPLEMENTED_FATAL();
1392     }
1393 #endif
1394 
1395     /* Check for VDM trap */
1396     if (KiVdmTrap(TrapFrame))
1397     {
1398         DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1399                 TrapFrame->SegCs, TrapFrame->Eip, Cr2);
1400         if (VdmDispatchPageFault(TrapFrame))
1401         {
1402             /* Return and end VDM execution */
1403             DPRINT1("VDM page fault with status 0x%lx resolved\n", Status);
1404             KiEoiHelper(TrapFrame);
1405         }
1406         DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status);
1407     }
1408 
1409     /* Either kernel or user trap (non VDM) so dispatch exception */
1410     if (Status == STATUS_ACCESS_VIOLATION)
1411     {
1412         /* This status code is repurposed so we can recognize it later */
1413         KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1414                                  TrapFrame->Eip,
1415                                  StoreInstruction,
1416                                  Cr2,
1417                                  TrapFrame);
1418     }
1419     else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
1420              (Status == STATUS_STACK_OVERFLOW))
1421     {
1422         /* These faults only have two parameters */
1423         KiDispatchException2Args(Status,
1424                                  TrapFrame->Eip,
1425                                  StoreInstruction,
1426                                  Cr2,
1427                                  TrapFrame);
1428     }
1429 
1430     /* Only other choice is an in-page error, with 3 parameters */
1431     KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
1432                                      0,
1433                                      TrapFrame->Eip,
1434                                      3,
1435                                      StoreInstruction,
1436                                      Cr2,
1437                                      Status,
1438                                      TrapFrame);
1439 }
1440 
1441 DECLSPEC_NORETURN
1442 VOID
1443 FASTCALL
1444 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
1445 {
1446     /* Save trap frame */
1447     KiEnterTrap(TrapFrame);
1448 
1449     /* FIXME: Kill the system */
1450     UNIMPLEMENTED;
1451     KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
1452 }
1453 
1454 DECLSPEC_NORETURN
1455 VOID
1456 FASTCALL
1457 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
1458 {
1459     PKTHREAD Thread;
1460     PFX_SAVE_AREA SaveArea;
1461 
1462     /* Save trap frame */
1463     KiEnterTrap(TrapFrame);
1464 
1465     /* Check if this is the NPX thrad */
1466     Thread = KeGetCurrentThread();
1467     SaveArea = KiGetThreadNpxArea(Thread);
1468     if (Thread != KeGetCurrentPrcb()->NpxThread)
1469     {
1470         /* It isn't, enable interrupts and set delayed error */
1471         _enable();
1472         SaveArea->Cr0NpxState |= CR0_TS;
1473 
1474         /* End trap */
1475         KiEoiHelper(TrapFrame);
1476     }
1477 
1478     /* Otherwise, proceed with NPX fault handling */
1479     KiNpxHandler(TrapFrame, Thread, SaveArea);
1480 }
1481 
1482 DECLSPEC_NORETURN
1483 VOID
1484 FASTCALL
1485 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
1486 {
1487     /* Save trap frame */
1488     KiEnterTrap(TrapFrame);
1489 
1490     /* Enable interrupts and kill the system */
1491     _enable();
1492     KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
1493 }
1494 
1495 DECLSPEC_NORETURN
1496 VOID
1497 FASTCALL
1498 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
1499 {
1500     PKTHREAD Thread;
1501     PFX_SAVE_AREA SaveArea;
1502     ULONG Cr0, MxCsrMask, Error;
1503 
1504     /* Save trap frame */
1505     KiEnterTrap(TrapFrame);
1506 
1507     /* Check if this is the NPX thrad */
1508     Thread = KeGetCurrentThread();
1509     if (Thread != KeGetCurrentPrcb()->NpxThread)
1510     {
1511         /* It isn't, kill the system */
1512         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
1513     }
1514 
1515     /* Get the NPX frame */
1516     SaveArea = KiGetThreadNpxArea(Thread);
1517 
1518     /* Check for VDM trap */
1519     ASSERT(KiVdmTrap(TrapFrame) == FALSE);
1520 
1521     /* Check for user trap */
1522     if (!KiUserTrap(TrapFrame))
1523     {
1524         /* Kernel should not fault on XMMI */
1525         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
1526     }
1527 
1528     /* Update CR0 */
1529     Cr0 = __readcr0();
1530     Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
1531     __writecr0(Cr0);
1532 
1533     /* Save FPU state */
1534     Ke386SaveFpuState(SaveArea);
1535 
1536     /* Mark CR0 state dirty */
1537     Cr0 |= NPX_STATE_NOT_LOADED;
1538     Cr0 |= SaveArea->Cr0NpxState;
1539      __writecr0(Cr0);
1540 
1541     /* Update NPX state */
1542     Thread->NpxState = NPX_STATE_NOT_LOADED;
1543     KeGetCurrentPrcb()->NpxThread = NULL;
1544 
1545     /* Clear the TS bit and re-enable interrupts */
1546     SaveArea->Cr0NpxState &= ~CR0_TS;
1547     _enable();
1548 
1549     /* Now look at MxCsr to get the mask of errors we should care about */
1550     MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
1551 
1552     /* Get legal exceptions that software should handle */
1553     Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
1554                                                 FSW_DENORMAL |
1555                                                 FSW_ZERO_DIVIDE |
1556                                                 FSW_OVERFLOW |
1557                                                 FSW_UNDERFLOW |
1558                                                 FSW_PRECISION);
1559     Error &= MxCsrMask;
1560 
1561     /* Now handle any of those legal errors */
1562     if (Error & (FSW_INVALID_OPERATION |
1563                  FSW_DENORMAL |
1564                  FSW_ZERO_DIVIDE |
1565                  FSW_OVERFLOW |
1566                  FSW_UNDERFLOW |
1567                  FSW_PRECISION))
1568     {
1569         /* By issuing an exception */
1570         KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
1571                                  TrapFrame->Eip,
1572                                  0,
1573                                  TrapFrame);
1574     }
1575 
1576     /* Unknown XMMI fault */
1577     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
1578 }
1579 
1580 /* SOFTWARE SERVICES **********************************************************/
1581 
1582 VOID
1583 FASTCALL
1584 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame)
1585 {
1586     /* Save trap frame */
1587     KiEnterTrap(TrapFrame);
1588 
1589     /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1590     TrapFrame->Eip -= 2;
1591 
1592     /* Check if this is a user trap */
1593     if (KiUserTrap(TrapFrame))
1594     {
1595         /* Dispatch exception to user mode */
1596         KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN,
1597                                          EXCEPTION_NONCONTINUABLE,
1598                                          TrapFrame->Eip,
1599                                          1,
1600                                          TrapFrame->Ecx,
1601                                          0,
1602                                          0,
1603                                          TrapFrame);
1604     }
1605     else
1606     {
1607         EXCEPTION_RECORD ExceptionRecord;
1608 
1609         /* Bugcheck the system */
1610         ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1611         ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
1612         ExceptionRecord.ExceptionRecord = NULL;
1613         ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Eip;
1614         ExceptionRecord.NumberParameters = 1;
1615         ExceptionRecord.ExceptionInformation[0] = TrapFrame->Ecx;
1616 
1617         KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE,
1618                          TrapFrame->Ecx,
1619                          (ULONG_PTR)TrapFrame,
1620                          (ULONG_PTR)&ExceptionRecord,
1621                          0,
1622                          TrapFrame);
1623     }
1624 }
1625 
1626 VOID
1627 FASTCALL
1628 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
1629 {
1630     /* Save trap frame */
1631     KiEnterTrap(TrapFrame);
1632 
1633     /*
1634      * Just fail the request
1635      */
1636     DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1637     TrapFrame->Eax = 0;
1638 
1639     /* Exit the trap */
1640     KiEoiHelper(TrapFrame);
1641 }
1642 
1643 VOID
1644 FASTCALL
1645 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
1646 {
1647     PKTHREAD Thread;
1648     NTSTATUS Status;
1649 
1650     /* Save the SEH chain, NtCallbackReturn will restore this */
1651     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1652 
1653     /* Set thread fields */
1654     Thread = KeGetCurrentThread();
1655     Thread->TrapFrame = TrapFrame;
1656     Thread->PreviousMode = KiUserTrap(TrapFrame);
1657     ASSERT(Thread->PreviousMode != KernelMode);
1658 
1659     /* Pass the register parameters to NtCallbackReturn.
1660        Result pointer is in ecx, result length in edx, status in eax */
1661     Status = NtCallbackReturn((PVOID)TrapFrame->Ecx,
1662                               TrapFrame->Edx,
1663                               TrapFrame->Eax);
1664 
1665     /* If we got here, something went wrong. Return an error to the caller */
1666     KiServiceExit(TrapFrame, Status);
1667 }
1668 
1669 DECLSPEC_NORETURN
1670 VOID
1671 FASTCALL
1672 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
1673 {
1674     /* Save trap frame */
1675     KiEnterTrap(TrapFrame);
1676 
1677     /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1678     TrapFrame->Eip -= 2;
1679 
1680     /* Dispatch the exception */
1681     KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
1682                              TrapFrame->Eip,
1683                              TrapFrame);
1684 }
1685 
1686 DECLSPEC_NORETURN
1687 VOID
1688 FASTCALL
1689 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
1690 {
1691     /* Save trap frame */
1692     KiEnterTrap(TrapFrame);
1693 
1694     /* Increment EIP to skip the INT3 instruction */
1695     TrapFrame->Eip++;
1696 
1697     /* Continue with the common handler */
1698     KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1699 }
1700 
1701 
1702 FORCEINLINE
1703 VOID
1704 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments)
1705 {
1706 #if DBG && !defined(_WINKD_)
1707     if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook)
1708         KeWin32PreServiceHook(SystemCallNumber, Arguments);
1709 #endif
1710 }
1711 
1712 FORCEINLINE
1713 ULONG_PTR
1714 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
1715 {
1716 #if DBG && !defined(_WINKD_)
1717     if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook)
1718         return KeWin32PostServiceHook(SystemCallNumber, Result);
1719 #endif
1720     return Result;
1721 }
1722 
1723 DECLSPEC_NORETURN
1724 VOID
1725 FASTCALL
1726 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
1727                        IN PVOID Arguments)
1728 {
1729     PKTHREAD Thread;
1730     PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
1731     ULONG Id, Offset, StackBytes;
1732     NTSTATUS Status;
1733     PVOID Handler;
1734     ULONG SystemCallNumber = TrapFrame->Eax;
1735 
1736     /* Get the current thread */
1737     Thread = KeGetCurrentThread();
1738 
1739     /* Set debug header */
1740     KiFillTrapFrameDebug(TrapFrame);
1741 
1742     /* Chain trap frames */
1743     TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
1744 
1745     /* No error code */
1746     TrapFrame->ErrCode = 0;
1747 
1748     /* Save previous mode */
1749     TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
1750 
1751     /* Save the SEH chain and terminate it for now */
1752     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1753     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
1754 
1755     /* Default to debugging disabled */
1756     TrapFrame->Dr7 = 0;
1757 
1758     /* Check if the frame was from user mode */
1759     if (KiUserTrap(TrapFrame))
1760     {
1761         /* Check for active debugging */
1762         if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
1763         {
1764             /* Handle debug registers */
1765             KiHandleDebugRegistersOnTrapEntry(TrapFrame);
1766         }
1767     }
1768 
1769     /* Set thread fields */
1770     Thread->TrapFrame = TrapFrame;
1771     Thread->PreviousMode = KiUserTrap(TrapFrame);
1772 
1773     /* Enable interrupts */
1774     _enable();
1775 
1776     /* Decode the system call number */
1777     Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
1778     Id = SystemCallNumber & SERVICE_NUMBER_MASK;
1779 
1780     /* Get descriptor table */
1781     DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
1782 
1783     /* Validate the system call number */
1784     if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
1785     {
1786         /* Check if this is a GUI call */
1787         if (!(Offset & SERVICE_TABLE_TEST))
1788         {
1789             /* Fail the call */
1790             Status = STATUS_INVALID_SYSTEM_SERVICE;
1791             goto ExitCall;
1792         }
1793 
1794         /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1795         Status = KiConvertToGuiThread();
1796 
1797         /* Reload trap frame and descriptor table pointer from new stack */
1798         TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
1799         DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
1800 
1801         if (!NT_SUCCESS(Status))
1802         {
1803             /* Set the last error and fail */
1804             goto ExitCall;
1805         }
1806 
1807         /* Validate the system call number again */
1808         if (Id >= DescriptorTable->Limit)
1809         {
1810             /* Fail the call */
1811             Status = STATUS_INVALID_SYSTEM_SERVICE;
1812             goto ExitCall;
1813         }
1814     }
1815 
1816     /* Check if this is a GUI call */
1817     if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
1818     {
1819         /* Get the batch count and flush if necessary */
1820         if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
1821     }
1822 
1823     /* Increase system call count */
1824     KeGetCurrentPrcb()->KeSystemCalls++;
1825 
1826     /* FIXME: Increase individual counts on debug systems */
1827     //KiIncreaseSystemCallCount(DescriptorTable, Id);
1828 
1829     /* Get stack bytes */
1830     StackBytes = DescriptorTable->Number[Id];
1831 
1832     /* Probe caller stack */
1833     if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
1834     {
1835         /* Access violation */
1836         UNIMPLEMENTED_FATAL();
1837     }
1838 
1839     /* Call pre-service debug hook */
1840     KiDbgPreServiceHook(SystemCallNumber, Arguments);
1841 
1842     /* Get the handler and make the system call */
1843     Handler = (PVOID)DescriptorTable->Base[Id];
1844     Status = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
1845 
1846     /* Call post-service debug hook */
1847     Status = KiDbgPostServiceHook(SystemCallNumber, Status);
1848 
1849     /* Make sure we're exiting correctly */
1850     KiExitSystemCallDebugChecks(Id, TrapFrame);
1851 
1852     /* Restore the old trap frame */
1853 ExitCall:
1854     Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
1855 
1856     /* Exit from system call */
1857     KiServiceExit(TrapFrame, Status);
1858 }
1859 
1860 VOID
1861 FASTCALL
1862 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame)
1863 {
1864     UNIMPLEMENTED;
1865 }
1866 
1867 /*
1868  * @implemented
1869  */
1870 VOID
1871 NTAPI
1872 Kei386EoiHelper(VOID)
1873 {
1874     /* We should never see this call happening */
1875     KeBugCheck(MISMATCHED_HAL);
1876 }
1877 
1878 /* EOF */
1879