Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenexp.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
1.7.6.1
|