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

exp.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/ke/i386/exp.c
00005  * PURPOSE:         Exception Dispatching and Context<->Trap Frame Conversion
00006  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007  *                  Gregor Anich
00008  *                  Skywing (skywing@valhallalegends.com)
00009  */
00010 
00011 /* INCLUDES ******************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #define NDEBUG
00015 #include <debug.h>
00016 
00017 
00018 /* FUNCTIONS *****************************************************************/
00019 
00020 VOID
00021 INIT_FUNCTION
00022 NTAPI
00023 KeInitExceptions(VOID)
00024 {
00025     ULONG i;
00026     USHORT FlippedSelector;
00027 
00028     /* Loop the IDT */
00029     for (i = 0; i <= MAXIMUM_IDTVECTOR; i++)
00030     {
00031         /* Save the current Selector */
00032         FlippedSelector = KiIdt[i].Selector;
00033 
00034         /* Flip Selector and Extended Offset */
00035         KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
00036         KiIdt[i].ExtendedOffset = FlippedSelector;
00037     }
00038 }
00039 
00040 ULONG
00041 FASTCALL
00042 KiUpdateDr7(IN ULONG Dr7)
00043 {
00044     ULONG DebugMask = KeGetCurrentThread()->Header.DebugActive;
00045 
00046     /* Check if debugging is enabled */
00047     if (DebugMask & DR_MASK(DR7_OVERRIDE_V))
00048     {
00049         /* Sanity checks */
00050         ASSERT((DebugMask & DR_REG_MASK) != 0);
00051         ASSERT((Dr7 & ~DR7_RESERVED_MASK) == DR7_OVERRIDE_MASK);
00052         return 0;
00053     }
00054 
00055     /* Return DR7 itself */
00056     return Dr7;
00057 }
00058 
00059 BOOLEAN
00060 FASTCALL
00061 KiRecordDr7(OUT PULONG Dr7Ptr,
00062             OUT PULONG DrMask)
00063 {
00064     ULONG NewMask, Mask;
00065     UCHAR Result;
00066 
00067     /* Check if the caller gave us a mask */
00068     if (!DrMask)
00069     {
00070         /* He didn't, use the one from the thread */
00071         Mask = KeGetCurrentThread()->Header.DebugActive;
00072     }
00073     else
00074     {
00075         /* He did, read it */
00076         Mask = *DrMask;
00077     }
00078 
00079     /* Sanity check */
00080     ASSERT((*Dr7Ptr & DR7_RESERVED_MASK) == 0);
00081 
00082     /* Check if DR7 is empty */
00083     NewMask = Mask;
00084     if (!(*Dr7Ptr))
00085     {
00086         /* Assume failure */
00087         Result = FALSE;
00088 
00089         /* Check the DR mask */
00090         NewMask &= ~(DR_MASK(7));
00091         if (NewMask & DR_REG_MASK)
00092         {
00093             /* Set the active mask */
00094             NewMask |= DR_MASK(DR7_OVERRIDE_V);
00095 
00096             /* Set DR7 override */
00097             *Dr7Ptr |= DR7_OVERRIDE_MASK;
00098         }
00099         else
00100         {
00101             /* Sanity check */
00102             ASSERT(NewMask == 0);
00103         }
00104     }
00105     else
00106     {
00107         /* Check if we have a mask or not */
00108         Result = NewMask ? TRUE: FALSE;
00109 
00110         /* Update the mask to disable debugging */
00111         NewMask &= ~(DR_MASK(DR7_OVERRIDE_V));
00112         NewMask |= DR_MASK(7);
00113     }
00114 
00115     /* Check if caller wants the new mask */
00116     if (DrMask)
00117     {
00118         /* Update it */
00119         *DrMask = NewMask;
00120     }
00121     else
00122     {
00123         /* Check if the mask changed */
00124         if (Mask != NewMask)
00125         {
00126             /* Update it */
00127             KeGetCurrentThread()->Header.DebugActive = (UCHAR)NewMask;
00128         }
00129     }
00130 
00131     /* Return the result */
00132     return Result;
00133 }
00134 
00135 ULONG
00136 NTAPI
00137 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
00138 {
00139     /* Check if this is user-mode or V86 */
00140     if ((TrapFrame->SegCs & MODE_MASK) ||
00141         (TrapFrame->EFlags & EFLAGS_V86_MASK))
00142     {
00143         /* Return it directly */
00144         return TrapFrame->HardwareEsp;
00145     }
00146     else
00147     {
00148         /* Edited frame */
00149         if (!(TrapFrame->SegCs & FRAME_EDITED))
00150         {
00151             /* Return edited value */
00152             return TrapFrame->TempEsp;
00153         }
00154         else
00155         {
00156             /* Virgin frame, calculate */
00157             return (ULONG)&TrapFrame->HardwareEsp;
00158         }
00159     }
00160 }
00161 
00162 VOID
00163 NTAPI
00164 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
00165                  IN ULONG Esp)
00166 {
00167     KIRQL OldIrql;
00168     ULONG Previous;
00169 
00170     /* Raise to APC_LEVEL if needed */
00171     OldIrql = KeGetCurrentIrql();
00172     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
00173 
00174     /* Get the old ESP */
00175     Previous = KiEspFromTrapFrame(TrapFrame);
00176 
00177     /* Check if this is user-mode or V86 */
00178     if ((TrapFrame->SegCs & MODE_MASK) ||
00179         (TrapFrame->EFlags & EFLAGS_V86_MASK))
00180     {
00181         /* Write it directly */
00182         TrapFrame->HardwareEsp = Esp;
00183     }
00184     else
00185     {
00186         /* Don't allow ESP to be lowered, this is illegal */
00187         if (Esp < Previous) KeBugCheckEx(SET_OF_INVALID_CONTEXT,
00188                                          Esp,
00189                                          Previous,
00190                                          (ULONG_PTR)TrapFrame,
00191                                          0);
00192 
00193         /* Create an edit frame, check if it was alrady */
00194         if (!(TrapFrame->SegCs & FRAME_EDITED))
00195         {
00196             /* Update the value */
00197             TrapFrame->TempEsp = Esp;
00198         }
00199         else
00200         {
00201             /* Check if ESP changed */
00202             if (Previous != Esp)
00203             {
00204                 /* Save CS */
00205                 TrapFrame->TempSegCs = TrapFrame->SegCs;
00206                 TrapFrame->SegCs &= ~FRAME_EDITED;
00207 
00208                 /* Save ESP */
00209                 TrapFrame->TempEsp = Esp;
00210             }
00211         }
00212     }
00213 
00214     /* Restore IRQL */
00215     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
00216 }
00217 
00218 ULONG
00219 NTAPI
00220 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
00221 {
00222     /* Check if this was V86 Mode */
00223     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
00224     {
00225         /* Just return it */
00226         return TrapFrame->HardwareSegSs;
00227     }
00228     else if (TrapFrame->SegCs & MODE_MASK)
00229     {
00230         /* User mode, return the User SS */
00231         return TrapFrame->HardwareSegSs | RPL_MASK;
00232     }
00233     else
00234     {
00235         /* Kernel mode */
00236         return KGDT_R0_DATA;
00237     }
00238 }
00239 
00240 VOID
00241 NTAPI
00242 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
00243                 IN ULONG Ss)
00244 {
00245     /* Remove the high-bits */
00246     Ss &= 0xFFFF;
00247 
00248     /* If this was V86 Mode */
00249     if (TrapFrame->EFlags & EFLAGS_V86_MASK)
00250     {
00251         /* Just write it */
00252         TrapFrame->HardwareSegSs = Ss;
00253     }
00254     else if (TrapFrame->SegCs & MODE_MASK)
00255     {
00256         /* Usermode, save the User SS */
00257         TrapFrame->HardwareSegSs = Ss | RPL_MASK;
00258     }
00259 }
00260 
00261 USHORT
00262 NTAPI
00263 KiTagWordFnsaveToFxsave(USHORT TagWord)
00264 {
00265     INT FxTagWord = ~TagWord;
00266 
00267     /*
00268      * Empty is now 00, any 2 bits containing 1 mean valid
00269      * Now convert the rest (11->0 and the rest to 1)
00270      */
00271     FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
00272     FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
00273     FxTagWord = (FxTagWord | (FxTagWord >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
00274     FxTagWord = (FxTagWord | (FxTagWord >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
00275     return FxTagWord;
00276 }
00277 
00278 VOID
00279 NTAPI
00280 Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame)
00281 {
00282     PKTHREAD Thread;
00283     ULONG_PTR Stack;
00284     ULONG EFlags;
00285 
00286     /* Get the current thread's stack */
00287     Thread = KeGetCurrentThread();
00288     Stack = (ULONG_PTR)Thread->InitialStack;
00289 
00290     /* Check if we are in V8086 mode */
00291     if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
00292     {
00293         /* Bias the stack for the V86 segments */
00294         Stack -= (FIELD_OFFSET(KTRAP_FRAME, V86Gs) -
00295                   FIELD_OFFSET(KTRAP_FRAME, HardwareSegSs));
00296     }
00297 
00298     /* Bias the stack for the FPU area */
00299     Stack -= sizeof(FX_SAVE_AREA);
00300 
00301     /* Disable interrupts */
00302     EFlags = __readeflags();
00303     _disable();
00304 
00305     /* Set new ESP0 value in the TSS */
00306     KeGetPcr()->TSS->Esp0 = Stack;
00307 
00308     /* Restore old interrupt state */
00309     __writeeflags(EFlags);
00310 }
00311 
00312 VOID
00313 NTAPI
00314 KeContextToTrapFrame(IN PCONTEXT Context,
00315                      IN OUT PKEXCEPTION_FRAME ExceptionFrame,
00316                      IN OUT PKTRAP_FRAME TrapFrame,
00317                      IN ULONG ContextFlags,
00318                      IN KPROCESSOR_MODE PreviousMode)
00319 {
00320     PFX_SAVE_AREA FxSaveArea;
00321     ULONG i;
00322     BOOLEAN V86Switch = FALSE;
00323     KIRQL OldIrql;
00324     ULONG DrMask = 0;
00325 
00326     /* Do this at APC_LEVEL */
00327     OldIrql = KeGetCurrentIrql();
00328     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
00329 
00330     /* Start with the basic Registers */
00331     if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
00332     {
00333         /* Check if we went through a V86 switch */
00334         if ((Context->EFlags & EFLAGS_V86_MASK) !=
00335             (TrapFrame->EFlags & EFLAGS_V86_MASK))
00336         {
00337             /* We did, remember this for later */
00338             V86Switch = TRUE;
00339         }
00340 
00341         /* Copy EFLAGS and sanitize them*/
00342         TrapFrame->EFlags = Ke386SanitizeFlags(Context->EFlags, PreviousMode);
00343 
00344         /* Copy EBP and EIP */
00345         TrapFrame->Ebp = Context->Ebp;
00346         TrapFrame->Eip = Context->Eip;
00347 
00348         /* Check if we were in V86 Mode */
00349         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
00350         {
00351             /* Simply copy the CS value */
00352             TrapFrame->SegCs = Context->SegCs;
00353         }
00354         else
00355         {
00356             /* We weren't in V86, so sanitize the CS */
00357             TrapFrame->SegCs = Ke386SanitizeSeg(Context->SegCs, PreviousMode);
00358 
00359             /* Don't let it under 8, that's invalid */
00360             if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
00361             {
00362                 /* Force it to User CS */
00363                 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
00364             }
00365         }
00366 
00367         /* Handle SS Specially for validation */
00368         KiSsToTrapFrame(TrapFrame, Context->SegSs);
00369 
00370         /* Write ESP back; take into account Edited Trap Frames */
00371         KiEspToTrapFrame(TrapFrame, Context->Esp);
00372 
00373         /* Handle our V86 Bias if we went through a switch */
00374         if (V86Switch) Ki386AdjustEsp0(TrapFrame);
00375     }
00376 
00377     /* Process the Integer Registers */
00378     if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
00379     {
00380         /* Copy them manually */
00381         TrapFrame->Eax = Context->Eax;
00382         TrapFrame->Ebx = Context->Ebx;
00383         TrapFrame->Ecx = Context->Ecx;
00384         TrapFrame->Edx = Context->Edx;
00385         TrapFrame->Esi = Context->Esi;
00386         TrapFrame->Edi = Context->Edi;
00387     }
00388 
00389     /* Process the Context Segments */
00390     if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
00391     {
00392         /* Check if we were in V86 Mode */
00393         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
00394         {
00395             /* Copy the V86 Segments directly */
00396             TrapFrame->V86Ds = Context->SegDs;
00397             TrapFrame->V86Es = Context->SegEs;
00398             TrapFrame->V86Fs = Context->SegFs;
00399             TrapFrame->V86Gs = Context->SegGs;
00400         }
00401         else if (!(TrapFrame->SegCs & MODE_MASK))
00402         {
00403             /* For kernel mode, write the standard values */
00404             TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
00405             TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
00406             TrapFrame->SegFs = Ke386SanitizeSeg(Context->SegFs, PreviousMode);
00407             TrapFrame->SegGs = 0;
00408         }
00409         else
00410         {
00411             /* For user mode, return the values directly */
00412             TrapFrame->SegDs = Context->SegDs;
00413             TrapFrame->SegEs = Context->SegEs;
00414             TrapFrame->SegFs = Context->SegFs;
00415 
00416             /* Handle GS specially */
00417             if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
00418             {
00419                 /* Don't use it, if user */
00420                 TrapFrame->SegGs = 0;
00421             }
00422             else
00423             {
00424                 /* Copy it if kernel */
00425                 TrapFrame->SegGs = Context->SegGs;
00426             }
00427         }
00428     }
00429 
00430     /* Handle the extended registers */
00431     if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
00432         CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
00433     {
00434         /* Get the FX Area */
00435         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
00436 
00437         /* Check if NPX is present */
00438         if (KeI386NpxPresent)
00439         {
00440             /* Flush the NPX State */
00441             KiFlushNPXState(NULL);
00442 
00443             /* Copy the FX State */
00444             RtlCopyMemory(&FxSaveArea->U.FxArea,
00445                           &Context->ExtendedRegisters[0],
00446                           MAXIMUM_SUPPORTED_EXTENSION);
00447 
00448             /* Remove reserved bits from MXCSR */
00449             FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask;
00450 
00451             /* Mask out any invalid flags */
00452             FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
00453 
00454             /* Check if this is a VDM app */
00455             if (PsGetCurrentProcess()->VdmObjects)
00456             {
00457                 /* Allow the EM flag */
00458                 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
00459                                            (CR0_EM | CR0_MP);
00460             }
00461         }
00462     }
00463 
00464     /* Handle the floating point state */
00465     if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
00466         CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
00467     {
00468         /* Get the FX Area */
00469         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
00470 
00471         /* Check if NPX is present */
00472         if (KeI386NpxPresent)
00473         {
00474             /* Flush the NPX State */
00475             KiFlushNPXState(NULL);
00476 
00477             /* Check if we have Fxsr support */
00478             if (KeI386FxsrPresent)
00479             {
00480                 /* Convert the Fn Floating Point state to Fx */
00481                 FxSaveArea->U.FxArea.ControlWord =
00482                     (USHORT)Context->FloatSave.ControlWord;
00483                 FxSaveArea->U.FxArea.StatusWord =
00484                     (USHORT)Context->FloatSave.StatusWord;
00485                 FxSaveArea->U.FxArea.TagWord =
00486                     KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord);
00487                 FxSaveArea->U.FxArea.ErrorOpcode =
00488                     (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF);
00489                 FxSaveArea->U.FxArea.ErrorOffset =
00490                     Context->FloatSave.ErrorOffset;
00491                 FxSaveArea->U.FxArea.ErrorSelector =
00492                     Context->FloatSave.ErrorSelector & 0xFFFF;
00493                 FxSaveArea->U.FxArea.DataOffset =
00494                     Context->FloatSave.DataOffset;
00495                 FxSaveArea->U.FxArea.DataSelector =
00496                     Context->FloatSave.DataSelector;
00497 
00498                 /* Clear out the Register Area */
00499                 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0],
00500                               SIZE_OF_FX_REGISTERS);
00501 
00502                 /* Loop the 8 floating point registers */
00503                 for (i = 0; i < 8; i++)
00504                 {
00505                     /* Copy from Fn to Fx */
00506                     RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
00507                                   Context->FloatSave.RegisterArea + (i * 10),
00508                                   10);
00509                 }
00510             }
00511             else
00512             {
00513                 /* Copy the structure */
00514                 FxSaveArea->U.FnArea.ControlWord = Context->FloatSave.
00515                                                    ControlWord;
00516                 FxSaveArea->U.FnArea.StatusWord = Context->FloatSave.
00517                                                   StatusWord;
00518                 FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord;
00519                 FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave.
00520                                                    ErrorOffset;
00521                 FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave.
00522                                                      ErrorSelector;
00523                 FxSaveArea->U.FnArea.DataOffset = Context->FloatSave.
00524                                                   DataOffset;
00525                 FxSaveArea->U.FnArea.DataSelector = Context->FloatSave.
00526                                                     DataSelector;
00527 
00528                 /* Loop registers */
00529                 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
00530                 {
00531                     /* Copy registers */
00532                     FxSaveArea->U.FnArea.RegisterArea[i] =
00533                         Context->FloatSave.RegisterArea[i];
00534                 }
00535             }
00536 
00537             /* Mask out any invalid flags */
00538             FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
00539 
00540             /* Check if this is a VDM app */
00541             if (PsGetCurrentProcess()->VdmObjects)
00542             {
00543                 /* Allow the EM flag */
00544                 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState &
00545                     (CR0_EM | CR0_MP);
00546             }
00547         }
00548         else
00549         {
00550             /* FIXME: Handle FPU Emulation */
00551             //ASSERT(FALSE);
00552         }
00553     }
00554 
00555     /* Handle the Debug Registers */
00556     if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
00557     {
00558         /* Copy Dr0 - Dr4 */
00559         TrapFrame->Dr0 = Context->Dr0;
00560         TrapFrame->Dr1 = Context->Dr1;
00561         TrapFrame->Dr2 = Context->Dr2;
00562         TrapFrame->Dr3 = Context->Dr3;
00563 
00564         /* If we're in user-mode */
00565         if (PreviousMode != KernelMode)
00566         {
00567             /* Make sure, no Dr address is above user space */
00568             if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0;
00569             if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0;
00570             if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0;
00571             if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0;
00572         }
00573 
00574         /* Now sanitize and save DR6 */
00575         TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL;
00576 
00577         /* Update the Dr active mask */
00578         if (TrapFrame->Dr0) DrMask |= DR_MASK(0);
00579         if (TrapFrame->Dr1) DrMask |= DR_MASK(1);
00580         if (TrapFrame->Dr2) DrMask |= DR_MASK(2);
00581         if (TrapFrame->Dr3) DrMask |= DR_MASK(3);
00582         if (TrapFrame->Dr6) DrMask |= DR_MASK(6);
00583 
00584         /* Sanitize and save DR7 */
00585         TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL;
00586         KiRecordDr7(&TrapFrame->Dr7, &DrMask);
00587 
00588         /* If we're in user-mode */
00589         if (PreviousMode != KernelMode)
00590         {
00591             /* Save the mask */
00592             KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask;
00593         }
00594     }
00595 
00596     /* Check if thread has IOPL and force it enabled if so */
00597     if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
00598 
00599     /* Restore IRQL */
00600     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
00601 }
00602 
00603 VOID
00604 NTAPI
00605 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
00606                      IN PKEXCEPTION_FRAME ExceptionFrame,
00607                      IN OUT PCONTEXT Context)
00608 {
00609     PFX_SAVE_AREA FxSaveArea;
00610     struct _AlignHack
00611     {
00612         UCHAR Hack[15];
00613         FLOATING_SAVE_AREA UnalignedArea;
00614     } FloatSaveBuffer;
00615     FLOATING_SAVE_AREA *FloatSaveArea;
00616     KIRQL OldIrql;
00617     ULONG i;
00618 
00619     /* Do this at APC_LEVEL */
00620     OldIrql = KeGetCurrentIrql();
00621     if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
00622 
00623     /* Start with the Control flags */
00624     if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
00625     {
00626         /* EBP, EIP and EFLAGS */
00627         Context->Ebp = TrapFrame->Ebp;
00628         Context->Eip = TrapFrame->Eip;
00629         Context->EFlags = TrapFrame->EFlags;
00630 
00631         /* Return the correct CS */
00632         if (!(TrapFrame->SegCs & FRAME_EDITED) &&
00633             !(TrapFrame->EFlags & EFLAGS_V86_MASK))
00634         {
00635             /* Get it from the Temp location */
00636             Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
00637         }
00638         else
00639         {
00640             /* Return it directly */
00641             Context->SegCs = TrapFrame->SegCs & 0xFFFF;
00642         }
00643 
00644         /* Get the Ss and ESP */
00645         Context->SegSs = KiSsFromTrapFrame(TrapFrame);
00646         Context->Esp = KiEspFromTrapFrame(TrapFrame);
00647     }
00648 
00649     /* Handle the Segments */
00650     if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
00651     {
00652         /* Do V86 Mode first */
00653         if (TrapFrame->EFlags & EFLAGS_V86_MASK)
00654         {
00655             /* Return from the V86 location */
00656             Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
00657             Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
00658             Context->SegEs = TrapFrame->V86Es & 0xFFFF;
00659             Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
00660         }
00661         else
00662         {
00663             /* Check if this was a Kernel Trap */
00664             if (TrapFrame->SegCs == KGDT_R0_CODE)
00665             {
00666                 /* Set valid selectors */
00667                 TrapFrame->SegGs = 0;
00668                 TrapFrame->SegFs = KGDT_R0_PCR;
00669                 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
00670                 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
00671             }
00672 
00673             /* Return the segments */
00674             Context->SegGs = TrapFrame->SegGs & 0xFFFF;
00675             Context->SegFs = TrapFrame->SegFs & 0xFFFF;
00676             Context->SegEs = TrapFrame->SegEs & 0xFFFF;
00677             Context->SegDs = TrapFrame->SegDs & 0xFFFF;
00678         }
00679     }
00680 
00681     /* Handle the simple registers */
00682     if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
00683     {
00684         /* Return them directly */
00685         Context->Eax = TrapFrame->Eax;
00686         Context->Ebx = TrapFrame->Ebx;
00687         Context->Ecx = TrapFrame->Ecx;
00688         Context->Edx = TrapFrame->Edx;
00689         Context->Esi = TrapFrame->Esi;
00690         Context->Edi = TrapFrame->Edi;
00691     }
00692 
00693     /* Handle extended registers */
00694     if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
00695         CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
00696     {
00697         /* Get the FX Save Area */
00698         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
00699 
00700         /* Make sure NPX is present */
00701         if (KeI386NpxPresent)
00702         {
00703             /* Flush the NPX State */
00704             KiFlushNPXState(NULL);
00705 
00706             /* Copy the registers */
00707             RtlCopyMemory(&Context->ExtendedRegisters[0],
00708                           &FxSaveArea->U.FxArea,
00709                           MAXIMUM_SUPPORTED_EXTENSION);
00710         }
00711     }
00712 
00713     /* Handle Floating Point */
00714     if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
00715         CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
00716     {
00717         /* Get the FX Save Area */
00718         FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
00719 
00720         /* Make sure we have an NPX */
00721         if (KeI386NpxPresent)
00722          {
00723             /* Check if we have Fxsr support */
00724             if (KeI386FxsrPresent)
00725             {
00726                 /* Align the floating area to 16-bytes */
00727                 FloatSaveArea = (FLOATING_SAVE_AREA*)
00728                                 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
00729 
00730                 /* Get the State */
00731                 KiFlushNPXState(FloatSaveArea);
00732             }
00733             else
00734             {
00735                 /* We don't, use the FN area and flush the NPX State */
00736                 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
00737                 KiFlushNPXState(NULL);
00738             }
00739 
00740             /* Copy structure */
00741             Context->FloatSave.ControlWord = FloatSaveArea->ControlWord;
00742             Context->FloatSave.StatusWord = FloatSaveArea->StatusWord;
00743             Context->FloatSave.TagWord = FloatSaveArea->TagWord;
00744             Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset;
00745             Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector;
00746             Context->FloatSave.DataOffset = FloatSaveArea->DataOffset;
00747             Context->FloatSave.DataSelector = FloatSaveArea->DataSelector;
00748             Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState;
00749 
00750             /* Loop registers */
00751             for (i = 0; i < SIZE_OF_80387_REGISTERS; i++)
00752             {
00753                 /* Copy them */
00754                 Context->FloatSave.RegisterArea[i] =
00755                     FloatSaveArea->RegisterArea[i];
00756             }
00757          }
00758          else
00759          {
00760             /* FIXME: Handle Emulation */
00761             ASSERT(FALSE);
00762          }
00763     }
00764 
00765     /* Handle debug registers */
00766     if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
00767         CONTEXT_DEBUG_REGISTERS)
00768     {
00769         /* Make sure DR7 is valid */
00770         if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK)
00771         {
00772             /* Copy the debug registers */
00773             Context->Dr0 = TrapFrame->Dr0;
00774             Context->Dr1 = TrapFrame->Dr1;
00775             Context->Dr2 = TrapFrame->Dr2;
00776             Context->Dr3 = TrapFrame->Dr3;
00777             Context->Dr6 = TrapFrame->Dr6;
00778 
00779             /* Update DR7 */
00780             Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
00781         }
00782         else
00783         {
00784             /* Otherwise clear DR registers */
00785             Context->Dr0 =
00786             Context->Dr1 =
00787             Context->Dr2 =
00788             Context->Dr3 =
00789             Context->Dr6 =
00790             Context->Dr7 = 0;
00791         }
00792     }
00793 
00794     /* Restore IRQL */
00795     if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
00796 }
00797 
00798 BOOLEAN
00799 FASTCALL
00800 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL)
00801 {
00802     ULONG Eip;
00803     PKTRAP_FRAME TrapFrame = TrapInformation;
00804     VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
00805 
00806     /* Don't do anything if we didn't get a trap frame */
00807     if (!TrapInformation) return FALSE;
00808 
00809     /* Check where we came from */
00810     switch (TrapFrame->SegCs)
00811     {
00812         /* Kernel mode */
00813         case KGDT_R0_CODE:
00814 
00815             /* Allow S-LIST Routine to fail */
00816             Eip = (ULONG)&ExpInterlockedPopEntrySListFault;
00817             break;
00818 
00819         /* User code */
00820         case KGDT_R3_CODE | RPL_MASK:
00821 
00822             /* Allow S-LIST Routine to fail */
00823             //Eip = (ULONG)KeUserPopEntrySListFault;
00824             Eip = 0;
00825             break;
00826 
00827         default:
00828 
00829             /* Anything else gets a bugcheck */
00830             Eip = 0;
00831     }
00832 
00833     /* Return TRUE if we want to keep the system up */
00834     return (TrapFrame->Eip == Eip) ? TRUE : FALSE;
00835 }
00836 
00837 VOID
00838 NTAPI
00839 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
00840                     IN PKEXCEPTION_FRAME ExceptionFrame,
00841                     IN PKTRAP_FRAME TrapFrame,
00842                     IN KPROCESSOR_MODE PreviousMode,
00843                     IN BOOLEAN FirstChance)
00844 {
00845     CONTEXT Context;
00846     EXCEPTION_RECORD LocalExceptRecord;
00847 
00848     /* Increase number of Exception Dispatches */
00849     KeGetCurrentPrcb()->KeExceptionDispatchCount++;
00850 
00851     /* Set the context flags */
00852     Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
00853 
00854     /* Check if User Mode or if the kernel debugger is enabled */
00855     if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock))
00856     {
00857         /* Add the FPU Flag */
00858         Context.ContextFlags |= CONTEXT_FLOATING_POINT;
00859 
00860         /* Check for NPX Support */
00861         if (KeI386FxsrPresent)
00862         {
00863             /* Save those too */
00864             Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
00865         }
00866     }
00867 
00868     /* Get a Context */
00869     KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
00870 
00871     /* Look at our exception code */
00872     switch (ExceptionRecord->ExceptionCode)
00873     {
00874         /* Breakpoint */
00875         case STATUS_BREAKPOINT:
00876 
00877             /* Decrement EIP by one */
00878             Context.Eip--;
00879             break;
00880 
00881         /* Internal exception */
00882         case KI_EXCEPTION_ACCESS_VIOLATION:
00883 
00884             /* Set correct code */
00885             ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
00886             if (PreviousMode == UserMode)
00887             {
00888                 /* FIXME: Handle no execute */
00889             }
00890             break;
00891     }
00892 
00893     /* Sanity check */
00894     ASSERT(!((PreviousMode == KernelMode) &&
00895              (Context.EFlags & EFLAGS_V86_MASK)));
00896 
00897     /* Handle kernel-mode first, it's simpler */
00898     if (PreviousMode == KernelMode)
00899     {
00900         /* Check if this is a first-chance exception */
00901         if (FirstChance == TRUE)
00902         {
00903             /* Break into the debugger for the first time */
00904             if (KiDebugRoutine(TrapFrame,
00905                                ExceptionFrame,
00906                                ExceptionRecord,
00907                                &Context,
00908                                PreviousMode,
00909                                FALSE))
00910             {
00911                 /* Exception was handled */
00912                 goto Handled;
00913             }
00914 
00915             /* If the Debugger couldn't handle it, dispatch the exception */
00916             if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
00917         }
00918 
00919         /* This is a second-chance exception, only for the debugger */
00920         if (KiDebugRoutine(TrapFrame,
00921                            ExceptionFrame,
00922                            ExceptionRecord,
00923                            &Context,
00924                            PreviousMode,
00925                            TRUE))
00926         {
00927             /* Exception was handled */
00928             goto Handled;
00929         }
00930 
00931         /* Third strike; you're out */
00932         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
00933                      ExceptionRecord->ExceptionCode,
00934                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
00935                      (ULONG_PTR)TrapFrame,
00936                      0);
00937     }
00938     else
00939     {
00940         /* User mode exception, was it first-chance? */
00941         if (FirstChance)
00942         {
00943             /*
00944              * Break into the kernel debugger unless a user mode debugger
00945              * is present or user mode exceptions are ignored, except if this
00946              * is a debug service which we must always pass to KD
00947              */
00948             if ((!(PsGetCurrentProcess()->DebugPort) &&
00949                  !(KdIgnoreUmExceptions)) ||
00950                  (KdIsThisAKdTrap(ExceptionRecord,
00951                                   &Context,
00952                                   PreviousMode)))
00953             {
00954                 /* Call the kernel debugger */
00955                 if (KiDebugRoutine(TrapFrame,
00956                                    ExceptionFrame,
00957                                    ExceptionRecord,
00958                                    &Context,
00959                                    PreviousMode,
00960                                    FALSE))
00961                 {
00962                     /* Exception was handled */
00963                     goto Handled;
00964                 }
00965             }
00966 
00967             /* Forward exception to user mode debugger */
00968             if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return;
00969 
00970             /* Set up the user-stack */
00971 DispatchToUser:
00972             _SEH2_TRY
00973             {
00974                 ULONG Size;
00975                 ULONG_PTR Stack, NewStack;
00976 
00977                 /* Make sure we have a valid SS and that this isn't V86 mode */
00978                 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) ||
00979                     (TrapFrame->EFlags & EFLAGS_V86_MASK))
00980                 {
00981                     /* Raise an exception instead */
00982                     LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
00983                     LocalExceptRecord.ExceptionFlags = 0;
00984                     LocalExceptRecord.NumberParameters = 0;
00985                     RtlRaiseException(&LocalExceptRecord);
00986                 }
00987 
00988                 /* Align context size and get stack pointer */
00989                 Size = (sizeof(CONTEXT) + 3) & ~3;
00990                 Stack = (Context.Esp & ~3) - Size;
00991 
00992                 /* Probe stack and copy Context */
00993                 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
00994                 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
00995 
00996                 /* Align exception record size and get stack pointer */
00997                 Size = (sizeof(EXCEPTION_RECORD) -
00998                        (EXCEPTION_MAXIMUM_PARAMETERS -
00999                         ExceptionRecord->NumberParameters) *
01000                        sizeof(ULONG) + 3) & ~3;
01001                 NewStack = Stack - Size;
01002 
01003                 /* Probe stack and copy exception record */
01004                 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
01005                               Size +  2 * sizeof(ULONG_PTR),
01006                               sizeof(ULONG));
01007                 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
01008 
01009                 /* Now write the two params for the user-mode dispatcher */
01010                 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
01011                 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
01012 
01013                 /* Set new Stack Pointer */
01014                 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
01015                 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
01016 
01017                 /* Force correct segments */
01018                 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode);
01019                 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
01020                 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode);
01021                 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB,  PreviousMode);
01022                 TrapFrame->SegGs = 0;
01023 
01024                 /* Set EIP to the User-mode Dispatcher */
01025                 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
01026 
01027                 /* Dispatch exception to user-mode */
01028                 _SEH2_YIELD(return);
01029             }
01030             _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
01031             {
01032                 /* Check if we got a stack overflow and raise that instead */
01033                 if ((NTSTATUS)LocalExceptRecord.ExceptionCode ==
01034                     STATUS_STACK_OVERFLOW)
01035                 {
01036                     /* Copy the exception address and record */
01037                     LocalExceptRecord.ExceptionAddress =
01038                         ExceptionRecord->ExceptionAddress;
01039                     RtlCopyMemory(ExceptionRecord,
01040                                   (PVOID)&LocalExceptRecord,
01041                                   sizeof(EXCEPTION_RECORD));
01042 
01043                     /* Do the exception again */
01044                     _SEH2_YIELD(goto DispatchToUser);
01045                 }
01046             }
01047             _SEH2_END;
01048         }
01049 
01050         /* Try second chance */
01051         if (DbgkForwardException(ExceptionRecord, TRUE, TRUE))
01052         {
01053             /* Handled, get out */
01054             return;
01055         }
01056         else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
01057         {
01058             /* Handled, get out */
01059             return;
01060         }
01061 
01062         /* 3rd strike, kill the process */
01063         DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx, BaseAddress: %lx\n",
01064                 PsGetCurrentProcess()->ImageFileName,
01065                 ExceptionRecord->ExceptionCode,
01066                 ExceptionRecord->ExceptionAddress,
01067                 PsGetCurrentProcess()->SectionBaseAddress);
01068 
01069         ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
01070         KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
01071                      ExceptionRecord->ExceptionCode,
01072                      (ULONG_PTR)ExceptionRecord->ExceptionAddress,
01073                      (ULONG_PTR)TrapFrame,
01074                      0);
01075     }
01076 
01077 Handled:
01078     /* Convert the context back into Trap/Exception Frames */
01079     KeContextToTrapFrame(&Context,
01080                          ExceptionFrame,
01081                          TrapFrame,
01082                          Context.ContextFlags,
01083                          PreviousMode);
01084     return;
01085 }
01086 
01087 DECLSPEC_NORETURN
01088 VOID
01089 NTAPI
01090 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code,
01091                                  IN ULONG_PTR Address,
01092                                  IN ULONG ParameterCount,
01093                                  IN ULONG_PTR Parameter1,
01094                                  IN ULONG_PTR Parameter2,
01095                                  IN ULONG_PTR Parameter3,
01096                                  IN PKTRAP_FRAME TrapFrame)
01097 {
01098     EXCEPTION_RECORD ExceptionRecord;
01099 
01100     /* Build the exception record */
01101     ExceptionRecord.ExceptionCode = Code;
01102     ExceptionRecord.ExceptionFlags = 0;
01103     ExceptionRecord.ExceptionRecord = NULL;
01104     ExceptionRecord.ExceptionAddress = (PVOID)Address;
01105     ExceptionRecord.NumberParameters = ParameterCount;
01106     if (ParameterCount)
01107     {
01108         /* Copy extra parameters */
01109         ExceptionRecord.ExceptionInformation[0] = Parameter1;
01110         ExceptionRecord.ExceptionInformation[1] = Parameter2;
01111         ExceptionRecord.ExceptionInformation[2] = Parameter3;
01112     }
01113 
01114     /* Now go dispatch the exception */
01115     KiDispatchException(&ExceptionRecord,
01116                         NULL,
01117                         TrapFrame,
01118                         TrapFrame->EFlags & EFLAGS_V86_MASK ?
01119                         -1 : KiUserTrap(TrapFrame),
01120                         TRUE);
01121 
01122     /* Return from this trap */
01123     KiEoiHelper(TrapFrame);
01124 }
01125 
01126 DECLSPEC_NORETURN
01127 VOID
01128 FASTCALL
01129 KiSystemFatalException(IN ULONG ExceptionCode,
01130                        IN PKTRAP_FRAME TrapFrame)
01131 {
01132     /* Bugcheck the system */
01133     KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
01134                      ExceptionCode,
01135                      0,
01136                      0,
01137                      0,
01138                      TrapFrame);
01139 }
01140 
01141 /* PUBLIC FUNCTIONS ***********************************************************/
01142 
01143 /*
01144  * @implemented
01145  */
01146 NTSTATUS
01147 NTAPI
01148 KeRaiseUserException(IN NTSTATUS ExceptionCode)
01149 {
01150     ULONG OldEip;
01151     PTEB Teb = KeGetCurrentThread()->Teb;
01152     PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
01153 
01154     /* Make sure we can access the TEB */
01155     _SEH2_TRY
01156     {
01157         /* Set the exception code */
01158         Teb->ExceptionCode = ExceptionCode;
01159     }
01160     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
01161     {
01162         /* Return the exception code */
01163         _SEH2_YIELD(return _SEH2_GetExceptionCode());
01164     }
01165     _SEH2_END;
01166 
01167     /* Get the old EIP */
01168     OldEip = TrapFrame->Eip;
01169 
01170     /* Change it to the user-mode dispatcher */
01171     TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
01172 
01173     /* Return the old EIP */
01174     return (NTSTATUS)OldEip;
01175 }

Generated on Sun May 27 2012 04:36:28 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.