1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: ntoskrnl/ke/i386/traphdlr.c 5 * PURPOSE: Kernel Trap Handlers 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 VOID __cdecl KiFastCallEntry(VOID); 16 VOID __cdecl KiFastCallEntryWithSingleStep(VOID); 17 18 extern PVOID KeUserPopEntrySListFault; 19 extern PVOID KeUserPopEntrySListResume; 20 extern PVOID FrRestore; 21 VOID FASTCALL Ke386LoadFpuState(IN PFX_SAVE_AREA SaveArea); 22 23 /* GLOBALS ********************************************************************/ 24 25 UCHAR KiTrapPrefixTable[] = 26 { 27 0xF2, /* REP */ 28 0xF3, /* REP INS/OUTS */ 29 0x67, /* ADDR */ 30 0xF0, /* LOCK */ 31 0x66, /* OP */ 32 0x2E, /* SEG */ 33 0x3E, /* DS */ 34 0x26, /* ES */ 35 0x64, /* FS */ 36 0x65, /* GS */ 37 0x36, /* SS */ 38 }; 39 40 UCHAR KiTrapIoTable[] = 41 { 42 0xE4, /* IN */ 43 0xE5, /* IN */ 44 0xEC, /* IN */ 45 0xED, /* IN */ 46 0x6C, /* INS */ 47 0x6D, /* INS */ 48 0xE6, /* OUT */ 49 0xE7, /* OUT */ 50 0xEE, /* OUT */ 51 0xEF, /* OUT */ 52 0x6E, /* OUTS */ 53 0x6F, /* OUTS */ 54 }; 55 56 PFAST_SYSTEM_CALL_EXIT KiFastCallExitHandler; 57 #if DBG && defined(_M_IX86) && !defined(_WINKD_) 58 PKDBG_PRESERVICEHOOK KeWin32PreServiceHook = NULL; 59 PKDBG_POSTSERVICEHOOK KeWin32PostServiceHook = NULL; 60 #endif 61 #if DBG 62 BOOLEAN StopChecking = FALSE; 63 #endif 64 65 66 /* TRAP EXIT CODE *************************************************************/ 67 68 FORCEINLINE 69 BOOLEAN 70 KiVdmTrap(IN PKTRAP_FRAME TrapFrame) 71 { 72 /* Either the V8086 flag is on, or this is user-mode with a VDM */ 73 return ((TrapFrame->EFlags & EFLAGS_V86_MASK) || 74 ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects))); 75 } 76 77 FORCEINLINE 78 BOOLEAN 79 KiV86Trap(IN PKTRAP_FRAME TrapFrame) 80 { 81 /* Check if the V8086 flag is on */ 82 return ((TrapFrame->EFlags & EFLAGS_V86_MASK) != 0); 83 } 84 85 FORCEINLINE 86 BOOLEAN 87 KiIsFrameEdited(IN PKTRAP_FRAME TrapFrame) 88 { 89 /* An edited frame changes esp. It is marked by clearing the bits 90 defined by FRAME_EDITED in the SegCs field of the trap frame */ 91 return ((TrapFrame->SegCs & FRAME_EDITED) == 0); 92 } 93 94 FORCEINLINE 95 VOID 96 KiCommonExit(IN PKTRAP_FRAME TrapFrame, BOOLEAN SkipPreviousMode) 97 { 98 /* Disable interrupts until we return */ 99 _disable(); 100 101 /* Check for APC delivery */ 102 KiCheckForApcDelivery(TrapFrame); 103 104 /* Restore the SEH handler chain */ 105 KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList; 106 107 /* Check if there are active debug registers */ 108 if (__builtin_expect(TrapFrame->Dr7 & ~DR7_RESERVED_MASK, 0)) 109 { 110 /* Check if the frame was from user mode or v86 mode */ 111 if (KiUserTrap(TrapFrame) || 112 (TrapFrame->EFlags & EFLAGS_V86_MASK)) 113 { 114 /* Handle debug registers */ 115 KiHandleDebugRegistersOnTrapExit(TrapFrame); 116 } 117 } 118 119 /* Debugging checks */ 120 KiExitTrapDebugChecks(TrapFrame, SkipPreviousMode); 121 } 122 123 DECLSPEC_NORETURN 124 VOID 125 FASTCALL 126 KiEoiHelper(IN PKTRAP_FRAME TrapFrame) 127 { 128 /* Common trap exit code */ 129 KiCommonExit(TrapFrame, TRUE); 130 131 /* Check if this was a V8086 trap */ 132 if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame); 133 134 /* Check for user mode exit */ 135 if (KiUserTrap(TrapFrame)) KiTrapReturn(TrapFrame); 136 137 /* Check for edited frame */ 138 if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame); 139 140 /* Check if we have single stepping enabled */ 141 if (TrapFrame->EFlags & EFLAGS_TF) KiTrapReturnNoSegments(TrapFrame); 142 143 /* Exit the trap to kernel mode */ 144 KiTrapReturnNoSegmentsRet8(TrapFrame); 145 } 146 147 DECLSPEC_NORETURN 148 VOID 149 FASTCALL 150 KiServiceExit(IN PKTRAP_FRAME TrapFrame, 151 IN NTSTATUS Status) 152 { 153 ASSERT((TrapFrame->EFlags & EFLAGS_V86_MASK) == 0); 154 ASSERT(!KiIsFrameEdited(TrapFrame)); 155 156 /* Copy the status into EAX */ 157 TrapFrame->Eax = Status; 158 159 /* Common trap exit code */ 160 KiCommonExit(TrapFrame, FALSE); 161 162 /* Restore previous mode */ 163 KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode; 164 165 /* Check for user mode exit */ 166 if (KiUserTrap(TrapFrame)) 167 { 168 /* Check if we were single stepping */ 169 if (TrapFrame->EFlags & EFLAGS_TF) 170 { 171 /* Must use the IRET handler */ 172 KiSystemCallTrapReturn(TrapFrame); 173 } 174 else 175 { 176 /* We can use the sysexit handler */ 177 KiFastCallExitHandler(TrapFrame); 178 UNREACHABLE; 179 } 180 } 181 182 /* Exit to kernel mode */ 183 KiSystemCallReturn(TrapFrame); 184 } 185 186 DECLSPEC_NORETURN 187 VOID 188 FASTCALL 189 KiServiceExit2(IN PKTRAP_FRAME TrapFrame) 190 { 191 /* Common trap exit code */ 192 KiCommonExit(TrapFrame, FALSE); 193 194 /* Restore previous mode */ 195 KeGetCurrentThread()->PreviousMode = (CCHAR)TrapFrame->PreviousPreviousMode; 196 197 /* Check if this was a V8086 trap */ 198 if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturnNoSegments(TrapFrame); 199 200 /* Check for user mode exit */ 201 if (KiUserTrap(TrapFrame)) KiTrapReturn(TrapFrame); 202 203 /* Check for edited frame */ 204 if (KiIsFrameEdited(TrapFrame)) KiEditedTrapReturn(TrapFrame); 205 206 /* Check if we have single stepping enabled */ 207 if (TrapFrame->EFlags & EFLAGS_TF) KiTrapReturnNoSegments(TrapFrame); 208 209 /* Exit the trap to kernel mode */ 210 KiTrapReturnNoSegmentsRet8(TrapFrame); 211 } 212 213 214 /* TRAP HANDLERS **************************************************************/ 215 216 DECLSPEC_NORETURN 217 VOID 218 FASTCALL 219 KiDebugHandler(IN PKTRAP_FRAME TrapFrame, 220 IN ULONG Parameter1, 221 IN ULONG Parameter2, 222 IN ULONG Parameter3) 223 { 224 /* Check for VDM trap */ 225 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 226 227 /* Enable interrupts if the trap came from user-mode */ 228 if (KiUserTrap(TrapFrame)) _enable(); 229 230 /* Dispatch the exception */ 231 KiDispatchExceptionFromTrapFrame(STATUS_BREAKPOINT, 232 0, 233 TrapFrame->Eip - 1, 234 3, 235 Parameter1, 236 Parameter2, 237 Parameter3, 238 TrapFrame); 239 } 240 241 DECLSPEC_NORETURN 242 VOID 243 FASTCALL 244 KiNpxHandler(IN PKTRAP_FRAME TrapFrame, 245 IN PKTHREAD Thread, 246 IN PFX_SAVE_AREA SaveArea) 247 { 248 ULONG Cr0, Mask, Error, ErrorOffset, DataOffset; 249 250 /* Check for VDM trap */ 251 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 252 253 /* Check for kernel trap */ 254 if (!KiUserTrap(TrapFrame)) 255 { 256 /* Kernel might've tripped a delayed error */ 257 SaveArea->Cr0NpxState |= CR0_TS; 258 259 /* Only valid if it happened during a restore */ 260 if ((PVOID)TrapFrame->Eip == FrRestore) 261 { 262 /* It did, so just skip the instruction */ 263 TrapFrame->Eip += 3; /* Size of FRSTOR instruction */ 264 KiEoiHelper(TrapFrame); 265 } 266 } 267 268 /* User or kernel trap -- check if we need to unload the current state */ 269 if (Thread->NpxState == NPX_STATE_LOADED) 270 { 271 /* Update CR0 */ 272 Cr0 = __readcr0(); 273 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS); 274 __writecr0(Cr0); 275 276 /* Save FPU state */ 277 Ke386SaveFpuState(SaveArea); 278 279 /* Mark CR0 state dirty */ 280 Cr0 |= NPX_STATE_NOT_LOADED; 281 Cr0 |= SaveArea->Cr0NpxState; 282 __writecr0(Cr0); 283 284 /* Update NPX state */ 285 Thread->NpxState = NPX_STATE_NOT_LOADED; 286 KeGetCurrentPrcb()->NpxThread = NULL; 287 } 288 289 /* Clear the TS bit and re-enable interrupts */ 290 SaveArea->Cr0NpxState &= ~CR0_TS; 291 _enable(); 292 293 /* Check if we should get the FN or FX error */ 294 if (KeI386FxsrPresent) 295 { 296 /* Get it from FX */ 297 Mask = SaveArea->U.FxArea.ControlWord; 298 Error = SaveArea->U.FxArea.StatusWord; 299 300 /* Get the FPU exception address too */ 301 ErrorOffset = SaveArea->U.FxArea.ErrorOffset; 302 DataOffset = SaveArea->U.FxArea.DataOffset; 303 } 304 else 305 { 306 /* Get it from FN */ 307 Mask = SaveArea->U.FnArea.ControlWord; 308 Error = SaveArea->U.FnArea.StatusWord; 309 310 /* Get the FPU exception address too */ 311 ErrorOffset = SaveArea->U.FnArea.ErrorOffset; 312 DataOffset = SaveArea->U.FnArea.DataOffset; 313 } 314 315 /* Get legal exceptions that software should handle */ 316 Mask &= (FSW_INVALID_OPERATION | 317 FSW_DENORMAL | 318 FSW_ZERO_DIVIDE | 319 FSW_OVERFLOW | 320 FSW_UNDERFLOW | 321 FSW_PRECISION); 322 Error &= ~Mask; 323 324 /* Check for invalid operation */ 325 if (Error & FSW_INVALID_OPERATION) 326 { 327 /* 328 * Now check if this is actually a Stack Fault. This is needed because 329 * on x86 the Invalid Operation error is set for Stack Check faults as well. 330 */ 331 if (Error & FSW_STACK_FAULT) 332 { 333 /* Issue stack check fault */ 334 KiDispatchException2Args(STATUS_FLOAT_STACK_CHECK, 335 ErrorOffset, 336 0, 337 DataOffset, 338 TrapFrame); 339 } 340 else 341 { 342 /* This is an invalid operation fault after all, so raise that instead */ 343 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION, 344 ErrorOffset, 345 0, 346 TrapFrame); 347 } 348 } 349 350 /* Check for divide by zero */ 351 if (Error & FSW_ZERO_DIVIDE) 352 { 353 /* Issue fault */ 354 KiDispatchException1Args(STATUS_FLOAT_DIVIDE_BY_ZERO, 355 ErrorOffset, 356 0, 357 TrapFrame); 358 } 359 360 /* Check for denormal */ 361 if (Error & FSW_DENORMAL) 362 { 363 /* Issue fault */ 364 KiDispatchException1Args(STATUS_FLOAT_INVALID_OPERATION, 365 ErrorOffset, 366 0, 367 TrapFrame); 368 } 369 370 /* Check for overflow */ 371 if (Error & FSW_OVERFLOW) 372 { 373 /* Issue fault */ 374 KiDispatchException1Args(STATUS_FLOAT_OVERFLOW, 375 ErrorOffset, 376 0, 377 TrapFrame); 378 } 379 380 /* Check for underflow */ 381 if (Error & FSW_UNDERFLOW) 382 { 383 /* Issue fault */ 384 KiDispatchException1Args(STATUS_FLOAT_UNDERFLOW, 385 ErrorOffset, 386 0, 387 TrapFrame); 388 } 389 390 /* Check for precision fault */ 391 if (Error & FSW_PRECISION) 392 { 393 /* Issue fault */ 394 KiDispatchException1Args(STATUS_FLOAT_INEXACT_RESULT, 395 ErrorOffset, 396 0, 397 TrapFrame); 398 } 399 400 /* Unknown FPU fault */ 401 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 1, Error, 0, 0, TrapFrame); 402 } 403 404 DECLSPEC_NORETURN 405 VOID 406 FASTCALL 407 KiTrap00Handler(IN PKTRAP_FRAME TrapFrame) 408 { 409 /* Save trap frame */ 410 KiEnterTrap(TrapFrame); 411 412 /* Check for VDM trap */ 413 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 414 415 /* Enable interrupts */ 416 _enable(); 417 418 /* Dispatch the exception */ 419 KiDispatchException0Args(STATUS_INTEGER_DIVIDE_BY_ZERO, 420 TrapFrame->Eip, 421 TrapFrame); 422 } 423 424 DECLSPEC_NORETURN 425 VOID 426 FASTCALL 427 KiTrap01Handler(IN PKTRAP_FRAME TrapFrame) 428 { 429 /* Save trap frame */ 430 KiEnterTrap(TrapFrame); 431 432 /* Check for VDM trap */ 433 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 434 435 /* Check if this was a single step after sysenter */ 436 if (TrapFrame->Eip == (ULONG)KiFastCallEntry) 437 { 438 /* Disable single stepping */ 439 TrapFrame->EFlags &= ~EFLAGS_TF; 440 441 /* Re-enter at the alternative sysenter entry point */ 442 TrapFrame->Eip = (ULONG)KiFastCallEntryWithSingleStep; 443 444 /* End this trap */ 445 KiEoiHelper(TrapFrame); 446 } 447 448 /* Enable interrupts if the trap came from user-mode */ 449 if (KiUserTrap(TrapFrame)) _enable(); 450 451 /* Mask out trap flag and dispatch the exception */ 452 TrapFrame->EFlags &= ~EFLAGS_TF; 453 KiDispatchException0Args(STATUS_SINGLE_STEP, 454 TrapFrame->Eip, 455 TrapFrame); 456 } 457 458 VOID 459 __cdecl 460 KiTrap02Handler(VOID) 461 { 462 PKTSS Tss, NmiTss; 463 PKTHREAD Thread; 464 PKPROCESS Process; 465 PKGDTENTRY TssGdt; 466 KTRAP_FRAME TrapFrame; 467 KIRQL OldIrql; 468 469 /* 470 * In some sort of strange recursion case, we might end up here with the IF 471 * flag incorrectly on the interrupt frame -- during a normal NMI this would 472 * normally already be set. 473 * 474 * For sanity's sake, make sure interrupts are disabled for sure. 475 * NMIs will already be since the CPU does it for us. 476 */ 477 _disable(); 478 479 /* Get the current TSS, thread, and process */ 480 Tss = KeGetPcr()->TSS; 481 Thread = ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread; 482 Process = Thread->ApcState.Process; 483 484 /* Save data usually not present in the TSS */ 485 Tss->CR3 = Process->DirectoryTableBase[0]; 486 Tss->IoMapBase = Process->IopmOffset; 487 Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0; 488 489 /* Now get the base address of the NMI TSS */ 490 TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)]; 491 NmiTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | 492 TssGdt->HighWord.Bytes.BaseMid << 16 | 493 TssGdt->HighWord.Bytes.BaseHi << 24); 494 495 /* 496 * Switch to it and activate it, masking off the nested flag. 497 * 498 * Note that in reality, we are already on the NMI TSS -- we just 499 * need to update the PCR to reflect this. 500 */ 501 KeGetPcr()->TSS = NmiTss; 502 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK); 503 TssGdt->HighWord.Bits.Dpl = 0; 504 TssGdt->HighWord.Bits.Pres = 1; 505 TssGdt->HighWord.Bits.Type = I386_TSS; 506 507 /* 508 * Now build the trap frame based on the original TSS. 509 * 510 * The CPU does a hardware "Context switch" / task switch of sorts 511 * and so it takes care of saving our context in the normal TSS. 512 * 513 * We just have to go get the values... 514 */ 515 RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME)); 516 TrapFrame.HardwareSegSs = Tss->Ss0; 517 TrapFrame.HardwareEsp = Tss->Esp0; 518 TrapFrame.EFlags = Tss->EFlags; 519 TrapFrame.SegCs = Tss->Cs; 520 TrapFrame.Eip = Tss->Eip; 521 TrapFrame.Ebp = Tss->Ebp; 522 TrapFrame.Ebx = Tss->Ebx; 523 TrapFrame.Esi = Tss->Esi; 524 TrapFrame.Edi = Tss->Edi; 525 TrapFrame.SegFs = Tss->Fs; 526 TrapFrame.ExceptionList = KeGetPcr()->NtTib.ExceptionList; 527 TrapFrame.PreviousPreviousMode = (ULONG)-1; 528 TrapFrame.Eax = Tss->Eax; 529 TrapFrame.Ecx = Tss->Ecx; 530 TrapFrame.Edx = Tss->Edx; 531 TrapFrame.SegDs = Tss->Ds; 532 TrapFrame.SegEs = Tss->Es; 533 TrapFrame.SegGs = Tss->Gs; 534 TrapFrame.DbgEip = Tss->Eip; 535 TrapFrame.DbgEbp = Tss->Ebp; 536 537 /* Store the trap frame in the KPRCB */ 538 KiSaveProcessorState(&TrapFrame, NULL); 539 540 /* Call any registered NMI handlers and see if they handled it or not */ 541 if (!KiHandleNmi()) 542 { 543 /* 544 * They did not, so call the platform HAL routine to bugcheck the system 545 * 546 * Make sure the HAL believes it's running at HIGH IRQL... we can't use 547 * the normal APIs here as playing with the IRQL could change the system 548 * state. 549 */ 550 OldIrql = KeGetPcr()->Irql; 551 KeGetPcr()->Irql = HIGH_LEVEL; 552 HalHandleNMI(NULL); 553 KeGetPcr()->Irql = OldIrql; 554 } 555 556 /* 557 * Although the CPU disabled NMIs, we just did a BIOS call, which could've 558 * totally changed things. 559 * 560 * We have to make sure we're still in our original NMI -- a nested NMI 561 * will point back to the NMI TSS, and in that case we're hosed. 562 */ 563 if (KeGetPcr()->TSS->Backlink == KGDT_NMI_TSS) 564 { 565 /* Unhandled: crash the system */ 566 KiSystemFatalException(EXCEPTION_NMI, NULL); 567 } 568 569 /* Restore original TSS */ 570 KeGetPcr()->TSS = Tss; 571 572 /* Set it back to busy */ 573 TssGdt->HighWord.Bits.Dpl = 0; 574 TssGdt->HighWord.Bits.Pres = 1; 575 TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS; 576 577 /* Restore nested flag */ 578 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK); 579 580 /* Handled, return from interrupt */ 581 } 582 583 DECLSPEC_NORETURN 584 VOID 585 FASTCALL 586 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame) 587 { 588 /* Save trap frame */ 589 KiEnterTrap(TrapFrame); 590 591 /* Continue with the common handler */ 592 KiDebugHandler(TrapFrame, BREAKPOINT_BREAK, 0, 0); 593 } 594 595 DECLSPEC_NORETURN 596 VOID 597 FASTCALL 598 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame) 599 { 600 /* Save trap frame */ 601 KiEnterTrap(TrapFrame); 602 603 /* Check for VDM trap */ 604 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 605 606 /* Enable interrupts */ 607 _enable(); 608 609 /* Dispatch the exception */ 610 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW, 611 TrapFrame->Eip - 1, 612 TrapFrame); 613 } 614 615 DECLSPEC_NORETURN 616 VOID 617 FASTCALL 618 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame) 619 { 620 /* Save trap frame */ 621 KiEnterTrap(TrapFrame); 622 623 /* Check for VDM trap */ 624 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 625 626 /* Check for kernel-mode fault */ 627 if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_BOUND_CHECK, TrapFrame); 628 629 /* Enable interrupts */ 630 _enable(); 631 632 /* Dispatch the exception */ 633 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED, 634 TrapFrame->Eip, 635 TrapFrame); 636 } 637 638 DECLSPEC_NORETURN 639 VOID 640 FASTCALL 641 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame) 642 { 643 PUCHAR Instruction; 644 ULONG i; 645 KIRQL OldIrql; 646 647 /* Check for V86 GPF */ 648 if (__builtin_expect(KiV86Trap(TrapFrame), 1)) 649 { 650 /* Enter V86 trap */ 651 KiEnterV86Trap(TrapFrame); 652 653 /* Must be a VDM process */ 654 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) 655 { 656 /* Enable interrupts */ 657 _enable(); 658 659 /* Setup illegal instruction fault */ 660 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 661 TrapFrame->Eip, 662 TrapFrame); 663 } 664 665 /* Go to APC level */ 666 KeRaiseIrql(APC_LEVEL, &OldIrql); 667 _enable(); 668 669 /* Check for BOP */ 670 if (!VdmDispatchBop(TrapFrame)) 671 { 672 /* Should only happen in VDM mode */ 673 UNIMPLEMENTED_FATAL(); 674 } 675 676 /* Bring IRQL back */ 677 KeLowerIrql(OldIrql); 678 _disable(); 679 680 /* Do a quick V86 exit if possible */ 681 KiExitV86Trap(TrapFrame); 682 } 683 684 /* Save trap frame */ 685 KiEnterTrap(TrapFrame); 686 687 /* Enable interrupts */ 688 Instruction = (PUCHAR)TrapFrame->Eip; 689 _enable(); 690 691 /* Check for user trap */ 692 if (KiUserTrap(TrapFrame)) 693 { 694 /* FIXME: Use SEH */ 695 696 /* Scan next 4 opcodes */ 697 for (i = 0; i < 4; i++) 698 { 699 /* Check for LOCK instruction */ 700 if (Instruction[i] == 0xF0) 701 { 702 /* Send invalid lock sequence exception */ 703 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE, 704 TrapFrame->Eip, 705 TrapFrame); 706 } 707 } 708 709 /* FIXME: SEH ends here */ 710 } 711 712 /* Kernel-mode or user-mode fault (but not LOCK) */ 713 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 714 TrapFrame->Eip, 715 TrapFrame); 716 717 } 718 719 DECLSPEC_NORETURN 720 VOID 721 FASTCALL 722 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame) 723 { 724 PKTHREAD Thread, NpxThread; 725 PFX_SAVE_AREA SaveArea, NpxSaveArea; 726 ULONG Cr0; 727 728 /* Save trap frame */ 729 KiEnterTrap(TrapFrame); 730 731 /* Try to handle NPX delay load */ 732 for (;;) 733 { 734 /* Get the current thread */ 735 Thread = KeGetCurrentThread(); 736 737 /* Get the NPX frame */ 738 SaveArea = KiGetThreadNpxArea(Thread); 739 740 /* Check if emulation is enabled */ 741 if (SaveArea->Cr0NpxState & CR0_EM) 742 { 743 /* Not implemented */ 744 UNIMPLEMENTED_FATAL(); 745 } 746 747 /* Save CR0 and check NPX state */ 748 Cr0 = __readcr0(); 749 if (Thread->NpxState != NPX_STATE_LOADED) 750 { 751 /* Update CR0 */ 752 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS); 753 __writecr0(Cr0); 754 755 /* Get the NPX thread */ 756 NpxThread = KeGetCurrentPrcb()->NpxThread; 757 if (NpxThread) 758 { 759 /* Get the NPX frame */ 760 NpxSaveArea = KiGetThreadNpxArea(NpxThread); 761 762 /* Save FPU state */ 763 Ke386SaveFpuState(NpxSaveArea); 764 765 /* Update NPX state */ 766 NpxThread->NpxState = NPX_STATE_NOT_LOADED; 767 } 768 769 /* Load FPU state */ 770 Ke386LoadFpuState(SaveArea); 771 772 /* Update NPX state */ 773 Thread->NpxState = NPX_STATE_LOADED; 774 KeGetCurrentPrcb()->NpxThread = Thread; 775 776 /* Enable interrupts */ 777 _enable(); 778 779 /* Check if CR0 needs to be reloaded due to context switch */ 780 if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame); 781 782 /* Otherwise, we need to reload CR0, disable interrupts */ 783 _disable(); 784 785 /* Reload CR0 */ 786 Cr0 = __readcr0(); 787 Cr0 |= SaveArea->Cr0NpxState; 788 __writecr0(Cr0); 789 790 /* Now restore interrupts and check for TS */ 791 _enable(); 792 if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame); 793 794 /* We're still here -- clear TS and try again */ 795 __writecr0(__readcr0() &~ CR0_TS); 796 _disable(); 797 } 798 else 799 { 800 /* This is an actual fault, not a lack of FPU state */ 801 break; 802 } 803 } 804 805 /* TS should not be set */ 806 if (Cr0 & CR0_TS) 807 { 808 /* 809 * If it's incorrectly set, then maybe the state is actually still valid 810 * but we could have lost track of that due to a BIOS call. 811 * Make sure MP is still set, which should verify the theory. 812 */ 813 if (Cr0 & CR0_MP) 814 { 815 /* Indeed, the state is actually still valid, so clear TS */ 816 __writecr0(__readcr0() &~ CR0_TS); 817 KiEoiHelper(TrapFrame); 818 } 819 820 /* Otherwise, something strange is going on */ 821 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame); 822 } 823 824 /* It's not a delayed load, so process this trap as an NPX fault */ 825 KiNpxHandler(TrapFrame, Thread, SaveArea); 826 } 827 828 DECLSPEC_NORETURN 829 VOID 830 __cdecl 831 KiTrap08Handler(VOID) 832 { 833 PKTSS Tss, DfTss; 834 PKTHREAD Thread; 835 PKPROCESS Process; 836 PKGDTENTRY TssGdt; 837 838 /* For sanity's sake, make sure interrupts are disabled */ 839 _disable(); 840 841 /* Get the current TSS, thread, and process */ 842 Tss = KeGetPcr()->TSS; 843 Thread = ((PKIPCR)KeGetPcr())->PrcbData.CurrentThread; 844 Process = Thread->ApcState.Process; 845 846 /* Save data usually not present in the TSS */ 847 Tss->CR3 = Process->DirectoryTableBase[0]; 848 Tss->IoMapBase = Process->IopmOffset; 849 Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0; 850 851 /* Now get the base address of the double-fault TSS */ 852 TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_DF_TSS / sizeof(KGDTENTRY)]; 853 DfTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | 854 TssGdt->HighWord.Bytes.BaseMid << 16 | 855 TssGdt->HighWord.Bytes.BaseHi << 24); 856 857 /* 858 * Switch to it and activate it, masking off the nested flag. 859 * 860 * Note that in reality, we are already on the double-fault TSS 861 * -- we just need to update the PCR to reflect this. 862 */ 863 KeGetPcr()->TSS = DfTss; 864 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK); 865 TssGdt->HighWord.Bits.Dpl = 0; 866 TssGdt->HighWord.Bits.Pres = 1; 867 // TssGdt->HighWord.Bits.Type &= ~0x2; /* I386_ACTIVE_TSS --> I386_TSS */ 868 TssGdt->HighWord.Bits.Type = I386_TSS; // Busy bit cleared in the TSS selector. 869 870 /* Bugcheck the system */ 871 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP, 872 EXCEPTION_DOUBLE_FAULT, 873 (ULONG_PTR)Tss, 874 0, 875 0, 876 NULL); 877 } 878 879 DECLSPEC_NORETURN 880 VOID 881 FASTCALL 882 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame) 883 { 884 /* Save trap frame */ 885 KiEnterTrap(TrapFrame); 886 887 /* Enable interrupts and kill the system */ 888 _enable(); 889 KiSystemFatalException(EXCEPTION_NPX_OVERRUN, TrapFrame); 890 } 891 892 DECLSPEC_NORETURN 893 VOID 894 FASTCALL 895 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame) 896 { 897 /* Save trap frame */ 898 KiEnterTrap(TrapFrame); 899 900 /* Check for VDM trap */ 901 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 902 903 /* Kill the system */ 904 KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame); 905 } 906 907 DECLSPEC_NORETURN 908 VOID 909 FASTCALL 910 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame) 911 { 912 /* Save trap frame */ 913 KiEnterTrap(TrapFrame); 914 915 /* FIXME: Kill the system */ 916 UNIMPLEMENTED; 917 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT, TrapFrame); 918 } 919 920 DECLSPEC_NORETURN 921 VOID 922 FASTCALL 923 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame) 924 { 925 /* Save trap frame */ 926 KiEnterTrap(TrapFrame); 927 928 /* FIXME: Kill the system */ 929 UNIMPLEMENTED; 930 KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame); 931 } 932 933 /* DECLSPEC_NORETURN VOID FASTCALL KiTrap0DHandler(IN PKTRAP_FRAME); */ 934 DECLSPEC_NORETURN VOID FASTCALL KiTrap0EHandler(IN PKTRAP_FRAME); 935 936 DECLSPEC_NORETURN 937 VOID 938 FASTCALL 939 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) 940 { 941 ULONG i, j, Iopl; 942 BOOLEAN Privileged = FALSE; 943 PUCHAR Instructions; 944 UCHAR Instruction = 0; 945 KIRQL OldIrql; 946 947 /* Check for V86 GPF */ 948 if (__builtin_expect(KiV86Trap(TrapFrame), 1)) 949 { 950 /* Enter V86 trap */ 951 KiEnterV86Trap(TrapFrame); 952 953 /* Must be a VDM process */ 954 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) 955 { 956 /* Enable interrupts */ 957 _enable(); 958 959 /* Setup illegal instruction fault */ 960 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 961 TrapFrame->Eip, 962 TrapFrame); 963 } 964 965 /* Go to APC level */ 966 KeRaiseIrql(APC_LEVEL, &OldIrql); 967 _enable(); 968 969 /* Handle the V86 opcode */ 970 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0)) 971 { 972 /* Should only happen in VDM mode */ 973 UNIMPLEMENTED_FATAL(); 974 } 975 976 /* Bring IRQL back */ 977 KeLowerIrql(OldIrql); 978 _disable(); 979 980 /* Do a quick V86 exit if possible */ 981 KiExitV86Trap(TrapFrame); 982 } 983 984 /* Save trap frame */ 985 KiEnterTrap(TrapFrame); 986 987 /* Check for user-mode GPF */ 988 if (KiUserTrap(TrapFrame)) 989 { 990 /* Should not be VDM */ 991 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 992 993 /* Enable interrupts and check error code */ 994 _enable(); 995 if (!TrapFrame->ErrCode) 996 { 997 /* FIXME: Use SEH */ 998 Instructions = (PUCHAR)TrapFrame->Eip; 999 1000 /* Scan next 15 bytes */ 1001 for (i = 0; i < 15; i++) 1002 { 1003 /* Skip prefix instructions */ 1004 for (j = 0; j < sizeof(KiTrapPrefixTable); j++) 1005 { 1006 /* Is this a prefix instruction? */ 1007 if (Instructions[i] == KiTrapPrefixTable[j]) 1008 { 1009 /* Stop looking */ 1010 break; 1011 } 1012 } 1013 1014 /* Is this NOT any prefix instruction? */ 1015 if (j == sizeof(KiTrapPrefixTable)) 1016 { 1017 /* We can go ahead and handle the fault now */ 1018 Instruction = Instructions[i]; 1019 break; 1020 } 1021 } 1022 1023 /* If all we found was prefixes, then this instruction is too long */ 1024 if (i == 15) 1025 { 1026 /* Setup illegal instruction fault */ 1027 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 1028 TrapFrame->Eip, 1029 TrapFrame); 1030 } 1031 1032 /* Check for privileged instructions */ 1033 DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n", 1034 i, 1035 Instructions[i], 1036 Instructions[i + 1], 1037 Instructions[i + 2], 1038 Instructions[i + 3]); 1039 if (Instruction == 0xF4) // HLT 1040 { 1041 /* HLT is privileged */ 1042 Privileged = TRUE; 1043 } 1044 else if (Instruction == 0x0F) 1045 { 1046 /* Test if it's any of the privileged two-byte opcodes */ 1047 if (((Instructions[i + 1] == 0x00) && // LLDT or LTR 1048 (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT 1049 (Instructions[i + 2] == 0x18))) || // LTR 1050 ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW 1051 (((Instructions[i + 2] & 0x38) == 0x10) || // LGDT 1052 (Instructions[i + 2] == 0x18) || // LIDT 1053 (Instructions[i + 2] == 0x30))) || // LMSW 1054 (Instructions[i + 1] == 0x08) || // INVD 1055 (Instructions[i + 1] == 0x09) || // WBINVD 1056 (Instructions[i + 1] == 0x35) || // SYSEXIT 1057 (Instructions[i + 1] == 0x21) || // MOV DR, XXX 1058 (Instructions[i + 1] == 0x06) || // CLTS 1059 (Instructions[i + 1] == 0x20) || // MOV CR, XXX 1060 (Instructions[i + 1] == 0x22) || // MOV XXX, CR 1061 (Instructions[i + 1] == 0x23) || // MOV YYY, DR 1062 (Instructions[i + 1] == 0x30) || // WRMSR 1063 (Instructions[i + 1] == 0x33)) // RDPMC 1064 // INVLPG, INVLPGA, SYSRET 1065 { 1066 /* These are all privileged */ 1067 Privileged = TRUE; 1068 } 1069 } 1070 else 1071 { 1072 /* Get the IOPL and compare with the RPL mask */ 1073 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12; 1074 if ((TrapFrame->SegCs & RPL_MASK) > Iopl) 1075 { 1076 /* I/O privilege error -- check for known instructions */ 1077 if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI 1078 { 1079 /* These are privileged */ 1080 Privileged = TRUE; 1081 } 1082 else 1083 { 1084 /* Last hope: an IN/OUT instruction */ 1085 for (j = 0; j < sizeof(KiTrapIoTable); j++) 1086 { 1087 /* Is this an I/O instruction? */ 1088 if (Instruction == KiTrapIoTable[j]) 1089 { 1090 /* Then it's privileged */ 1091 Privileged = TRUE; 1092 break; 1093 } 1094 } 1095 } 1096 } 1097 } 1098 1099 /* So now... was the instruction privileged or not? */ 1100 if (Privileged) 1101 { 1102 /* Whew! We have a privileged instruction, so dispatch the fault */ 1103 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION, 1104 TrapFrame->Eip, 1105 TrapFrame); 1106 } 1107 } 1108 1109 /* If we got here, send an access violation */ 1110 KiDispatchException2Args(STATUS_ACCESS_VIOLATION, 1111 TrapFrame->Eip, 1112 0, 1113 0xFFFFFFFF, 1114 TrapFrame); 1115 } 1116 1117 /* 1118 * Check for a fault during checking of the user instruction. 1119 * 1120 * Note that the SEH handler will catch invalid EIP, but we could be dealing 1121 * with an invalid CS, which will generate another GPF instead. 1122 * 1123 */ 1124 if ((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler && 1125 (PVOID)TrapFrame->Eip < (PVOID)KiTrap0EHandler) 1126 { 1127 /* Not implemented */ 1128 UNIMPLEMENTED_FATAL(); 1129 } 1130 1131 /* 1132 * NOTE: The ASM trap exit code would restore segment registers by doing 1133 * a POP <SEG>, which could cause an invalid segment if someone had messed 1134 * with the segment values. 1135 * 1136 * Another case is a bogus SS, which would hit a GPF when doing the iret. 1137 * This could only be done through a buggy or malicious driver, or perhaps 1138 * the kernel debugger. 1139 * 1140 * The kernel normally restores the "true" segment if this happens. 1141 * 1142 * However, since we're restoring in C, not ASM, we can't detect 1143 * POP <SEG> since the actual instructions will be different. 1144 * 1145 * A better technique would be to check the EIP and somehow edit the 1146 * trap frame before restarting the instruction -- but we would need to 1147 * know the extract instruction that was used first. 1148 * 1149 * We could force a special instrinsic to use stack instructions, or write 1150 * a simple instruction length checker. 1151 * 1152 * Nevertheless, this is a lot of work for the purpose of avoiding a crash 1153 * when the user is purposedly trying to create one from kernel-mode, so 1154 * we should probably table this for now since it's not a "real" issue. 1155 */ 1156 1157 /* 1158 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call) 1159 * which will cause a GPF since the trap frame is a total mess (on purpose) 1160 * as built in KiEnterV86Mode. 1161 * 1162 * The idea is to scan for IRET, scan for the known EIP adress, validate CS 1163 * and then manually issue a jump to the V8086 return EIP. 1164 */ 1165 Instructions = (PUCHAR)TrapFrame->Eip; 1166 if (Instructions[0] == 0xCF) 1167 { 1168 /* 1169 * Some evil shit is going on here -- this is not the SS:ESP you're 1170 * looking for! Instead, this is actually CS:EIP you're looking at! 1171 * Why? Because part of the trap frame actually corresponds to the IRET 1172 * stack during the trap exit! 1173 */ 1174 if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) && 1175 (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK))) 1176 { 1177 /* Exit the V86 trap! */ 1178 Ki386BiosCallReturnAddress(TrapFrame); 1179 } 1180 else 1181 { 1182 /* Otherwise, this is another kind of IRET fault */ 1183 UNIMPLEMENTED_FATAL(); 1184 } 1185 } 1186 1187 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */ 1188 if ((Instructions[0] == 0xF) && // 2-byte opcode 1189 ((Instructions[1] == 0x32) || // RDMSR 1190 (Instructions[1] == 0x30))) // WRMSR 1191 { 1192 /* Unknown CPU MSR, so raise an access violation */ 1193 KiDispatchException0Args(STATUS_ACCESS_VIOLATION, 1194 TrapFrame->Eip, 1195 TrapFrame); 1196 } 1197 1198 /* Check for lazy segment load */ 1199 if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK)) 1200 { 1201 /* Fix it */ 1202 TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK); 1203 } 1204 else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK)) 1205 { 1206 /* Fix it */ 1207 TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK); 1208 } 1209 else 1210 { 1211 /* Whatever it is, we can't handle it */ 1212 KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame); 1213 } 1214 1215 /* Return to where we came from */ 1216 KiTrapReturn(TrapFrame); 1217 } 1218 1219 BOOLEAN 1220 FASTCALL 1221 KiCheckForSListFault(PKTRAP_FRAME TrapFrame) 1222 { 1223 /* Explanation: An S-List fault can occur due to a race condition between 2 1224 threads simultaneously trying to pop an element from the S-List. After 1225 thread 1 has read the pointer to the top element on the S-List it is 1226 preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List, 1227 removing the top element and freeing it's memory. After that thread 1 1228 resumes and tries to read the address of the Next pointer from the top 1229 element, which it assumes will be the next top element. 1230 But since that memory has been freed, we get a page fault. To handle this 1231 race condition, we let thread 1 repeat the operation. 1232 We do NOT invoke the page fault handler in this case, since we do not 1233 want to trigger any side effects, like paging or a guard page fault. 1234 1235 Sequence of operations: 1236 1237 Thread 1 : mov eax, [ebp] <= eax now points to the first element 1238 Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence 1239 *** preempted *** 1240 Thread 2 : calls InterlockedPopEntrySlist, changing the top element 1241 Thread 2 : frees the memory of the element that was popped 1242 *** preempted *** 1243 Thread 1 : checks if eax is NULL 1244 Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults 1245 1246 To be sure that we are dealing with exactly the case described above, we 1247 check whether the ListHeader has changed. If Thread 2 only popped one 1248 entry, the Next field in the S-List-header has changed. 1249 If after thread 1 has faulted, thread 2 allocates a new element, by 1250 chance getting the same address as the previously freed element and 1251 pushes it on the list again, we will see the same top element, but the 1252 Sequence member of the S-List header has changed. Therefore we check 1253 both fields to make sure we catch any concurrent modification of the 1254 S-List-header. 1255 */ 1256 if ((TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault) || 1257 (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault)) 1258 { 1259 ULARGE_INTEGER SListHeader; 1260 PVOID ResumeAddress; 1261 1262 /* Sanity check that the assembly is correct: 1263 This must be mov ebx, [eax] 1264 Followed by cmpxchg8b [ebp] */ 1265 ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) && 1266 (((UCHAR*)TrapFrame->Eip)[1] == 0x18) && 1267 (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) && 1268 (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) && 1269 (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) && 1270 (((UCHAR*)TrapFrame->Eip)[5] == 0x00)); 1271 1272 /* Check if this is a user fault */ 1273 if (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault) 1274 { 1275 /* EBP points to the S-List-header. Copy it inside SEH, to protect 1276 against a bogus pointer from user mode */ 1277 _SEH2_TRY 1278 { 1279 ProbeForRead((PVOID)TrapFrame->Ebp, 1280 sizeof(ULARGE_INTEGER), 1281 TYPE_ALIGNMENT(SLIST_HEADER)); 1282 SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp; 1283 } 1284 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1285 { 1286 /* The S-List pointer is not valid! */ 1287 return FALSE; 1288 } 1289 _SEH2_END; 1290 ResumeAddress = KeUserPopEntrySListResume; 1291 } 1292 else 1293 { 1294 SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp; 1295 ResumeAddress = ExpInterlockedPopEntrySListResume; 1296 } 1297 1298 /* Check if either the Next pointer or the Sequence member in the 1299 S-List-header has changed. If any of these has changed, we restart 1300 the operation. Otherwise we only have a bogus pointer and let the 1301 page fault handler deal with it. */ 1302 if ((SListHeader.LowPart != TrapFrame->Eax) || 1303 (SListHeader.HighPart != TrapFrame->Edx)) 1304 { 1305 DPRINT1("*** Got an S-List-Fault ***\n"); 1306 KeGetCurrentThread()->SListFaultCount++; 1307 1308 /* Restart the operation */ 1309 TrapFrame->Eip = (ULONG_PTR)ResumeAddress; 1310 1311 return TRUE; 1312 } 1313 } 1314 1315 return FALSE; 1316 } 1317 1318 DECLSPEC_NORETURN 1319 VOID 1320 FASTCALL 1321 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame) 1322 { 1323 PKTHREAD Thread; 1324 BOOLEAN StoreInstruction; 1325 ULONG_PTR Cr2; 1326 NTSTATUS Status; 1327 1328 /* Save trap frame */ 1329 KiEnterTrap(TrapFrame); 1330 1331 /* Check if this is the base frame */ 1332 Thread = KeGetCurrentThread(); 1333 if (KeGetTrapFrame(Thread) != TrapFrame) 1334 { 1335 /* It isn't, check if this is a second nested frame */ 1336 if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <= 1337 FIELD_OFFSET(KTRAP_FRAME, EFlags)) 1338 { 1339 /* The stack is somewhere in between frames, we need to fix it */ 1340 UNIMPLEMENTED_FATAL(); 1341 } 1342 } 1343 1344 /* Save CR2 */ 1345 Cr2 = __readcr2(); 1346 1347 /* Enable interrupts */ 1348 _enable(); 1349 1350 /* Interpret the error code */ 1351 StoreInstruction = (TrapFrame->ErrCode & 2) != 0; 1352 1353 /* Check if we came in with interrupts disabled */ 1354 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK)) 1355 { 1356 /* This is completely illegal, bugcheck the system */ 1357 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL, 1358 Cr2, 1359 (ULONG_PTR)-1, 1360 TrapFrame->ErrCode, 1361 TrapFrame->Eip, 1362 TrapFrame); 1363 } 1364 1365 /* Check for S-List fault */ 1366 if (KiCheckForSListFault(TrapFrame)) 1367 { 1368 /* Continue execution */ 1369 KiEoiHelper(TrapFrame); 1370 } 1371 1372 /* Call the access fault handler */ 1373 Status = MmAccessFault(TrapFrame->ErrCode, 1374 (PVOID)Cr2, 1375 KiUserTrap(TrapFrame), 1376 TrapFrame); 1377 if (NT_SUCCESS(Status)) 1378 { 1379 #ifdef _WINKD_ 1380 /* Check whether the kernel debugger has owed breakpoints to be inserted */ 1381 KdSetOwedBreakpoints(); 1382 #endif 1383 /* We succeeded, return */ 1384 KiEoiHelper(TrapFrame); 1385 } 1386 1387 /* Check for syscall fault */ 1388 #if 0 1389 if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) || 1390 (TrapFrame->Eip == (ULONG_PTR)ReadBatch)) 1391 { 1392 /* Not yet implemented */ 1393 UNIMPLEMENTED_FATAL(); 1394 } 1395 #endif 1396 1397 /* Check for VDM trap */ 1398 if (KiVdmTrap(TrapFrame)) 1399 { 1400 DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n", 1401 TrapFrame->SegCs, TrapFrame->Eip, Cr2); 1402 if (VdmDispatchPageFault(TrapFrame)) 1403 { 1404 /* Return and end VDM execution */ 1405 DPRINT1("VDM page fault with status 0x%lx resolved\n", Status); 1406 KiEoiHelper(TrapFrame); 1407 } 1408 DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status); 1409 } 1410 1411 /* Either kernel or user trap (non VDM) so dispatch exception */ 1412 if (Status == STATUS_ACCESS_VIOLATION) 1413 { 1414 /* This status code is repurposed so we can recognize it later */ 1415 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION, 1416 TrapFrame->Eip, 1417 StoreInstruction, 1418 Cr2, 1419 TrapFrame); 1420 } 1421 else if ((Status == STATUS_GUARD_PAGE_VIOLATION) || 1422 (Status == STATUS_STACK_OVERFLOW)) 1423 { 1424 /* These faults only have two parameters */ 1425 KiDispatchException2Args(Status, 1426 TrapFrame->Eip, 1427 StoreInstruction, 1428 Cr2, 1429 TrapFrame); 1430 } 1431 1432 /* Only other choice is an in-page error, with 3 parameters */ 1433 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR, 1434 0, 1435 TrapFrame->Eip, 1436 3, 1437 StoreInstruction, 1438 Cr2, 1439 Status, 1440 TrapFrame); 1441 } 1442 1443 DECLSPEC_NORETURN 1444 VOID 1445 FASTCALL 1446 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame) 1447 { 1448 /* Save trap frame */ 1449 KiEnterTrap(TrapFrame); 1450 1451 /* FIXME: Kill the system */ 1452 UNIMPLEMENTED; 1453 KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame); 1454 } 1455 1456 DECLSPEC_NORETURN 1457 VOID 1458 FASTCALL 1459 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame) 1460 { 1461 PKTHREAD Thread; 1462 PFX_SAVE_AREA SaveArea; 1463 1464 /* Save trap frame */ 1465 KiEnterTrap(TrapFrame); 1466 1467 /* Check if this is the NPX thrad */ 1468 Thread = KeGetCurrentThread(); 1469 SaveArea = KiGetThreadNpxArea(Thread); 1470 if (Thread != KeGetCurrentPrcb()->NpxThread) 1471 { 1472 /* It isn't, enable interrupts and set delayed error */ 1473 _enable(); 1474 SaveArea->Cr0NpxState |= CR0_TS; 1475 1476 /* End trap */ 1477 KiEoiHelper(TrapFrame); 1478 } 1479 1480 /* Otherwise, proceed with NPX fault handling */ 1481 KiNpxHandler(TrapFrame, Thread, SaveArea); 1482 } 1483 1484 DECLSPEC_NORETURN 1485 VOID 1486 FASTCALL 1487 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame) 1488 { 1489 /* Save trap frame */ 1490 KiEnterTrap(TrapFrame); 1491 1492 /* Enable interrupts and kill the system */ 1493 _enable(); 1494 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame); 1495 } 1496 1497 DECLSPEC_NORETURN 1498 VOID 1499 FASTCALL 1500 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame) 1501 { 1502 PKTHREAD Thread; 1503 PFX_SAVE_AREA SaveArea; 1504 ULONG Cr0, MxCsrMask, Error; 1505 1506 /* Save trap frame */ 1507 KiEnterTrap(TrapFrame); 1508 1509 /* Check if this is the NPX thrad */ 1510 Thread = KeGetCurrentThread(); 1511 if (Thread != KeGetCurrentPrcb()->NpxThread) 1512 { 1513 /* It isn't, kill the system */ 1514 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame); 1515 } 1516 1517 /* Get the NPX frame */ 1518 SaveArea = KiGetThreadNpxArea(Thread); 1519 1520 /* Check for VDM trap */ 1521 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 1522 1523 /* Check for user trap */ 1524 if (!KiUserTrap(TrapFrame)) 1525 { 1526 /* Kernel should not fault on XMMI */ 1527 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame); 1528 } 1529 1530 /* Update CR0 */ 1531 Cr0 = __readcr0(); 1532 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS); 1533 __writecr0(Cr0); 1534 1535 /* Save FPU state */ 1536 Ke386SaveFpuState(SaveArea); 1537 1538 /* Mark CR0 state dirty */ 1539 Cr0 |= NPX_STATE_NOT_LOADED; 1540 Cr0 |= SaveArea->Cr0NpxState; 1541 __writecr0(Cr0); 1542 1543 /* Update NPX state */ 1544 Thread->NpxState = NPX_STATE_NOT_LOADED; 1545 KeGetCurrentPrcb()->NpxThread = NULL; 1546 1547 /* Clear the TS bit and re-enable interrupts */ 1548 SaveArea->Cr0NpxState &= ~CR0_TS; 1549 _enable(); 1550 1551 /* Now look at MxCsr to get the mask of errors we should care about */ 1552 MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7); 1553 1554 /* Get legal exceptions that software should handle */ 1555 Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION | 1556 FSW_DENORMAL | 1557 FSW_ZERO_DIVIDE | 1558 FSW_OVERFLOW | 1559 FSW_UNDERFLOW | 1560 FSW_PRECISION); 1561 Error &= MxCsrMask; 1562 1563 /* Now handle any of those legal errors */ 1564 if (Error & (FSW_INVALID_OPERATION | 1565 FSW_DENORMAL | 1566 FSW_ZERO_DIVIDE | 1567 FSW_OVERFLOW | 1568 FSW_UNDERFLOW | 1569 FSW_PRECISION)) 1570 { 1571 /* By issuing an exception */ 1572 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS, 1573 TrapFrame->Eip, 1574 0, 1575 TrapFrame); 1576 } 1577 1578 /* Unknown XMMI fault */ 1579 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame); 1580 } 1581 1582 /* SOFTWARE SERVICES **********************************************************/ 1583 1584 VOID 1585 FASTCALL 1586 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame) 1587 { 1588 /* Save trap frame */ 1589 KiEnterTrap(TrapFrame); 1590 1591 /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */ 1592 TrapFrame->Eip -= 2; 1593 1594 /* Check if this is a user trap */ 1595 if (KiUserTrap(TrapFrame)) 1596 { 1597 /* Dispatch exception to user mode */ 1598 KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN, 1599 EXCEPTION_NONCONTINUABLE, 1600 TrapFrame->Eip, 1601 1, 1602 TrapFrame->Ecx, 1603 0, 1604 0, 1605 TrapFrame); 1606 } 1607 else 1608 { 1609 EXCEPTION_RECORD ExceptionRecord; 1610 1611 /* Bugcheck the system */ 1612 ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; 1613 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 1614 ExceptionRecord.ExceptionRecord = NULL; 1615 ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Eip; 1616 ExceptionRecord.NumberParameters = 1; 1617 ExceptionRecord.ExceptionInformation[0] = TrapFrame->Ecx; 1618 1619 KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE, 1620 TrapFrame->Ecx, 1621 (ULONG_PTR)TrapFrame, 1622 (ULONG_PTR)&ExceptionRecord, 1623 0, 1624 TrapFrame); 1625 } 1626 } 1627 1628 VOID 1629 FASTCALL 1630 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame) 1631 { 1632 /* Save trap frame */ 1633 KiEnterTrap(TrapFrame); 1634 1635 /* 1636 * Just fail the request 1637 */ 1638 DbgPrint("INT 0x2A attempted, returning 0 tick count\n"); 1639 TrapFrame->Eax = 0; 1640 1641 /* Exit the trap */ 1642 KiEoiHelper(TrapFrame); 1643 } 1644 1645 VOID 1646 FASTCALL 1647 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame) 1648 { 1649 PKTHREAD Thread; 1650 NTSTATUS Status; 1651 1652 /* Save the SEH chain, NtCallbackReturn will restore this */ 1653 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; 1654 1655 /* Set thread fields */ 1656 Thread = KeGetCurrentThread(); 1657 Thread->TrapFrame = TrapFrame; 1658 Thread->PreviousMode = KiUserTrap(TrapFrame); 1659 ASSERT(Thread->PreviousMode != KernelMode); 1660 1661 /* Pass the register parameters to NtCallbackReturn. 1662 Result pointer is in ecx, result length in edx, status in eax */ 1663 Status = NtCallbackReturn((PVOID)TrapFrame->Ecx, 1664 TrapFrame->Edx, 1665 TrapFrame->Eax); 1666 1667 /* If we got here, something went wrong. Return an error to the caller */ 1668 KiServiceExit(TrapFrame, Status); 1669 } 1670 1671 DECLSPEC_NORETURN 1672 VOID 1673 FASTCALL 1674 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame) 1675 { 1676 /* Save trap frame */ 1677 KiEnterTrap(TrapFrame); 1678 1679 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */ 1680 TrapFrame->Eip -= 2; 1681 1682 /* Dispatch the exception */ 1683 KiDispatchException0Args(STATUS_ASSERTION_FAILURE, 1684 TrapFrame->Eip, 1685 TrapFrame); 1686 } 1687 1688 DECLSPEC_NORETURN 1689 VOID 1690 FASTCALL 1691 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame) 1692 { 1693 /* Save trap frame */ 1694 KiEnterTrap(TrapFrame); 1695 1696 /* Increment EIP to skip the INT3 instruction */ 1697 TrapFrame->Eip++; 1698 1699 /* Continue with the common handler */ 1700 KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx); 1701 } 1702 1703 1704 FORCEINLINE 1705 VOID 1706 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments) 1707 { 1708 #if DBG && !defined(_WINKD_) 1709 if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook) 1710 KeWin32PreServiceHook(SystemCallNumber, Arguments); 1711 #endif 1712 } 1713 1714 FORCEINLINE 1715 ULONG_PTR 1716 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result) 1717 { 1718 #if DBG && !defined(_WINKD_) 1719 if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook) 1720 return KeWin32PostServiceHook(SystemCallNumber, Result); 1721 #endif 1722 return Result; 1723 } 1724 1725 DECLSPEC_NORETURN 1726 VOID 1727 FASTCALL 1728 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame, 1729 IN PVOID Arguments) 1730 { 1731 PKTHREAD Thread; 1732 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 1733 ULONG Id, Offset, StackBytes; 1734 NTSTATUS Status; 1735 PVOID Handler; 1736 ULONG SystemCallNumber = TrapFrame->Eax; 1737 1738 /* Get the current thread */ 1739 Thread = KeGetCurrentThread(); 1740 1741 /* Set debug header */ 1742 KiFillTrapFrameDebug(TrapFrame); 1743 1744 /* Chain trap frames */ 1745 TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame; 1746 1747 /* No error code */ 1748 TrapFrame->ErrCode = 0; 1749 1750 /* Save previous mode */ 1751 TrapFrame->PreviousPreviousMode = Thread->PreviousMode; 1752 1753 /* Save the SEH chain and terminate it for now */ 1754 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; 1755 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 1756 1757 /* Default to debugging disabled */ 1758 TrapFrame->Dr7 = 0; 1759 1760 /* Check if the frame was from user mode */ 1761 if (KiUserTrap(TrapFrame)) 1762 { 1763 /* Check for active debugging */ 1764 if (KeGetCurrentThread()->Header.DebugActive & 0xFF) 1765 { 1766 /* Handle debug registers */ 1767 KiHandleDebugRegistersOnTrapEntry(TrapFrame); 1768 } 1769 } 1770 1771 /* Set thread fields */ 1772 Thread->TrapFrame = TrapFrame; 1773 Thread->PreviousMode = KiUserTrap(TrapFrame); 1774 1775 /* Enable interrupts */ 1776 _enable(); 1777 1778 /* Decode the system call number */ 1779 Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 1780 Id = SystemCallNumber & SERVICE_NUMBER_MASK; 1781 1782 /* Get descriptor table */ 1783 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 1784 1785 /* Validate the system call number */ 1786 if (__builtin_expect(Id >= DescriptorTable->Limit, 0)) 1787 { 1788 /* Check if this is a GUI call */ 1789 if (!(Offset & SERVICE_TABLE_TEST)) 1790 { 1791 /* Fail the call */ 1792 Status = STATUS_INVALID_SYSTEM_SERVICE; 1793 goto ExitCall; 1794 } 1795 1796 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */ 1797 Status = KiConvertToGuiThread(); 1798 1799 /* Reload trap frame and descriptor table pointer from new stack */ 1800 TrapFrame = *(volatile PVOID*)&Thread->TrapFrame; 1801 DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset); 1802 1803 if (!NT_SUCCESS(Status)) 1804 { 1805 /* Set the last error and fail */ 1806 goto ExitCall; 1807 } 1808 1809 /* Validate the system call number again */ 1810 if (Id >= DescriptorTable->Limit) 1811 { 1812 /* Fail the call */ 1813 Status = STATUS_INVALID_SYSTEM_SERVICE; 1814 goto ExitCall; 1815 } 1816 } 1817 1818 /* Check if this is a GUI call */ 1819 if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0)) 1820 { 1821 /* Get the batch count and flush if necessary */ 1822 if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch(); 1823 } 1824 1825 /* Increase system call count */ 1826 KeGetCurrentPrcb()->KeSystemCalls++; 1827 1828 /* FIXME: Increase individual counts on debug systems */ 1829 //KiIncreaseSystemCallCount(DescriptorTable, Id); 1830 1831 /* Get stack bytes */ 1832 StackBytes = DescriptorTable->Number[Id]; 1833 1834 /* Probe caller stack */ 1835 if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0)) 1836 { 1837 /* Access violation */ 1838 UNIMPLEMENTED_FATAL(); 1839 } 1840 1841 /* Call pre-service debug hook */ 1842 KiDbgPreServiceHook(SystemCallNumber, Arguments); 1843 1844 /* Get the handler and make the system call */ 1845 Handler = (PVOID)DescriptorTable->Base[Id]; 1846 Status = KiSystemCallTrampoline(Handler, Arguments, StackBytes); 1847 1848 /* Call post-service debug hook */ 1849 Status = KiDbgPostServiceHook(SystemCallNumber, Status); 1850 1851 /* Make sure we're exiting correctly */ 1852 KiExitSystemCallDebugChecks(Id, TrapFrame); 1853 1854 /* Restore the old trap frame */ 1855 ExitCall: 1856 Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx; 1857 1858 /* Exit from system call */ 1859 KiServiceExit(TrapFrame, Status); 1860 } 1861 1862 VOID 1863 FASTCALL 1864 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame) 1865 { 1866 UNIMPLEMENTED; 1867 } 1868 1869 /* 1870 * @implemented 1871 */ 1872 VOID 1873 NTAPI 1874 Kei386EoiHelper(VOID) 1875 { 1876 /* We should never see this call happening */ 1877 KeBugCheck(MISMATCHED_HAL); 1878 } 1879 1880 /* EOF */ 1881