Doxygen

traphdlr.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            ntoskrnl/ke/i386/traphdlr.c
00005  * PURPOSE:         Kernel Trap Handlers
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* GLOBALS ********************************************************************/
00016 
00017 UCHAR KiTrapPrefixTable[] =
00018 {
00019     0xF2,                      /* REP                                  */
00020     0xF3,                      /* REP INS/OUTS                         */
00021     0x67,                      /* ADDR                                 */
00022     0xF0,                      /* LOCK                                 */
00023     0x66,                      /* OP                                   */
00024     0x2E,                      /* SEG                                  */
00025     0x3E,                      /* DS                                   */
00026     0x26,                      /* ES                                   */
00027     0x64,                      /* FS                                   */
00028     0x65,                      /* GS                                   */
00029     0x36,                      /* SS                                   */
00030 };
00031 
00032 UCHAR KiTrapIoTable[] =
00033 {
00034     0xE4,                      /* IN                                   */
00035     0xE5,                      /* IN                                   */
00036     0xEC,                      /* IN                                   */
00037     0xED,                      /* IN                                   */
00038     0x6C,                      /* INS                                  */
00039     0x6D,                      /* INS                                  */
00040     0xE6,                      /* OUT                                  */
00041     0xE7,                      /* OUT                                  */
00042     0xEE,                      /* OUT                                  */
00043     0xEF,                      /* OUT                                  */
00044     0x6E,                      /* OUTS                                 */
00045     0x6F,                      /* OUTS                                 */
00046 };
00047 
00048 PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler;
00049 #if DBG && !defined(_WINKD_)
00050 PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL;
00051 PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL;
00052 #endif
00053 #if TRAP_DEBUG
00054 BOOLEAN StopChecking = FALSE;
00055 #endif
00056 
00057 
00058 /* TRAP EXIT CODE *************************************************************/
00059 
00060 BOOLEAN
00061 FORCEINLINE
00062 KiVdmTrap(IN PKTRAP_FRAME TrapFrame)
00063 {
00064     /* Either the V8086 flag is on, or this is user-mode with a VDM */
00065     return ((TrapFrame->EFlags & EFLAGS_V86_MASK) ||
00066             ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects)));
00067 }
00068 
00069 BOOLEAN
00070 FORCEINLINE
00071 KiV86Trap(IN PKTRAP_FRAME TrapFrame)
00072 {
00073     /* Check if the V8086 flag is on */
00074     return ((TrapFrame->EFlags & EFLAGS_V86_MASK) != 0);
00075 }
00076 
00077 BOOLEAN
00078 FORCEINLINE
00079 KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame)
00080 {
00081     /* An edited frame changes esp. It is marked by clearing the bits
00082        defined by FRAME_EDITED in the SegCs field of the trap frame */
00083     return ((TrapFrame->SegCs & FRAME_EDITED) == 0);
00084 }
00085 
00086 VOID
00087 FORCEINLINE
00088 KiCommonExit(IN PKTRAP_FRAME TrapFrame, BOOLEAN SkipPreviousMode)
00089 {
00090     /* Disable interrupts until we return */
00091     _disable();
00092 
00093     /* Check for APC delivery */
00094     KiCheckForApcDelivery(TrapFrame);
00095 
00096     /* Restore the SEH handler chain */
00097     KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
00098 
00099     /* Check if there are active debug registers */
00100     if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0))
00101     {
00102         /* Check if the frame was from user mode or v86 mode */
00103         if ((TrapFrame->SegCs & MODE_MASK) ||
00104             (TrapFrame->EFlags & EFLAGS_V86_MASK))
00105         {
00106             /* Handle debug registers */
00107             KiHandleDebugRegistersOnTrapExit(TrapFrame);
00108         }
00109     }
00110 
00111     /* Debugging checks */
00112     KiExitTrapDebugChecks(TrapFrame, SkipPreviousMode);
00113 }
00114 
00115 DECLSPEC_NORETURN
00116 VOID
00117 FASTCALL
00118 KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
00119 {
00120     /* Common trap exit code */
00121     KiCommonExit(TrapFrame, TRUE);
00122 
00123     /* Check if this was a V8086 trap */
00124     if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame);
00125 
00126     /* Check for user mode exit */
00127     if (TrapFrame->SegCs & MODE_MASK) KiTrapReturn(TrapFrame);
00128 
00129     /* Check for edited frame */
00130     if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame);
00131 
00132     /* Exit the trap to kernel mode */
00133     KiTrapReturnNoSegments(TrapFrame);
00134 }
00135 
00136 DECLSPEC_NORETURN
00137 VOID
00138 FASTCALL
00139 KiServiceExit(IN PKTRAP_FRAME TrapFrame,
00140               IN NTSTATUS Status)
00141 {
00142     ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) == 0);
00143     ASSERT(!KiIsFrameEdited(TrapFrame));
00144     
00145     /* Copy the status into EAX */
00146     TrapFrame->Eax = Status;
00147     
00148     /* Common trap exit code */
00149     KiCommonExit(TrapFrame, FALSE);
00150     
00151     /* Restore previous mode */
00152     KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode;
00153 
00154     /* Check for user mode exit */
00155     if (TrapFrame->SegCs & MODE_MASK)
00156     {
00157         /* Check if we were single stepping */
00158         if (TrapFrame->EFlags & EFLAGS_TF)
00159         {
00160             /* Must use the IRET handler */
00161             KiSystemCallTrapReturn(TrapFrame);
00162         }
00163         else
00164         {
00165             /* We can use the sysexit handler */
00166             KiFastCallExitHandler(TrapFrame);
00167         }
00168     }
00169 
00170     /* Exit to kernel mode */
00171     KiSystemCallReturn(TrapFrame);
00172 }
00173 
00174 DECLSPEC_NORETURN
00175 VOID
00176 FASTCALL
00177 KiServiceExit2(IN PKTRAP_FRAME TrapFrame)
00178 {
00179     /* Common trap exit code */
00180     KiCommonExit(TrapFrame, FALSE);
00181     
00182     /* Restore previous mode */
00183     KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode;
00184     
00185     /* Check if this was a V8086 trap */
00186     if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame);
00187 
00188     /* Check for user mode exit */
00189     if (TrapFrame->SegCs & MODE_MASK) KiTrapReturn(TrapFrame);
00190 
00191     /* Check for edited frame */
00192     if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame);
00193 
00194     /* Exit the trap to kernel mode */
00195     KiTrapReturnNoSegments(TrapFrame);
00196 }
00197 
00198 
00199 /* TRAP HANDLERS **************************************************************/
00200 
00201 DECLSPEC_NORETURN
00202 VOID
00203 FASTCALL
00204 KiDebugHandler(IN PKTRAP_FRAME TrapFrame,
00205                IN ULONG Parameter1,
00206                IN ULONG Parameter2,
00207                IN ULONG Parameter3)
00208 {
00209     /* Check for VDM trap */
00210     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
00211 
00212     /* Enable interrupts if the trap came from user-mode */
00213     if (KiUserTrap(TrapFrame)) _enable();
00214 
00215     /* Dispatch the exception  */
00216     KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT,
00217                                      TrapFrame->Eip - 1,
00218                                      3,
00219                                      Parameter1,
00220                                      Parameter2,
00221                                      Parameter3,
00222                                      TrapFrame);
00223 }
00224 
00225 DECLSPEC_NORETURN
00226 VOID
00227 FASTCALL
00228 KiNpxHandler(IN PKTRAP_FRAME TrapFrame,
00229              IN PKTHREAD Thread,
00230              IN PFX_SAVE_AREA SaveArea)
00231 {
00232     ULONG Cr0, Mask, Error, ErrorOffset, DataOffset;
00233     
00234     /* Check for VDM trap */
00235     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
00236 
00237     /* Check for kernel trap */
00238     if (!KiUserTrap(TrapFrame))
00239     {
00240         /* Kernel might've tripped a delayed error */
00241         SaveArea->Cr0NpxState |= CR0_TS;
00242         
00243         /* Only valid if it happened during a restore */
00244         //if ((PVOID)TrapFrame->Eip == FrRestore)
00245         {
00246             /* It did, so just skip the instruction */
00247             //TrapFrame->Eip += 3; /* sizeof(FRSTOR) */
00248             //KiEoiHelper(TrapFrame);
00249         }
00250     }
00251 
00252     /* User or kernel trap -- get ready to issue an exception */
00253     //if (Thread->NpxState == NPX_STATE_NOT_LOADED)
00254     {
00255         /* Update CR0 */
00256         Cr0 = __readcr0();
00257         Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
00258         __writecr0(Cr0);
00259 
00260         /* Save FPU state */
00261         Ke386SaveFpuState(SaveArea);
00262 
00263         /* Mark CR0 state dirty */
00264         Cr0 |= NPX_STATE_NOT_LOADED;
00265         Cr0 |= SaveArea->Cr0NpxState;
00266         __writecr0(Cr0);
00267 
00268         /* Update NPX state */
00269         Thread->NpxState = NPX_STATE_NOT_LOADED;
00270         KeGetCurrentPrcb()->NpxThread = NULL;
00271     }
00272 
00273     /* Clear the TS bit and re-enable interrupts */
00274     SaveArea->Cr0NpxState &= ~CR0_TS;
00275     _enable();
00276     
00277     /* Check if we should get the FN or FX error */
00278     if (KeI386FxsrPresent)
00279     {
00280         /* Get it from FX */
00281         Mask = SaveArea->U.FxArea.ControlWord;
00282         Error = SaveArea->U.FxArea.StatusWord;
00283         
00284         /* Get the FPU exception address too */
00285         ErrorOffset = SaveArea->U.FxArea.ErrorOffset;
00286         DataOffset = SaveArea->U.FxArea.DataOffset;
00287     }
00288     else
00289     {
00290         /* Get it from FN */
00291         Mask = SaveArea->U.FnArea.ControlWord;
00292         Error = SaveArea->U.FnArea.StatusWord;
00293         
00294         /* Get the FPU exception address too */
00295         ErrorOffset = SaveArea->U.FnArea.ErrorOffset;
00296         DataOffset = SaveArea->U.FnArea.DataOffset;
00297     }
00298 
00299     /* Get legal exceptions that software should handle */
00300     /* We do this by first masking off from the Mask the bits we need, */
00301     /* This is done so we can keep the FSW_STACK_FAULT bit in Error. */
00302     Mask &= (FSW_INVALID_OPERATION |
00303              FSW_DENORMAL |
00304              FSW_ZERO_DIVIDE |
00305              FSW_OVERFLOW |
00306              FSW_UNDERFLOW |
00307              FSW_PRECISION);
00308     Error &= ~Mask;
00309 
00310     /* Check for invalid operation */
00311     if (Error & FSW_INVALID_OPERATION)
00312     {
00313         /* NOTE: Stack fault is handled differently than any other case. */
00314         /* 1. It's only raised for invalid operation. */
00315         /* 2. It's only raised if invalid operation is not masked. */
00316         if (Error & FSW_STACK_FAULT)
00317         {
00318             /* Issue stack check fault */
00319             KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK,
00320                                      ErrorOffset,
00321                                      0,
00322                                      DataOffset,
00323                                      TrapFrame);
00324         }
00325 
00326         /* Issue fault */
00327         KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
00328                                  ErrorOffset,
00329                                  0,
00330                                  TrapFrame);
00331     }
00332     
00333     /* Check for divide by zero */
00334     if (Error & FSW_ZERO_DIVIDE)
00335     {
00336         /* Issue fault */
00337         KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO,
00338                                  ErrorOffset,
00339                                  0,
00340                                  TrapFrame);
00341     }
00342     
00343     /* Check for denormal */
00344     if (Error & FSW_DENORMAL)
00345     {
00346         /* Issue fault */
00347         KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION,
00348                                  ErrorOffset,
00349                                  0,
00350                                  TrapFrame);
00351     }
00352     
00353     /* Check for overflow */
00354     if (Error & FSW_OVERFLOW)
00355     {
00356         /* Issue fault */
00357         KiDispatchException1Args(STATUS_FLOAT_OVERFLOW,
00358                                  ErrorOffset,
00359                                  0,
00360                                  TrapFrame);
00361     }
00362     
00363     /* Check for underflow */
00364     if (Error & FSW_UNDERFLOW)
00365     {
00366         /* Issue fault */
00367         KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW,
00368                                  ErrorOffset,
00369                                  0,
00370                                  TrapFrame);
00371     }
00372 
00373     /* Check for precision fault */
00374     if (Error & FSW_PRECISION)
00375     {
00376         /* Issue fault */
00377         KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT,
00378                                  ErrorOffset,
00379                                  0,
00380                                  TrapFrame);
00381     }
00382     
00383     /* Unknown FPU fault */
00384     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 1, Error, 0, 0, TrapFrame);
00385 }
00386 
00387 DECLSPEC_NORETURN
00388 VOID
00389 FASTCALL
00390 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame)
00391 {
00392     /* Save trap frame */
00393     KiEnterTrap(TrapFrame);
00394     
00395     /* Check for VDM trap */
00396     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
00397 
00398     /*  Enable interrupts */
00399     _enable();
00400     
00401     /* Dispatch the exception */
00402     KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO,
00403                              TrapFrame->Eip,
00404                              TrapFrame);
00405 }
00406 
00407 DECLSPEC_NORETURN
00408 VOID
00409 FASTCALL
00410 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame)
00411 {
00412     /* Save trap frame */
00413     KiEnterTrap(TrapFrame);
00414     
00415     /* Check for VDM trap */
00416     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
00417 
00418     /* Enable interrupts if the trap came from user-mode */
00419     if (KiUserTrap(TrapFrame)) _enable();
00420     
00421     /*  Mask out trap flag and dispatch the exception */
00422     TrapFrame->EFlags &= ~EFLAGS_TF;
00423     KiDispatchException0Args(STATUS_SINGLE_STEP,
00424                              TrapFrame->Eip,
00425                              TrapFrame);
00426 }
00427 
00428 DECLSPEC_NORETURN
00429 VOID
00430 __cdecl
00431 KiTrap02(VOID)
00432 {
00433     PKTSS Tss, NmiTss;
00434     PKTHREAD Thread;
00435     PKPROCESS Process;
00436     PKGDTENTRY TssGdt;
00437     KTRAP_FRAME TrapFrame;
00438     KIRQL OldIrql;
00439     
00440     //
00441     // In some sort of strange recursion case, we might end up here with the IF
00442     // flag incorrectly on the interrupt frame -- during a normal NMI this would
00443     // normally already be set.
00444     //
00445     // For sanity's sake, make sure interrupts are disabled for sure.
00446     // NMIs will already be since the CPU does it for us.
00447     //
00448     _disable();
00449 
00450     //
00451     // Get the current TSS, thread, and process
00452     //
00453     Tss = PCR->TSS;
00454     Thread = ((PKIPCR)PCR)->PrcbData.CurrentThread;
00455     Process = Thread->ApcState.Process;
00456     
00457     //
00458     // Save data usually not in the TSS
00459     //
00460     Tss->CR3 = Process->DirectoryTableBase[0];
00461     Tss->IoMapBase = Process->IopmOffset;
00462     Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0;
00463     
00464     //
00465     // Now get the base address of the NMI TSS
00466     //
00467     TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)];
00468     NmiTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow |
00469                                 TssGdt->HighWord.Bytes.BaseMid << 16 |
00470                                 TssGdt->HighWord.Bytes.BaseHi << 24);
00471                     
00472     //
00473     // Switch to it and activate it, masking off the nested flag
00474     //
00475     // Note that in reality, we are already on the NMI tss -- we just need to
00476     // update the PCR to reflect this
00477     //
00478     PCR->TSS = NmiTss;
00479     __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK);
00480     TssGdt->HighWord.Bits.Dpl = 0;
00481     TssGdt->HighWord.Bits.Pres = 1;
00482     TssGdt->HighWord.Bits.Type = I386_TSS;
00483     
00484     //
00485     // Now build the trap frame based on the original TSS
00486     //
00487     // The CPU does a hardware "Context switch" / task switch of sorts and so it
00488     // takes care of saving our context in the normal TSS.
00489     //
00490     // We just have to go get the values...
00491     //
00492     RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME));
00493     TrapFrame.HardwareSegSs = Tss->Ss0;
00494     TrapFrame.HardwareEsp = Tss->Esp0;
00495     TrapFrame.EFlags = Tss->EFlags;
00496     TrapFrame.SegCs = Tss->Cs;
00497     TrapFrame.Eip = Tss->Eip;
00498     TrapFrame.Ebp = Tss->Ebp;
00499     TrapFrame.Ebx = Tss->Ebx;
00500     TrapFrame.Esi = Tss->Esi;
00501     TrapFrame.Edi = Tss->Edi;
00502     TrapFrame.SegFs = Tss->Fs;
00503     TrapFrame.ExceptionList = PCR->NtTib.ExceptionList;
00504     TrapFrame.PreviousPreviousMode = -1;
00505     TrapFrame.Eax = Tss->Eax;
00506     TrapFrame.Ecx = Tss->Ecx;
00507     TrapFrame.Edx = Tss->Edx;
00508     TrapFrame.SegDs = Tss->Ds;
00509     TrapFrame.SegEs = Tss->Es;
00510     TrapFrame.SegGs = Tss->Gs;
00511     TrapFrame.DbgEip = Tss->Eip;
00512     TrapFrame.DbgEbp = Tss->Ebp;
00513     
00514     //
00515     // Store the trap frame in the KPRCB
00516     //
00517     KiSaveProcessorState(&TrapFrame, NULL);
00518     
00519     //
00520     // Call any registered NMI handlers and see if they handled it or not
00521     //
00522     if (!KiHandleNmi())
00523     {
00524         //
00525         // They did not, so call the platform HAL routine to bugcheck the system
00526         //
00527         // Make sure the HAL believes it's running at HIGH IRQL... we can't use
00528         // the normal APIs here as playing with the IRQL could change the system
00529         // state
00530         //
00531         OldIrql = PCR->Irql;
00532         PCR->Irql = HIGH_LEVEL;
00533         HalHandleNMI(NULL);
00534         PCR->Irql = OldIrql;
00535     }
00536 
00537     //
00538     // Although the CPU disabled NMIs, we just did a BIOS Call, which could've
00539     // totally changed things.
00540     //
00541     // We have to make sure we're still in our original NMI -- a nested NMI
00542     // will point back to the NMI TSS, and in that case we're hosed.
00543     //
00544     if (PCR->TSS->Backlink != KGDT_NMI_TSS)
00545     {
00546         //
00547         // Restore original TSS
00548         //
00549         PCR->TSS = Tss;
00550         
00551         //
00552         // Set it back to busy
00553         //
00554         TssGdt->HighWord.Bits.Dpl = 0;
00555         TssGdt->HighWord.Bits.Pres = 1;
00556         TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS;
00557         
00558         //
00559         // Restore nested flag
00560         //
00561         __writeeflags(__readeflags() | EFLAGS_NESTED_TASK);
00562         
00563         //
00564         // Handled, return from interrupt
00565         //
00566         KiIret();
00567     }
00568     
00569     //
00570     // Unhandled: crash the system
00571     //
00572     KiSystemFatalException(EXCEPTION_NMI, NULL);
00573 }
00574 
00575 DECLSPEC_NORETURN
00576 VOID
00577 FASTCALL
00578 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame)
00579 {
00580     /* Save trap frame */
00581     KiEnterTrap(TrapFrame);
00582     
00583     /* Continue with the common handler */
00584     KiDebugHandler(TrapFrame, BREAKPOINT_BREAK, 0, 0);
00585 }
00586 
00587 DECLSPEC_NORETURN
00588 VOID
00589 FASTCALL
00590 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame)
00591 {
00592     /* Save trap frame */
00593     KiEnterTrap(TrapFrame);
00594     
00595     /* Check for VDM trap */
00596     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
00597 
00598      /* Enable interrupts */
00599     _enable();
00600     
00601     /* Dispatch the exception */
00602     KiDispatchException0Args(STATUS_INTEGER_OVERFLOW,
00603                              TrapFrame->Eip - 1,
00604                              TrapFrame);
00605 }
00606 
00607 DECLSPEC_NORETURN
00608 VOID
00609 FASTCALL
00610 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame)
00611 {
00612     /* Save trap frame */
00613     KiEnterTrap(TrapFrame);
00614     
00615     /* Check for VDM trap */
00616     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
00617     
00618     /* Check for kernel-mode fault */
00619     if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_BOUND_CHECK, TrapFrame);
00620 
00621     /* Enable interrupts */
00622     _enable();
00623     
00624     /* Dispatch the exception */
00625     KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED,
00626                              TrapFrame->Eip,
00627                              TrapFrame);
00628 }
00629 
00630 DECLSPEC_NORETURN
00631 VOID
00632 FASTCALL
00633 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame)
00634 {
00635     PUCHAR Instruction;
00636     ULONG i;
00637     KIRQL OldIrql;
00638     
00639     /* Check for V86 GPF */
00640     if (__builtin_expect(KiV86Trap(TrapFrame), 1))
00641     {
00642         /* Enter V86 trap */
00643         KiEnterV86Trap(TrapFrame);
00644         
00645         /* Must be a VDM process */
00646         if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
00647         {
00648             /* Enable interrupts */
00649             _enable();
00650             
00651             /* Setup illegal instruction fault */
00652             KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
00653                                      TrapFrame->Eip,
00654                                      TrapFrame);
00655         }
00656         
00657         /* Go to APC level */
00658         OldIrql = KfRaiseIrql(APC_LEVEL);
00659         _enable();
00660         
00661         /* Check for BOP */
00662         if (!VdmDispatchBop(TrapFrame))
00663         {
00664             /* Should only happen in VDM mode */
00665             UNIMPLEMENTED_FATAL();
00666         }
00667         
00668         /* Bring IRQL back */
00669         KfLowerIrql(OldIrql);
00670         _disable();
00671         
00672         /* Do a quick V86 exit if possible */
00673         KiExitV86Trap(TrapFrame);
00674     }
00675 
00676     /* Save trap frame */
00677     KiEnterTrap(TrapFrame);
00678     
00679     /* Enable interrupts */
00680     Instruction = (PUCHAR)TrapFrame->Eip;
00681     _enable();
00682         
00683     /* Check for user trap */
00684     if (KiUserTrap(TrapFrame))
00685     {
00686         /* FIXME: Use SEH */
00687         
00688         /* Scan next 4 opcodes */
00689         for (i = 0; i < 4; i++)
00690         {
00691             /* Check for LOCK instruction */
00692             if (Instruction[i] == 0xF0)
00693             {
00694                 /* Send invalid lock sequence exception */
00695                 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE,
00696                                          TrapFrame->Eip,
00697                                          TrapFrame);
00698             }
00699         }
00700         
00701         /* FIXME: SEH ends here */
00702     }
00703     
00704     /* Kernel-mode or user-mode fault (but not LOCK) */
00705     KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
00706                              TrapFrame->Eip,
00707                              TrapFrame);
00708     
00709 }
00710 
00711 DECLSPEC_NORETURN
00712 VOID
00713 FASTCALL
00714 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame)
00715 {
00716     PKTHREAD Thread, NpxThread;
00717     PFX_SAVE_AREA SaveArea, NpxSaveArea;
00718     ULONG Cr0;
00719     
00720     /* Save trap frame */
00721     KiEnterTrap(TrapFrame);
00722 
00723     /* Try to handle NPX delay load */
00724     while (TRUE)
00725     {
00726         /* Get the current thread */
00727         Thread = KeGetCurrentThread();
00728 
00729         /* Get the NPX frame */
00730         SaveArea = KiGetThreadNpxArea(Thread);
00731 
00732         /* Check if emulation is enabled */
00733         if (SaveArea->Cr0NpxState & CR0_EM)
00734         {
00735             /* Not implemented */
00736             UNIMPLEMENTED_FATAL();
00737         }
00738     
00739         /* Save CR0 and check NPX state */
00740         Cr0 = __readcr0();
00741         if (Thread->NpxState != NPX_STATE_LOADED)
00742         {
00743             /* Update CR0 */
00744             Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
00745             __writecr0(Cr0);
00746         
00747             /* Get the NPX thread */
00748             NpxThread = KeGetCurrentPrcb()->NpxThread;
00749             if (NpxThread)
00750             {
00751                 /* Get the NPX frame */
00752                 NpxSaveArea = KiGetThreadNpxArea(NpxThread);
00753                 
00754                 /* Save FPU state */
00755                 DPRINT("FIXME: Save FPU state: %p\n", NpxSaveArea);
00756                 //Ke386SaveFpuState(NpxSaveArea);
00757 
00758                 /* Update NPX state */
00759                 NpxThread->NpxState = NPX_STATE_NOT_LOADED;
00760            }
00761        
00762             /* Load FPU state */
00763             //Ke386LoadFpuState(SaveArea);
00764         
00765             /* Update NPX state */
00766             Thread->NpxState = NPX_STATE_LOADED;
00767             KeGetCurrentPrcb()->NpxThread = Thread;
00768         
00769             /* Enable interrupts */
00770             _enable();
00771         
00772             /* Check if CR0 needs to be reloaded due to context switch */
00773             if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame);
00774         
00775             /* Otherwise, we need to reload CR0, disable interrupts */
00776             _disable();
00777         
00778             /* Reload CR0 */
00779             Cr0 = __readcr0();
00780             Cr0 |= SaveArea->Cr0NpxState;
00781             __writecr0(Cr0);
00782         
00783             /* Now restore interrupts and check for TS */
00784             _enable();
00785             if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame);
00786         
00787             /* We're still here -- clear TS and try again */
00788             __writecr0(__readcr0() &~ CR0_TS);
00789             _disable();
00790         }
00791         else
00792         {
00793             /* This is an actual fault, not a lack of FPU state */
00794             break;
00795         }
00796     }
00797     
00798     /* TS should not be set */
00799     if (Cr0 & CR0_TS)
00800     {
00801         /*
00802          * If it's incorrectly set, then maybe the state is actually still valid
00803          * but we could've lock track of that due to a BIOS call.
00804          * Make sure MP is still set, which should verify the theory.
00805          */
00806         if (Cr0 & CR0_MP)
00807         {
00808             /* Indeed, the state is actually still valid, so clear TS */
00809             __writecr0(__readcr0() &~ CR0_TS);
00810             KiEoiHelper(TrapFrame);
00811         }
00812         
00813         /* Otherwise, something strange is going on */
00814         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame);
00815     }
00816     
00817     /* It's not a delayed load, so process this trap as an NPX fault */
00818     KiNpxHandler(TrapFrame, Thread, SaveArea);
00819 }
00820 
00821 DECLSPEC_NORETURN
00822 VOID
00823 FASTCALL
00824 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame)
00825 {
00826     /* FIXME: Not handled */
00827     KiSystemFatalException(EXCEPTION_DOUBLE_FAULT, TrapFrame);
00828 }
00829 
00830 DECLSPEC_NORETURN
00831 VOID
00832 FASTCALL
00833 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame)
00834 {
00835     /* Save trap frame */
00836     KiEnterTrap(TrapFrame);
00837 
00838     /* Enable interrupts and kill the system */
00839     _enable();
00840     KiSystemFatalException(EXCEPTION_NPX_OVERRUN, TrapFrame);
00841 }
00842 
00843 DECLSPEC_NORETURN
00844 VOID
00845 FASTCALL
00846 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame)
00847 {
00848     /* Save trap frame */
00849     KiEnterTrap(TrapFrame);
00850 
00851     /* Check for VDM trap */
00852     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
00853 
00854     /* Kill the system */
00855     KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame);
00856 }
00857 
00858 DECLSPEC_NORETURN
00859 VOID
00860 FASTCALL
00861 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame)
00862 {
00863     /* Save trap frame */
00864     KiEnterTrap(TrapFrame);
00865 
00866     /* FIXME: Kill the system */
00867     UNIMPLEMENTED;
00868     KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT, TrapFrame);
00869 }
00870 
00871 DECLSPEC_NORETURN
00872 VOID
00873 FASTCALL
00874 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame)
00875 {
00876     /* Save trap frame */
00877     KiEnterTrap(TrapFrame);
00878 
00879     /* FIXME: Kill the system */
00880     UNIMPLEMENTED;
00881     KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame);
00882 }
00883 
00884 DECLSPEC_NORETURN
00885 VOID
00886 FASTCALL
00887 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame)
00888 {
00889     ULONG i, j, Iopl;
00890     BOOLEAN Privileged = FALSE;
00891     PUCHAR Instructions;
00892     UCHAR Instruction = 0;
00893     KIRQL OldIrql;
00894     
00895     /* Check for V86 GPF */
00896     if (__builtin_expect(KiV86Trap(TrapFrame), 1))
00897     {
00898         /* Enter V86 trap */
00899         KiEnterV86Trap(TrapFrame);
00900         
00901         /* Must be a VDM process */
00902         if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0))
00903         {
00904             /* Enable interrupts */
00905             _enable();
00906             
00907             /* Setup illegal instruction fault */
00908             KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
00909                                      TrapFrame->Eip,
00910                                      TrapFrame);
00911         }
00912         
00913         /* Go to APC level */
00914         OldIrql = KfRaiseIrql(APC_LEVEL);
00915         _enable();
00916         
00917         /* Handle the V86 opcode */
00918         if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0))
00919         {
00920             /* Should only happen in VDM mode */
00921             UNIMPLEMENTED_FATAL();
00922         }
00923         
00924         /* Bring IRQL back */
00925         KfLowerIrql(OldIrql);
00926         _disable();
00927         
00928         /* Do a quick V86 exit if possible */
00929         KiExitV86Trap(TrapFrame);
00930     }
00931     
00932     /* Save trap frame */
00933     KiEnterTrap(TrapFrame);
00934 
00935     /* Check for user-mode GPF */
00936     if (KiUserTrap(TrapFrame))
00937     {
00938         /* Should not be VDM */
00939         ASSERT(KiVdmTrap(TrapFrame) == FALSE);
00940         
00941         /* Enable interrupts and check error code */
00942         _enable();
00943         if (!TrapFrame->ErrCode)
00944         {
00945             /* FIXME: Use SEH */
00946             Instructions = (PUCHAR)TrapFrame->Eip;
00947             
00948             /* Scan next 15 bytes */
00949             for (i = 0; i < 15; i++)
00950             {
00951                 /* Skip prefix instructions */
00952                 for (j = 0; j < sizeof(KiTrapPrefixTable); j++)
00953                 {
00954                     /* Is this a prefix instruction? */
00955                     if (Instructions[i] == KiTrapPrefixTable[j])
00956                     {
00957                         /* Stop looking */
00958                         break;
00959                     }
00960                 }
00961                 
00962                 /* Is this NOT any prefix instruction? */
00963                 if (j == sizeof(KiTrapPrefixTable))
00964                 {
00965                     /* We can go ahead and handle the fault now */
00966                     Instruction = Instructions[i];
00967                     break;
00968                 }
00969             }
00970             
00971             /* If all we found was prefixes, then this instruction is too long */
00972             if (i == 15)
00973             {
00974                 /* Setup illegal instruction fault */
00975                 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION,
00976                                          TrapFrame->Eip,
00977                                          TrapFrame);
00978             }
00979             
00980             /* Check for privileged instructions */
00981             DPRINT("Instruction (%d) at fault: %lx %lx %lx %lx\n",
00982                     i,
00983                     Instructions[i],
00984                     Instructions[i + 1],
00985                     Instructions[i + 2],
00986                     Instructions[i + 3]);
00987             if (Instruction == 0xF4)                            // HLT
00988             {
00989                 /* HLT is privileged */
00990                 Privileged = TRUE;
00991             }
00992             else if (Instruction == 0x0F)
00993             {
00994                 /* Test if it's any of the privileged two-byte opcodes */
00995                 if (((Instructions[i + 1] == 0x00) &&              // LLDT or LTR
00996                      (((Instructions[i + 2] & 0x38) == 0x10) ||        // LLDT
00997                       (Instructions[i + 2] == 0x18))) ||               // LTR
00998                     ((Instructions[i + 1] == 0x01) &&              // LGDT or LIDT or LMSW
00999                      (((Instructions[i + 2] & 0x38) == 0x10) ||        // LGDT
01000                       (Instructions[i + 2] == 0x18) ||                 // LIDT
01001                       (Instructions[i + 2] == 0x30))) ||               // LMSW
01002                     (Instructions[i + 1] == 0x08) ||               // INVD
01003                     (Instructions[i + 1] == 0x09) ||               // WBINVD
01004                     (Instructions[i + 1] == 0x35) ||               // SYSEXIT
01005                     (Instructions[i + 1] == 0x21) ||               // MOV DR, XXX
01006                     (Instructions[i + 1] == 0x06) ||               // CLTS
01007                     (Instructions[i + 1] == 0x20) ||               // MOV CR, XXX
01008                     (Instructions[i + 1] == 0x22) ||               // MOV XXX, CR
01009                     (Instructions[i + 1] == 0x23) ||               // MOV YYY, DR
01010                     (Instructions[i + 1] == 0x30) ||               // WRMSR
01011                     (Instructions[i + 1] == 0x33))                 // RDPMC
01012                     // INVLPG, INVLPGA, SYSRET
01013                 {
01014                     /* These are all privileged */
01015                     Privileged = TRUE;
01016                 }
01017             }
01018             else
01019             {
01020                 /* Get the IOPL and compare with the RPL mask */
01021                 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12;
01022                 if ((TrapFrame->SegCs & RPL_MASK) > Iopl)
01023                 {
01024                     /* I/O privilege error -- check for known instructions */
01025                     if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI
01026                     {
01027                         /* These are privileged */
01028                         Privileged = TRUE;
01029                     }
01030                     else
01031                     {
01032                         /* Last hope: an IN/OUT instruction */
01033                         for (j = 0; j < sizeof(KiTrapIoTable); j++)
01034                         {
01035                             /* Is this an I/O instruction? */
01036                             if (Instruction == KiTrapIoTable[j])
01037                             {
01038                                 /* Then it's privileged */
01039                                 Privileged = TRUE;
01040                                 break;
01041                             }
01042                         }
01043                     }
01044                 }
01045             }
01046             
01047             /* So now... was the instruction privileged or not? */
01048             if (Privileged)
01049             {
01050                 /* Whew! We have a privileged instruction, so dispatch the fault */
01051                 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION,
01052                                          TrapFrame->Eip,
01053                                          TrapFrame);
01054             }
01055         }
01056             
01057         /* If we got here, send an access violation */
01058         KiDispatchException2Args(STATUS_ACCESS_VIOLATION,
01059                                  TrapFrame->Eip,
01060                                  0,
01061                                  0xFFFFFFFF,
01062                                  TrapFrame);
01063     }
01064 
01065     /*
01066      * Check for a fault during checking of the user instruction.
01067      *
01068      * Note that the SEH handler will catch invalid EIP, but we could be dealing
01069      * with an invalid CS, which will generate another GPF instead.
01070      *
01071      */
01072     if (((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler) &&
01073         ((PVOID)TrapFrame->Eip < (PVOID)KiTrap0DHandler))
01074     {
01075         /* Not implemented */
01076         UNIMPLEMENTED_FATAL();
01077     }
01078 
01079     /*
01080      * NOTE: The ASM trap exit code would restore segment registers by doing
01081      * a POP <SEG>, which could cause an invalid segment if someone had messed
01082      * with the segment values.
01083      *
01084      * Another case is a bogus SS, which would hit a GPF when doing the iret.
01085      * This could only be done through a buggy or malicious driver, or perhaps
01086      * the kernel debugger.
01087      *
01088      * The kernel normally restores the "true" segment if this happens.
01089      *
01090      * However, since we're restoring in C, not ASM, we can't detect
01091      * POP <SEG> since the actual instructions will be different.
01092      *
01093      * A better technique would be to check the EIP and somehow edit the
01094      * trap frame before restarting the instruction -- but we would need to
01095      * know the extract instruction that was used first.
01096      *
01097      * We could force a special instrinsic to use stack instructions, or write
01098      * a simple instruction length checker.
01099      *
01100      * Nevertheless, this is a lot of work for the purpose of avoiding a crash
01101      * when the user is purposedly trying to create one from kernel-mode, so
01102      * we should probably table this for now since it's not a "real" issue.
01103      */
01104      
01105     /*
01106      * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call)
01107      * which will cause a GPF since the trap frame is a total mess (on purpose)
01108      * as built in KiEnterV86Mode.
01109      *
01110      * The idea is to scan for IRET, scan for the known EIP adress, validate CS
01111      * and then manually issue a jump to the V8086 return EIP.
01112      */
01113     Instructions = (PUCHAR)TrapFrame->Eip;
01114     if (Instructions[0] == 0xCF)
01115     {
01116         /*
01117          * Some evil shit is going on here -- this is not the SS:ESP you're
01118          * looking for! Instead, this is actually CS:EIP you're looking at!
01119          * Why? Because part of the trap frame actually corresponds to the IRET
01120          * stack during the trap exit!
01121          */
01122         if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) &&
01123             (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK)))
01124         {
01125             /* Exit the V86 trap! */
01126             Ki386BiosCallReturnAddress(TrapFrame);
01127         }
01128         else
01129         {
01130             /* Otherwise, this is another kind of IRET fault */
01131             UNIMPLEMENTED_FATAL();
01132         }
01133     }
01134      
01135      /* So since we're not dealing with the above case, check for RDMSR/WRMSR */
01136     if ((Instructions[0] == 0xF) &&            // 2-byte opcode
01137         ((Instructions[1] == 0x32) ||        // RDMSR
01138          (Instructions[1] == 0x30)))         // WRMSR
01139     {
01140         /* Unknown CPU MSR, so raise an access violation */
01141         KiDispatchException0Args(STATUS_ACCESS_VIOLATION,
01142                                  TrapFrame->Eip,
01143                                  TrapFrame);
01144     }
01145 
01146     /* Check for lazy segment load */
01147     if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK))
01148     {
01149         /* Fix it */
01150         TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK);
01151     }
01152     else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK))
01153     {
01154         /* Fix it */
01155         TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK);
01156     }
01157     else
01158     {
01159         /* Whatever it is, we can't handle it */
01160         KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame);
01161     }
01162     
01163     /* Return to where we came from */
01164     KiTrapReturn(TrapFrame);
01165 }
01166 
01167 DECLSPEC_NORETURN
01168 VOID
01169 FASTCALL
01170 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame)
01171 {
01172     PKTHREAD Thread;
01173     ULONG_PTR Cr2;
01174     NTSTATUS Status;
01175 
01176     /* Save trap frame */
01177     KiEnterTrap(TrapFrame);
01178 
01179     /* Check if this is the base frame */
01180     Thread = KeGetCurrentThread();
01181     if (KeGetTrapFrame(Thread) != TrapFrame)
01182     {
01183         /* It isn't, check if this is a second nested frame */
01184         if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
01185             FIELD_OFFSET(KTRAP_FRAME, EFlags))
01186         {
01187             /* The stack is somewhere in between frames, we need to fix it */
01188             UNIMPLEMENTED_FATAL();
01189         }
01190     }
01191 
01192     /* Save CR2 */
01193     Cr2 = __readcr2();
01194 
01195     /* Enable interupts */
01196     _enable();
01197 
01198     /* Check if we came in with interrupts disabled */
01199     if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
01200     {
01201         /* This is completely illegal, bugcheck the system */
01202         KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
01203                          Cr2,
01204                          -1,
01205                          TrapFrame->ErrCode & 2 ? TRUE : FALSE,
01206                          TrapFrame->Eip,
01207                          TrapFrame);
01208     }
01209 
01210     /* Check for S-LIST fault in kernel mode */
01211     if (TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault)
01212     {
01213         PSLIST_HEADER SListHeader;
01214 
01215         /* Sanity check that the assembly is correct:
01216            This must be mov ebx, [eax]
01217            Followed by cmpxchg8b [ebp] */
01218         ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) &&
01219                (((UCHAR*)TrapFrame->Eip)[1] == 0x18) &&
01220                (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) &&
01221                (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) &&
01222                (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) &&
01223                (((UCHAR*)TrapFrame->Eip)[5] == 0x00));
01224 
01225         /* Get the pointer to the SLIST_HEADER */
01226         SListHeader = (PSLIST_HEADER)TrapFrame->Ebp;
01227 
01228         /* Check if the Next member of the SLIST_HEADER was changed */
01229         if (SListHeader->Next.Next != (PSLIST_ENTRY)TrapFrame->Eax)
01230         {
01231             /* Restart the operation */
01232             TrapFrame->Eip = (ULONG_PTR)ExpInterlockedPopEntrySListResume;
01233 
01234             /* Continue execution */
01235             KiEoiHelper(TrapFrame);
01236         }
01237     }
01238 
01239     /* Call the access fault handler */
01240     Status = MmAccessFault(TrapFrame->ErrCode & 1,
01241                            (PVOID)Cr2,
01242                            TrapFrame->SegCs & MODE_MASK,
01243                            TrapFrame);
01244     if (NT_SUCCESS(Status)) KiEoiHelper(TrapFrame);
01245     
01246     /* Check for syscall fault */
01247 #if 0
01248     if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
01249         (TrapFrame->Eip == (ULONG_PTR)ReadBatch))
01250     {
01251         /* Not yet implemented */
01252         UNIMPLEMENTED_FATAL();
01253     }
01254 #endif
01255     /* Check for VDM trap */
01256     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
01257     
01258     /* Either kernel or user trap (non VDM) so dispatch exception */
01259     if (Status == STATUS_ACCESS_VIOLATION)
01260     {
01261         /* This status code is repurposed so we can recognize it later */
01262         KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
01263                                  TrapFrame->Eip,
01264                                  TrapFrame->ErrCode & 2 ? TRUE : FALSE,
01265                                  Cr2,
01266                                  TrapFrame);
01267     }
01268     else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
01269              (Status == STATUS_STACK_OVERFLOW))
01270     {
01271         /* These faults only have two parameters */
01272         KiDispatchException2Args(Status,
01273                                  TrapFrame->Eip,
01274                                  TrapFrame->ErrCode & 2 ? TRUE : FALSE,
01275                                  Cr2,
01276                                  TrapFrame);
01277     }
01278     
01279     /* Only other choice is an in-page error, with 3 parameters */
01280     KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
01281                                      TrapFrame->Eip,
01282                                      3,
01283                                      TrapFrame->ErrCode & 2 ? TRUE : FALSE,
01284                                      Cr2,
01285                                      Status,
01286                                      TrapFrame);
01287 }
01288 
01289 DECLSPEC_NORETURN
01290 VOID
01291 FASTCALL
01292 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
01293 {
01294     /* Save trap frame */
01295     KiEnterTrap(TrapFrame);
01296 
01297     /* FIXME: Kill the system */
01298     UNIMPLEMENTED;
01299     KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame);
01300 }
01301 
01302 DECLSPEC_NORETURN
01303 VOID
01304 FASTCALL
01305 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame)
01306 {
01307     PKTHREAD Thread;
01308     PFX_SAVE_AREA SaveArea;
01309     
01310     /* Save trap frame */
01311     KiEnterTrap(TrapFrame);
01312 
01313     /* Check if this is the NPX thrad */
01314     Thread = KeGetCurrentThread();
01315     SaveArea = KiGetThreadNpxArea(Thread);
01316     if (Thread != KeGetCurrentPrcb()->NpxThread)
01317     {
01318         /* It isn't, enable interrupts and set delayed error */
01319         _enable();
01320         SaveArea->Cr0NpxState |= CR0_TS;
01321         
01322         /* End trap */
01323         KiEoiHelper(TrapFrame);
01324     }
01325     
01326     /* Otherwise, proceed with NPX fault handling */
01327     KiNpxHandler(TrapFrame, Thread, SaveArea);
01328 }
01329 
01330 DECLSPEC_NORETURN
01331 VOID
01332 FASTCALL
01333 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame)
01334 {
01335     /* Save trap frame */
01336     KiEnterTrap(TrapFrame);
01337 
01338     /* Enable interrupts and kill the system */
01339     _enable();
01340     KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame);
01341 }
01342 
01343 DECLSPEC_NORETURN
01344 VOID
01345 FASTCALL
01346 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame)
01347 {
01348     PKTHREAD Thread;
01349     PFX_SAVE_AREA SaveArea;
01350     ULONG Cr0, MxCsrMask, Error;
01351     
01352     /* Save trap frame */
01353     KiEnterTrap(TrapFrame);
01354 
01355     /* Check if this is the NPX thrad */
01356     Thread = KeGetCurrentThread();
01357     if (Thread != KeGetCurrentPrcb()->NpxThread)
01358     {
01359         /* It isn't, kill the system */
01360         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame);
01361     }
01362 
01363     /* Get the NPX frame */
01364     SaveArea = KiGetThreadNpxArea(Thread);
01365 
01366     /* Check for VDM trap */
01367     ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
01368 
01369     /* Check for user trap */
01370     if (!KiUserTrap(TrapFrame))
01371     {
01372         /* Kernel should not fault on XMMI */
01373         KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame);
01374     }
01375     
01376     /* Update CR0 */
01377     Cr0 = __readcr0();
01378     Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS);
01379     __writecr0(Cr0);
01380     
01381     /* Save FPU state */
01382     Ke386SaveFpuState(SaveArea);
01383     
01384     /* Mark CR0 state dirty */
01385     Cr0 |= NPX_STATE_NOT_LOADED;
01386     Cr0 |= SaveArea->Cr0NpxState;
01387      __writecr0(Cr0);
01388     
01389     /* Update NPX state */
01390     Thread->NpxState = NPX_STATE_NOT_LOADED;
01391     KeGetCurrentPrcb()->NpxThread = NULL;
01392     
01393     /* Clear the TS bit and re-enable interrupts */
01394     SaveArea->Cr0NpxState &= ~CR0_TS;
01395     _enable();
01396 
01397     /* Now look at MxCsr to get the mask of errors we should care about */
01398     MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7);
01399     
01400     /* Get legal exceptions that software should handle */
01401     Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION |
01402                                                 FSW_DENORMAL |
01403                                                 FSW_ZERO_DIVIDE |
01404                                                 FSW_OVERFLOW |
01405                                                 FSW_UNDERFLOW |
01406                                                 FSW_PRECISION);
01407     Error &= MxCsrMask;
01408 
01409     /* Now handle any of those legal errors */
01410     if (Error & (FSW_INVALID_OPERATION |
01411                  FSW_DENORMAL |
01412                  FSW_ZERO_DIVIDE |
01413                  FSW_OVERFLOW |
01414                  FSW_UNDERFLOW |
01415                  FSW_PRECISION))
01416     {
01417         /* By issuing an exception */
01418         KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS,
01419                                  TrapFrame->Eip,
01420                                  0,
01421                                  TrapFrame);
01422     }
01423     
01424     /* Unknown XMMI fault */
01425     KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
01426 }
01427 
01428 /* SOFTWARE SERVICES **********************************************************/
01429 
01430 VOID
01431 FASTCALL
01432 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame)
01433 {
01434     UNIMPLEMENTED_DBGBREAK();
01435 }
01436 
01437 VOID
01438 FASTCALL
01439 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame)
01440 {
01441     UNIMPLEMENTED_DBGBREAK();
01442 }
01443 
01444 DECLSPEC_NORETURN
01445 VOID
01446 FASTCALL
01447 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
01448 {
01449     /* Save trap frame */
01450     KiEnterTrap(TrapFrame);
01451 
01452     /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
01453     TrapFrame->Eip -= 2;
01454 
01455     /* Dispatch the exception */
01456     KiDispatchException0Args(STATUS_ASSERTION_FAILURE,
01457                              TrapFrame->Eip,
01458                              TrapFrame);
01459 }
01460 
01461 DECLSPEC_NORETURN
01462 VOID
01463 FASTCALL
01464 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame)
01465 {
01466     /* Save trap frame */
01467     KiEnterTrap(TrapFrame);
01468     
01469     /* Increment EIP to skip the INT3 instruction */
01470     TrapFrame->Eip++;
01471     
01472     /* Continue with the common handler */
01473     KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx);
01474 }
01475 
01476 
01477 FORCEINLINE
01478 VOID
01479 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments)
01480 {
01481 #if DBG && !defined(_WINKD_)
01482     if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook)
01483         KeWin32PreServiceHook(SystemCallNumber, Arguments);
01484 #endif
01485 }
01486 
01487 FORCEINLINE
01488 ULONG_PTR
01489 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result)
01490 {
01491 #if DBG && !defined(_WINKD_)
01492     if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook)
01493         return KeWin32PostServiceHook(SystemCallNumber, Result);
01494 #endif
01495     return Result;
01496 }
01497 
01498 DECLSPEC_NORETURN
01499 VOID
01500 FORCEINLINE
01501 KiSystemCall(IN PKTRAP_FRAME TrapFrame,
01502              IN PVOID Arguments)
01503 {
01504     PKTHREAD Thread;
01505     PKSERVICE_TABLE_DESCRIPTOR DescriptorTable;
01506     ULONG Id, Offset, StackBytes, Result;
01507     PVOID Handler;
01508     ULONG SystemCallNumber = TrapFrame->Eax;
01509     
01510     /* Get the current thread */
01511     Thread = KeGetCurrentThread();
01512 
01513     /* Set debug header */
01514     KiFillTrapFrameDebug(TrapFrame);
01515 
01516     /* Chain trap frames */
01517     TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame;
01518 
01519     /* No error code */
01520     TrapFrame->ErrCode = 0;
01521 
01522     /* Save previous mode */
01523     TrapFrame->PreviousPreviousMode = Thread->PreviousMode;
01524 
01525     /* Save the SEH chain and terminate it for now */
01526     TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList;
01527     KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
01528 
01529     /* Default to debugging disabled */
01530     TrapFrame->Dr7 = 0;
01531 
01532     /* Check if the frame was from user mode */
01533     if (TrapFrame->SegCs & MODE_MASK)
01534     {
01535         /* Check for active debugging */
01536         if (KeGetCurrentThread()->Header.DebugActive & 0xFF)
01537         {
01538             /* Handle debug registers */
01539             KiHandleDebugRegistersOnTrapEntry(TrapFrame);
01540         }
01541     }
01542 
01543     /* Set thread fields */
01544     Thread->TrapFrame = TrapFrame;
01545     Thread->PreviousMode = KiUserTrap(TrapFrame);
01546 
01547     /* Enable interrupts */
01548     _enable();
01549 
01550     /* Decode the system call number */
01551     Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK;
01552     Id = SystemCallNumber & SERVICE_NUMBER_MASK;
01553     
01554     /* Get descriptor table */
01555     DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset);
01556 
01557     /* Validate the system call number */
01558     if (__builtin_expect(Id >= DescriptorTable->Limit, 0))
01559     {
01560         /* Check if this is a GUI call */
01561         if (!(Offset & SERVICE_TABLE_TEST))
01562         {
01563             /* Fail the call */
01564             Result = STATUS_INVALID_SYSTEM_SERVICE;
01565             goto ExitCall;
01566         }
01567 
01568         /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */
01569         Result = KiConvertToGuiThread();
01570 
01571         /* Reload trap frame and descriptor table pointer from new stack */
01572         TrapFrame = *(volatile PVOID*)&Thread->TrapFrame;
01573         DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset);
01574 
01575         if (!NT_SUCCESS(Result))
01576         {
01577             /* Set the last error and fail */
01578             //SetLastWin32Error(RtlNtStatusToDosError(Result));
01579             goto ExitCall;
01580         }
01581 
01582         /* Validate the system call number again */
01583         if (Id >= DescriptorTable->Limit)
01584         {
01585             /* Fail the call */
01586             Result = STATUS_INVALID_SYSTEM_SERVICE;
01587             goto ExitCall;
01588         }
01589     }
01590     
01591     /* Check if this is a GUI call */
01592     if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0))
01593     {
01594         /* Get the batch count and flush if necessary */
01595         if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch();
01596     }
01597     
01598     /* Increase system call count */
01599     KeGetCurrentPrcb()->KeSystemCalls++;
01600     
01601     /* FIXME: Increase individual counts on debug systems */
01602     //KiIncreaseSystemCallCount(DescriptorTable, Id);
01603     
01604     /* Get stack bytes */
01605     StackBytes = DescriptorTable->Number[Id];
01606     
01607     /* Probe caller stack */
01608     if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0))
01609     {
01610         /* Access violation */
01611         UNIMPLEMENTED_FATAL();
01612     }
01613     
01614     /* Call pre-service debug hook */
01615     KiDbgPreServiceHook(SystemCallNumber, Arguments);
01616 
01617     /* Get the handler and make the system call */
01618     Handler = (PVOID)DescriptorTable->Base[Id];
01619     Result = KiSystemCallTrampoline(Handler, Arguments, StackBytes);
01620     
01621     /* Call post-service debug hook */
01622     Result = KiDbgPostServiceHook(SystemCallNumber, Result);
01623 
01624     /* Make sure we're exiting correctly */
01625     KiExitSystemCallDebugChecks(Id, TrapFrame);
01626     
01627     /* Restore the old trap frame */
01628 ExitCall:
01629     Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
01630 
01631     /* Exit from system call */
01632     KiServiceExit(TrapFrame, Result);
01633 }
01634 
01635 DECLSPEC_NORETURN
01636 VOID
01637 FASTCALL
01638 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame,
01639                        IN PVOID Arguments)
01640 {
01641     /* Call the shared handler (inline) */
01642     KiSystemCall(TrapFrame, Arguments);
01643 }
01644 
01645 DECLSPEC_NORETURN
01646 VOID
01647 FASTCALL
01648 KiFastCallEntryHandler(IN PKTRAP_FRAME TrapFrame,
01649                        IN PVOID Arguments)
01650 {
01651     /* Set up a fake INT Stack and enable interrupts */
01652     TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
01653     TrapFrame->HardwareEsp = (ULONG_PTR)Arguments;
01654     TrapFrame->EFlags = __readeflags() | EFLAGS_INTERRUPT_MASK;
01655     TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
01656     TrapFrame->Eip = SharedUserData->SystemCallReturn;
01657     TrapFrame->SegFs = KGDT_R3_TEB | RPL_MASK;
01658     __writeeflags(0x2);
01659     
01660     /* Arguments are actually 2 frames down (because of the double indirection) */
01661     Arguments = (PVOID)(TrapFrame->HardwareEsp + 8);
01662 
01663     /* Call the shared handler (inline) */
01664     KiSystemCall(TrapFrame, Arguments);
01665 }
01666 
01667 /*
01668  * @implemented
01669  */
01670 VOID
01671 NTAPI
01672 Kei386EoiHelper(VOID)
01673 {
01674     /* We should never see this call happening */
01675     ERROR_FATAL("Mismatched NT/HAL version");
01676 }
01677 
01678 /* EOF */