ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

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

Generated on Fri May 25 2012 04:35:55 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.