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