xref: /reactos/ntoskrnl/ke/i386/traphdlr.c (revision ffb20d33)
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
KiVdmTrap(IN PKTRAP_FRAME TrapFrame)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
KiV86Trap(IN PKTRAP_FRAME TrapFrame)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
KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame)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
KiCommonExit(IN PKTRAP_FRAME TrapFrame,BOOLEAN SkipPreviousMode)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
KiEoiHelper(IN PKTRAP_FRAME TrapFrame)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
KiServiceExit(IN PKTRAP_FRAME TrapFrame,IN NTSTATUS Status)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
KiServiceExit2(IN PKTRAP_FRAME TrapFrame)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
KiDebugHandler(IN PKTRAP_FRAME TrapFrame,IN ULONG Parameter1,IN ULONG Parameter2,IN ULONG Parameter3)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
KiNpxHandler(IN PKTRAP_FRAME TrapFrame,IN PKTHREAD Thread,IN PFX_SAVE_AREA SaveArea)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
KiTrap00Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap01Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap02Handler(VOID)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
KiTrap03Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap04Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap05Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap08Handler(VOID)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
KiTrap09Handler(IN PKTRAP_FRAME TrapFrame)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
KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame)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
KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame)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
KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame)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
KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)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 address, 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
KiCheckForSListFault(PKTRAP_FRAME TrapFrame)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
KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)1321 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
1322 {
1323     PKTHREAD Thread;
1324     ULONG_PTR Cr2;
1325     NTSTATUS Status;
1326 
1327     /* Save trap frame */
1328     KiEnterTrap(TrapFrame);
1329 
1330     /* Check if this is the base frame */
1331     Thread = KeGetCurrentThread();
1332     if (KeGetTrapFrame(Thread) != TrapFrame)
1333     {
1334         /* It isn't, check if this is a second nested frame */
1335         if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
1336             FIELD_OFFSET(KTRAP_FRAME, EFlags))
1337         {
1338             /* The stack is somewhere in between frames, we need to fix it */
1339             UNIMPLEMENTED_FATAL();
1340         }
1341     }
1342 
1343     /* Save CR2 */
1344     Cr2 = __readcr2();
1345 
1346     /* Enable interrupts */
1347     _enable();
1348 
1349     /* Check if we came in with interrupts disabled */
1350     if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
1351     {
1352         /* This is completely illegal, bugcheck the system */
1353         KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
1354                          Cr2,
1355                          (ULONG_PTR)-1,
1356                          TrapFrame->ErrCode,
1357                          TrapFrame->Eip,
1358                          TrapFrame);
1359     }
1360 
1361     /* Check for S-List fault */
1362     if (KiCheckForSListFault(TrapFrame))
1363     {
1364         /* Continue execution */
1365         KiEoiHelper(TrapFrame);
1366     }
1367 
1368     /* Call the access fault handler */
1369     Status = MmAccessFault(TrapFrame->ErrCode,
1370                            (PVOID)Cr2,
1371                            KiUserTrap(TrapFrame),
1372                            TrapFrame);
1373     if (NT_SUCCESS(Status))
1374     {
1375         /* Check whether the kernel debugger has owed breakpoints to be inserted */
1376         KdSetOwedBreakpoints();
1377         /* We succeeded, return */
1378         KiEoiHelper(TrapFrame);
1379     }
1380 
1381     /* Check for syscall fault */
1382 #if 0
1383     if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
1384         (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
1385     {
1386         /* Not yet implemented */
1387         UNIMPLEMENTED_FATAL();
1388     }
1389 #endif
1390 
1391     /* Check for VDM trap */
1392     if (KiVdmTrap(TrapFrame))
1393     {
1394         DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n",
1395                 TrapFrame->SegCs, TrapFrame->Eip, Cr2);
1396         if (VdmDispatchPageFault(TrapFrame))
1397         {
1398             /* Return and end VDM execution */
1399             DPRINT1("VDM page fault with status 0x%lx resolved\n", Status);
1400             KiEoiHelper(TrapFrame);
1401         }
1402         DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status);
1403     }
1404 
1405     /* Either kernel or user trap (non VDM) so dispatch exception */
1406     if (Status == STATUS_ACCESS_VIOLATION)
1407     {
1408         /* This status code is repurposed so we can recognize it later */
1409         KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
1410                                  TrapFrame->Eip,
1411                                  MI_IS_WRITE_ACCESS(TrapFrame->ErrCode),
1412                                  Cr2,
1413                                  TrapFrame);
1414     }
1415     else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
1416              (Status == STATUS_STACK_OVERFLOW))
1417     {
1418         /* These faults only have two parameters */
1419         KiDispatchException2Args(Status,
1420                                  TrapFrame->Eip,
1421                                  MI_IS_WRITE_ACCESS(TrapFrame->ErrCode),
1422                                  Cr2,
1423                                  TrapFrame);
1424     }
1425 
1426     /* Only other choice is an in-page error, with 3 parameters */
1427     KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
1428                                      0,
1429                                      TrapFrame->Eip,
1430                                      3,
1431                                      MI_IS_WRITE_ACCESS(TrapFrame->ErrCode),
1432                                      Cr2,
1433                                      Status,
1434                                      TrapFrame);
1435 }
1436 
1437 DECLSPEC_NORETURN
1438 VOID
1439 FASTCALL
KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)1440 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
1441 {
1442     /* Save trap frame */
1443     KiEnterTrap(TrapFrame);
1444 
1445     /* FIXME: Kill the system */
1446     UNIMPLEMENTED;
1447     KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
1448 }
1449 
1450 DECLSPEC_NORETURN
1451 VOID
1452 FASTCALL
KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)1453 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
1454 {
1455     PKTHREAD Thread;
1456     PFX_SAVE_AREA SaveArea;
1457 
1458     /* Save trap frame */
1459     KiEnterTrap(TrapFrame);
1460 
1461     /* Check if this is the NPX thrad */
1462     Thread = KeGetCurrentThread();
1463     SaveArea = KiGetThreadNpxArea(Thread);
1464     if (Thread != KeGetCurrentPrcb()->NpxThread)
1465     {
1466         /* It isn't, enable interrupts and set delayed error */
1467         _enable();
1468         SaveArea->Cr0NpxState |= CR0_TS;
1469 
1470         /* End trap */
1471         KiEoiHelper(TrapFrame);
1472     }
1473 
1474     /* Otherwise, proceed with NPX fault handling */
1475     KiNpxHandler(TrapFrame, Thread, SaveArea);
1476 }
1477 
1478 DECLSPEC_NORETURN
1479 VOID
1480 FASTCALL
KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)1481 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
1482 {
1483     /* Save trap frame */
1484     KiEnterTrap(TrapFrame);
1485 
1486     /* Enable interrupts and kill the system */
1487     _enable();
1488     KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
1489 }
1490 
1491 DECLSPEC_NORETURN
1492 VOID
1493 FASTCALL
KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)1494 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
1495 {
1496     PKTHREAD Thread;
1497     PFX_SAVE_AREA SaveArea;
1498     ULONG Cr0, MxCsrMask, Error;
1499 
1500     /* Save trap frame */
1501     KiEnterTrap(TrapFrame);
1502 
1503     /* Check if this is the NPX thrad */
1504     Thread = KeGetCurrentThread();
1505     if (Thread != KeGetCurrentPrcb()->NpxThread)
1506     {
1507         /* It isn't, kill the system */
1508         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
1509     }
1510 
1511     /* Get the NPX frame */
1512     SaveArea = KiGetThreadNpxArea(Thread);
1513 
1514     /* Check for VDM trap */
1515     ASSERT(KiVdmTrap(TrapFrame) == FALSE);
1516 
1517     /* Check for user trap */
1518     if (!KiUserTrap(TrapFrame))
1519     {
1520         /* Kernel should not fault on XMMI */
1521         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
1522     }
1523 
1524     /* Update CR0 */
1525     Cr0 = __readcr0();
1526     Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
1527     __writecr0(Cr0);
1528 
1529     /* Save FPU state */
1530     Ke386SaveFpuState(SaveArea);
1531 
1532     /* Mark CR0 state dirty */
1533     Cr0 |= NPX_STATE_NOT_LOADED;
1534     Cr0 |= SaveArea->Cr0NpxState;
1535      __writecr0(Cr0);
1536 
1537     /* Update NPX state */
1538     Thread->NpxState = NPX_STATE_NOT_LOADED;
1539     KeGetCurrentPrcb()->NpxThread = NULL;
1540 
1541     /* Clear the TS bit and re-enable interrupts */
1542     SaveArea->Cr0NpxState &= ~CR0_TS;
1543     _enable();
1544 
1545     /* Now look at MxCsr to get the mask of errors we should care about */
1546     MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
1547 
1548     /* Get legal exceptions that software should handle */
1549     Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
1550                                                 FSW_DENORMAL |
1551                                                 FSW_ZERO_DIVIDE |
1552                                                 FSW_OVERFLOW |
1553                                                 FSW_UNDERFLOW |
1554                                                 FSW_PRECISION);
1555     Error &= MxCsrMask;
1556 
1557     /* Now handle any of those legal errors */
1558     if (Error & (FSW_INVALID_OPERATION |
1559                  FSW_DENORMAL |
1560                  FSW_ZERO_DIVIDE |
1561                  FSW_OVERFLOW |
1562                  FSW_UNDERFLOW |
1563                  FSW_PRECISION))
1564     {
1565         /* By issuing an exception */
1566         KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
1567                                  TrapFrame->Eip,
1568                                  0,
1569                                  TrapFrame);
1570     }
1571 
1572     /* Unknown XMMI fault */
1573     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
1574 }
1575 
1576 /* SOFTWARE SERVICES **********************************************************/
1577 
1578 VOID
1579 FASTCALL
KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame)1580 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame)
1581 {
1582     /* Save trap frame */
1583     KiEnterTrap(TrapFrame);
1584 
1585     /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */
1586     TrapFrame->Eip -= 2;
1587 
1588     /* Check if this is a user trap */
1589     if (KiUserTrap(TrapFrame))
1590     {
1591         /* Dispatch exception to user mode */
1592         KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN,
1593                                          EXCEPTION_NONCONTINUABLE,
1594                                          TrapFrame->Eip,
1595                                          1,
1596                                          TrapFrame->Ecx,
1597                                          0,
1598                                          0,
1599                                          TrapFrame);
1600     }
1601     else
1602     {
1603         EXCEPTION_RECORD ExceptionRecord;
1604 
1605         /* Bugcheck the system */
1606         ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1607         ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
1608         ExceptionRecord.ExceptionRecord = NULL;
1609         ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Eip;
1610         ExceptionRecord.NumberParameters = 1;
1611         ExceptionRecord.ExceptionInformation[0] = TrapFrame->Ecx;
1612 
1613         KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE,
1614                          TrapFrame->Ecx,
1615                          (ULONG_PTR)TrapFrame,
1616                          (ULONG_PTR)&ExceptionRecord,
1617                          0,
1618                          TrapFrame);
1619     }
1620 }
1621 
1622 VOID
1623 FASTCALL
KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)1624 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
1625 {
1626     /* Save trap frame */
1627     KiEnterTrap(TrapFrame);
1628 
1629     /*
1630      * Just fail the request
1631      */
1632     DbgPrint("INT 0x2A attempted, returning 0 tick count\n");
1633     TrapFrame->Eax = 0;
1634 
1635     /* Exit the trap */
1636     KiEoiHelper(TrapFrame);
1637 }
1638 
1639 VOID
1640 FASTCALL
KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)1641 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
1642 {
1643     PKTHREAD Thread;
1644     NTSTATUS Status;
1645 
1646     /* Save the SEH chain, NtCallbackReturn will restore this */
1647     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1648 
1649     /* Set thread fields */
1650     Thread = KeGetCurrentThread();
1651     Thread->TrapFrame = TrapFrame;
1652     Thread->PreviousMode = KiUserTrap(TrapFrame);
1653     ASSERT(Thread->PreviousMode != KernelMode);
1654 
1655     /* Pass the register parameters to NtCallbackReturn.
1656        Result pointer is in ecx, result length in edx, status in eax */
1657     Status = NtCallbackReturn((PVOID)TrapFrame->Ecx,
1658                               TrapFrame->Edx,
1659                               TrapFrame->Eax);
1660 
1661     /* If we got here, something went wrong. Return an error to the caller */
1662     KiServiceExit(TrapFrame, Status);
1663 }
1664 
1665 DECLSPEC_NORETURN
1666 VOID
1667 FASTCALL
KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)1668 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
1669 {
1670     /* Save trap frame */
1671     KiEnterTrap(TrapFrame);
1672 
1673     /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
1674     TrapFrame->Eip -= 2;
1675 
1676     /* Dispatch the exception */
1677     KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
1678                              TrapFrame->Eip,
1679                              TrapFrame);
1680 }
1681 
1682 DECLSPEC_NORETURN
1683 VOID
1684 FASTCALL
KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)1685 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
1686 {
1687     /* Save trap frame */
1688     KiEnterTrap(TrapFrame);
1689 
1690     /* Increment EIP to skip the INT3 instruction */
1691     TrapFrame->Eip++;
1692 
1693     /* Continue with the common handler */
1694     KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
1695 }
1696 
1697 
1698 FORCEINLINE
1699 VOID
KiDbgPreServiceHook(ULONG SystemCallNumber,PULONG_PTR Arguments)1700 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments)
1701 {
1702 #if DBG && !defined(_WINKD_)
1703     if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook)
1704         KeWin32PreServiceHook(SystemCallNumber, Arguments);
1705 #endif
1706 }
1707 
1708 FORCEINLINE
1709 ULONG_PTR
KiDbgPostServiceHook(ULONG SystemCallNumber,ULONG_PTR Result)1710 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
1711 {
1712 #if DBG && !defined(_WINKD_)
1713     if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook)
1714         return KeWin32PostServiceHook(SystemCallNumber, Result);
1715 #endif
1716     return Result;
1717 }
1718 
1719 DECLSPEC_NORETURN
1720 VOID
1721 FASTCALL
KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,IN PVOID Arguments)1722 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
1723                        IN PVOID Arguments)
1724 {
1725     PKTHREAD Thread;
1726     PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
1727     ULONG Id, Offset, StackBytes;
1728     NTSTATUS Status;
1729     PVOID Handler;
1730     ULONG SystemCallNumber = TrapFrame->Eax;
1731 
1732     /* Get the current thread */
1733     Thread = KeGetCurrentThread();
1734 
1735     /* Set debug header */
1736     KiFillTrapFrameDebug(TrapFrame);
1737 
1738     /* Chain trap frames */
1739     TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
1740 
1741     /* No error code */
1742     TrapFrame->ErrCode = 0;
1743 
1744     /* Save previous mode */
1745     TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
1746 
1747     /* Save the SEH chain and terminate it for now */
1748     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
1749     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
1750 
1751     /* Default to debugging disabled */
1752     TrapFrame->Dr7 = 0;
1753 
1754     /* Check if the frame was from user mode */
1755     if (KiUserTrap(TrapFrame))
1756     {
1757         /* Check for active debugging */
1758         if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
1759         {
1760             /* Handle debug registers */
1761             KiHandleDebugRegistersOnTrapEntry(TrapFrame);
1762         }
1763     }
1764 
1765     /* Set thread fields */
1766     Thread->TrapFrame = TrapFrame;
1767     Thread->PreviousMode = KiUserTrap(TrapFrame);
1768 
1769     /* Enable interrupts */
1770     _enable();
1771 
1772     /* Decode the system call number */
1773     Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
1774     Id = SystemCallNumber & SERVICE_NUMBER_MASK;
1775 
1776     /* Get descriptor table */
1777     DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
1778 
1779     /* Validate the system call number */
1780     if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
1781     {
1782         /* Check if this is a GUI call */
1783         if (!(Offset & SERVICE_TABLE_TEST))
1784         {
1785             /* Fail the call */
1786             Status = STATUS_INVALID_SYSTEM_SERVICE;
1787             goto ExitCall;
1788         }
1789 
1790         /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
1791         Status = KiConvertToGuiThread();
1792 
1793         /* Reload trap frame and descriptor table pointer from new stack */
1794         TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
1795         DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
1796 
1797         if (!NT_SUCCESS(Status))
1798         {
1799             /* Set the last error and fail */
1800             goto ExitCall;
1801         }
1802 
1803         /* Validate the system call number again */
1804         if (Id >= DescriptorTable->Limit)
1805         {
1806             /* Fail the call */
1807             Status = STATUS_INVALID_SYSTEM_SERVICE;
1808             goto ExitCall;
1809         }
1810     }
1811 
1812     /* Check if this is a GUI call */
1813     if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
1814     {
1815         /* Get the batch count and flush if necessary */
1816         if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
1817     }
1818 
1819     /* Increase system call count */
1820     KeGetCurrentPrcb()->KeSystemCalls++;
1821 
1822     /* FIXME: Increase individual counts on debug systems */
1823     //KiIncreaseSystemCallCount(DescriptorTable, Id);
1824 
1825     /* Get stack bytes */
1826     StackBytes = DescriptorTable->Number[Id];
1827 
1828     /* Probe caller stack */
1829     if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
1830     {
1831         /* Access violation */
1832         UNIMPLEMENTED_FATAL();
1833     }
1834 
1835     /* Call pre-service debug hook */
1836     KiDbgPreServiceHook(SystemCallNumber, Arguments);
1837 
1838     /* Get the handler and make the system call */
1839     Handler = (PVOID)DescriptorTable->Base[Id];
1840     Status = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
1841 
1842     /* Call post-service debug hook */
1843     Status = KiDbgPostServiceHook(SystemCallNumber, Status);
1844 
1845     /* Make sure we're exiting correctly */
1846     KiExitSystemCallDebugChecks(Id, TrapFrame);
1847 
1848     /* Restore the old trap frame */
1849 ExitCall:
1850     Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
1851 
1852     /* Exit from system call */
1853     KiServiceExit(TrapFrame, Status);
1854 }
1855 
1856 VOID
1857 FASTCALL
KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame)1858 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame)
1859 {
1860     UNIMPLEMENTED;
1861 }
1862 
1863 /*
1864  * @implemented
1865  */
1866 VOID
1867 NTAPI
Kei386EoiHelper(VOID)1868 Kei386EoiHelper(VOID)
1869 {
1870     /* We should never see this call happening */
1871     KeBugCheck(MISMATCHED_HAL);
1872 }
1873 
1874 /* EOF */
1875