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 DECLSPEC_NORETURN 459 VOID 460 __cdecl 461 KiTrap02(VOID) 462 { 463 PKTSS Tss, NmiTss; 464 PKTHREAD Thread; 465 PKPROCESS Process; 466 PKGDTENTRY TssGdt; 467 KTRAP_FRAME TrapFrame; 468 KIRQL OldIrql; 469 470 // 471 // In some sort of strange recursion case, we might end up here with the IF 472 // flag incorrectly on the interrupt frame -- during a normal NMI this would 473 // normally already be set. 474 // 475 // For sanity's sake, make sure interrupts are disabled for sure. 476 // NMIs will already be since the CPU does it for us. 477 // 478 _disable(); 479 480 // 481 // Get the current TSS, thread, and process 482 // 483 Tss = PCR->TSS; 484 Thread = ((PKIPCR)PCR)->PrcbData.CurrentThread; 485 Process = Thread->ApcState.Process; 486 487 // 488 // Save data usually not in the TSS 489 // 490 Tss->CR3 = Process->DirectoryTableBase[0]; 491 Tss->IoMapBase = Process->IopmOffset; 492 Tss->LDT = Process->LdtDescriptor.LimitLow ? KGDT_LDT : 0; 493 494 // 495 // Now get the base address of the NMI TSS 496 // 497 TssGdt = &((PKIPCR)KeGetPcr())->GDT[KGDT_NMI_TSS / sizeof(KGDTENTRY)]; 498 NmiTss = (PKTSS)(ULONG_PTR)(TssGdt->BaseLow | 499 TssGdt->HighWord.Bytes.BaseMid << 16 | 500 TssGdt->HighWord.Bytes.BaseHi << 24); 501 502 // 503 // Switch to it and activate it, masking off the nested flag 504 // 505 // Note that in reality, we are already on the NMI tss -- we just need to 506 // update the PCR to reflect this 507 // 508 PCR->TSS = NmiTss; 509 __writeeflags(__readeflags() &~ EFLAGS_NESTED_TASK); 510 TssGdt->HighWord.Bits.Dpl = 0; 511 TssGdt->HighWord.Bits.Pres = 1; 512 TssGdt->HighWord.Bits.Type = I386_TSS; 513 514 // 515 // Now build the trap frame based on the original TSS 516 // 517 // The CPU does a hardware "Context switch" / task switch of sorts and so it 518 // takes care of saving our context in the normal TSS. 519 // 520 // We just have to go get the values... 521 // 522 RtlZeroMemory(&TrapFrame, sizeof(KTRAP_FRAME)); 523 TrapFrame.HardwareSegSs = Tss->Ss0; 524 TrapFrame.HardwareEsp = Tss->Esp0; 525 TrapFrame.EFlags = Tss->EFlags; 526 TrapFrame.SegCs = Tss->Cs; 527 TrapFrame.Eip = Tss->Eip; 528 TrapFrame.Ebp = Tss->Ebp; 529 TrapFrame.Ebx = Tss->Ebx; 530 TrapFrame.Esi = Tss->Esi; 531 TrapFrame.Edi = Tss->Edi; 532 TrapFrame.SegFs = Tss->Fs; 533 TrapFrame.ExceptionList = PCR->NtTib.ExceptionList; 534 TrapFrame.PreviousPreviousMode = (ULONG)-1; 535 TrapFrame.Eax = Tss->Eax; 536 TrapFrame.Ecx = Tss->Ecx; 537 TrapFrame.Edx = Tss->Edx; 538 TrapFrame.SegDs = Tss->Ds; 539 TrapFrame.SegEs = Tss->Es; 540 TrapFrame.SegGs = Tss->Gs; 541 TrapFrame.DbgEip = Tss->Eip; 542 TrapFrame.DbgEbp = Tss->Ebp; 543 544 // 545 // Store the trap frame in the KPRCB 546 // 547 KiSaveProcessorState(&TrapFrame, NULL); 548 549 // 550 // Call any registered NMI handlers and see if they handled it or not 551 // 552 if (!KiHandleNmi()) 553 { 554 // 555 // They did not, so call the platform HAL routine to bugcheck the system 556 // 557 // Make sure the HAL believes it's running at HIGH IRQL... we can't use 558 // the normal APIs here as playing with the IRQL could change the system 559 // state 560 // 561 OldIrql = PCR->Irql; 562 PCR->Irql = HIGH_LEVEL; 563 HalHandleNMI(NULL); 564 PCR->Irql = OldIrql; 565 } 566 567 // 568 // Although the CPU disabled NMIs, we just did a BIOS Call, which could've 569 // totally changed things. 570 // 571 // We have to make sure we're still in our original NMI -- a nested NMI 572 // will point back to the NMI TSS, and in that case we're hosed. 573 // 574 if (PCR->TSS->Backlink != KGDT_NMI_TSS) 575 { 576 // 577 // Restore original TSS 578 // 579 PCR->TSS = Tss; 580 581 // 582 // Set it back to busy 583 // 584 TssGdt->HighWord.Bits.Dpl = 0; 585 TssGdt->HighWord.Bits.Pres = 1; 586 TssGdt->HighWord.Bits.Type = I386_ACTIVE_TSS; 587 588 // 589 // Restore nested flag 590 // 591 __writeeflags(__readeflags() | EFLAGS_NESTED_TASK); 592 593 // 594 // Handled, return from interrupt 595 // 596 KiIret(); 597 } 598 599 // 600 // Unhandled: crash the system 601 // 602 KiSystemFatalException(EXCEPTION_NMI, NULL); 603 } 604 605 DECLSPEC_NORETURN 606 VOID 607 FASTCALL 608 KiTrap03Handler(IN PKTRAP_FRAME TrapFrame) 609 { 610 /* Save trap frame */ 611 KiEnterTrap(TrapFrame); 612 613 /* Continue with the common handler */ 614 KiDebugHandler(TrapFrame, BREAKPOINT_BREAK, 0, 0); 615 } 616 617 DECLSPEC_NORETURN 618 VOID 619 FASTCALL 620 KiTrap04Handler(IN PKTRAP_FRAME TrapFrame) 621 { 622 /* Save trap frame */ 623 KiEnterTrap(TrapFrame); 624 625 /* Check for VDM trap */ 626 ASSERT((KiVdmTrap(TrapFrame)) == FALSE); 627 628 /* Enable interrupts */ 629 _enable(); 630 631 /* Dispatch the exception */ 632 KiDispatchException0Args(STATUS_INTEGER_OVERFLOW, 633 TrapFrame->Eip - 1, 634 TrapFrame); 635 } 636 637 DECLSPEC_NORETURN 638 VOID 639 FASTCALL 640 KiTrap05Handler(IN PKTRAP_FRAME TrapFrame) 641 { 642 /* Save trap frame */ 643 KiEnterTrap(TrapFrame); 644 645 /* Check for VDM trap */ 646 ASSERT((KiVdmTrap(TrapFrame)) == FALSE); 647 648 /* Check for kernel-mode fault */ 649 if (!KiUserTrap(TrapFrame)) KiSystemFatalException(EXCEPTION_BOUND_CHECK, TrapFrame); 650 651 /* Enable interrupts */ 652 _enable(); 653 654 /* Dispatch the exception */ 655 KiDispatchException0Args(STATUS_ARRAY_BOUNDS_EXCEEDED, 656 TrapFrame->Eip, 657 TrapFrame); 658 } 659 660 DECLSPEC_NORETURN 661 VOID 662 FASTCALL 663 KiTrap06Handler(IN PKTRAP_FRAME TrapFrame) 664 { 665 PUCHAR Instruction; 666 ULONG i; 667 KIRQL OldIrql; 668 669 /* Check for V86 GPF */ 670 if (__builtin_expect(KiV86Trap(TrapFrame), 1)) 671 { 672 /* Enter V86 trap */ 673 KiEnterV86Trap(TrapFrame); 674 675 /* Must be a VDM process */ 676 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) 677 { 678 /* Enable interrupts */ 679 _enable(); 680 681 /* Setup illegal instruction fault */ 682 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 683 TrapFrame->Eip, 684 TrapFrame); 685 } 686 687 /* Go to APC level */ 688 KeRaiseIrql(APC_LEVEL, &OldIrql); 689 _enable(); 690 691 /* Check for BOP */ 692 if (!VdmDispatchBop(TrapFrame)) 693 { 694 /* Should only happen in VDM mode */ 695 UNIMPLEMENTED_FATAL(); 696 } 697 698 /* Bring IRQL back */ 699 KeLowerIrql(OldIrql); 700 _disable(); 701 702 /* Do a quick V86 exit if possible */ 703 KiExitV86Trap(TrapFrame); 704 } 705 706 /* Save trap frame */ 707 KiEnterTrap(TrapFrame); 708 709 /* Enable interrupts */ 710 Instruction = (PUCHAR)TrapFrame->Eip; 711 _enable(); 712 713 /* Check for user trap */ 714 if (KiUserTrap(TrapFrame)) 715 { 716 /* FIXME: Use SEH */ 717 718 /* Scan next 4 opcodes */ 719 for (i = 0; i < 4; i++) 720 { 721 /* Check for LOCK instruction */ 722 if (Instruction[i] == 0xF0) 723 { 724 /* Send invalid lock sequence exception */ 725 KiDispatchException0Args(STATUS_INVALID_LOCK_SEQUENCE, 726 TrapFrame->Eip, 727 TrapFrame); 728 } 729 } 730 731 /* FIXME: SEH ends here */ 732 } 733 734 /* Kernel-mode or user-mode fault (but not LOCK) */ 735 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 736 TrapFrame->Eip, 737 TrapFrame); 738 739 } 740 741 DECLSPEC_NORETURN 742 VOID 743 FASTCALL 744 KiTrap07Handler(IN PKTRAP_FRAME TrapFrame) 745 { 746 PKTHREAD Thread, NpxThread; 747 PFX_SAVE_AREA SaveArea, NpxSaveArea; 748 ULONG Cr0; 749 750 /* Save trap frame */ 751 KiEnterTrap(TrapFrame); 752 753 /* Try to handle NPX delay load */ 754 for (;;) 755 { 756 /* Get the current thread */ 757 Thread = KeGetCurrentThread(); 758 759 /* Get the NPX frame */ 760 SaveArea = KiGetThreadNpxArea(Thread); 761 762 /* Check if emulation is enabled */ 763 if (SaveArea->Cr0NpxState & CR0_EM) 764 { 765 /* Not implemented */ 766 UNIMPLEMENTED_FATAL(); 767 } 768 769 /* Save CR0 and check NPX state */ 770 Cr0 = __readcr0(); 771 if (Thread->NpxState != NPX_STATE_LOADED) 772 { 773 /* Update CR0 */ 774 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS); 775 __writecr0(Cr0); 776 777 /* Get the NPX thread */ 778 NpxThread = KeGetCurrentPrcb()->NpxThread; 779 if (NpxThread) 780 { 781 /* Get the NPX frame */ 782 NpxSaveArea = KiGetThreadNpxArea(NpxThread); 783 784 /* Save FPU state */ 785 Ke386SaveFpuState(NpxSaveArea); 786 787 /* Update NPX state */ 788 NpxThread->NpxState = NPX_STATE_NOT_LOADED; 789 } 790 791 /* Load FPU state */ 792 Ke386LoadFpuState(SaveArea); 793 794 /* Update NPX state */ 795 Thread->NpxState = NPX_STATE_LOADED; 796 KeGetCurrentPrcb()->NpxThread = Thread; 797 798 /* Enable interrupts */ 799 _enable(); 800 801 /* Check if CR0 needs to be reloaded due to context switch */ 802 if (!SaveArea->Cr0NpxState) KiEoiHelper(TrapFrame); 803 804 /* Otherwise, we need to reload CR0, disable interrupts */ 805 _disable(); 806 807 /* Reload CR0 */ 808 Cr0 = __readcr0(); 809 Cr0 |= SaveArea->Cr0NpxState; 810 __writecr0(Cr0); 811 812 /* Now restore interrupts and check for TS */ 813 _enable(); 814 if (Cr0 & CR0_TS) KiEoiHelper(TrapFrame); 815 816 /* We're still here -- clear TS and try again */ 817 __writecr0(__readcr0() &~ CR0_TS); 818 _disable(); 819 } 820 else 821 { 822 /* This is an actual fault, not a lack of FPU state */ 823 break; 824 } 825 } 826 827 /* TS should not be set */ 828 if (Cr0 & CR0_TS) 829 { 830 /* 831 * If it's incorrectly set, then maybe the state is actually still valid 832 * but we could have lost track of that due to a BIOS call. 833 * Make sure MP is still set, which should verify the theory. 834 */ 835 if (Cr0 & CR0_MP) 836 { 837 /* Indeed, the state is actually still valid, so clear TS */ 838 __writecr0(__readcr0() &~ CR0_TS); 839 KiEoiHelper(TrapFrame); 840 } 841 842 /* Otherwise, something strange is going on */ 843 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 2, Cr0, 0, 0, TrapFrame); 844 } 845 846 /* It's not a delayed load, so process this trap as an NPX fault */ 847 KiNpxHandler(TrapFrame, Thread, SaveArea); 848 } 849 850 DECLSPEC_NORETURN 851 VOID 852 FASTCALL 853 KiTrap08Handler(IN PKTRAP_FRAME TrapFrame) 854 { 855 /* FIXME: Not handled */ 856 KiSystemFatalException(EXCEPTION_DOUBLE_FAULT, TrapFrame); 857 } 858 859 DECLSPEC_NORETURN 860 VOID 861 FASTCALL 862 KiTrap09Handler(IN PKTRAP_FRAME TrapFrame) 863 { 864 /* Save trap frame */ 865 KiEnterTrap(TrapFrame); 866 867 /* Enable interrupts and kill the system */ 868 _enable(); 869 KiSystemFatalException(EXCEPTION_NPX_OVERRUN, TrapFrame); 870 } 871 872 DECLSPEC_NORETURN 873 VOID 874 FASTCALL 875 KiTrap0AHandler(IN PKTRAP_FRAME TrapFrame) 876 { 877 /* Save trap frame */ 878 KiEnterTrap(TrapFrame); 879 880 /* Check for VDM trap */ 881 ASSERT((KiVdmTrap(TrapFrame)) == FALSE); 882 883 /* Kill the system */ 884 KiSystemFatalException(EXCEPTION_INVALID_TSS, TrapFrame); 885 } 886 887 DECLSPEC_NORETURN 888 VOID 889 FASTCALL 890 KiTrap0BHandler(IN PKTRAP_FRAME TrapFrame) 891 { 892 /* Save trap frame */ 893 KiEnterTrap(TrapFrame); 894 895 /* FIXME: Kill the system */ 896 UNIMPLEMENTED; 897 KiSystemFatalException(EXCEPTION_SEGMENT_NOT_PRESENT, TrapFrame); 898 } 899 900 DECLSPEC_NORETURN 901 VOID 902 FASTCALL 903 KiTrap0CHandler(IN PKTRAP_FRAME TrapFrame) 904 { 905 /* Save trap frame */ 906 KiEnterTrap(TrapFrame); 907 908 /* FIXME: Kill the system */ 909 UNIMPLEMENTED; 910 KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame); 911 } 912 913 DECLSPEC_NORETURN 914 VOID 915 FASTCALL 916 KiTrap0DHandler(IN PKTRAP_FRAME TrapFrame) 917 { 918 ULONG i, j, Iopl; 919 BOOLEAN Privileged = FALSE; 920 PUCHAR Instructions; 921 UCHAR Instruction = 0; 922 KIRQL OldIrql; 923 924 /* Check for V86 GPF */ 925 if (__builtin_expect(KiV86Trap(TrapFrame), 1)) 926 { 927 /* Enter V86 trap */ 928 KiEnterV86Trap(TrapFrame); 929 930 /* Must be a VDM process */ 931 if (__builtin_expect(!PsGetCurrentProcess()->VdmObjects, 0)) 932 { 933 /* Enable interrupts */ 934 _enable(); 935 936 /* Setup illegal instruction fault */ 937 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 938 TrapFrame->Eip, 939 TrapFrame); 940 } 941 942 /* Go to APC level */ 943 KeRaiseIrql(APC_LEVEL, &OldIrql); 944 _enable(); 945 946 /* Handle the V86 opcode */ 947 if (__builtin_expect(Ki386HandleOpcodeV86(TrapFrame) == 0xFF, 0)) 948 { 949 /* Should only happen in VDM mode */ 950 UNIMPLEMENTED_FATAL(); 951 } 952 953 /* Bring IRQL back */ 954 KeLowerIrql(OldIrql); 955 _disable(); 956 957 /* Do a quick V86 exit if possible */ 958 KiExitV86Trap(TrapFrame); 959 } 960 961 /* Save trap frame */ 962 KiEnterTrap(TrapFrame); 963 964 /* Check for user-mode GPF */ 965 if (KiUserTrap(TrapFrame)) 966 { 967 /* Should not be VDM */ 968 ASSERT(KiVdmTrap(TrapFrame) == FALSE); 969 970 /* Enable interrupts and check error code */ 971 _enable(); 972 if (!TrapFrame->ErrCode) 973 { 974 /* FIXME: Use SEH */ 975 Instructions = (PUCHAR)TrapFrame->Eip; 976 977 /* Scan next 15 bytes */ 978 for (i = 0; i < 15; i++) 979 { 980 /* Skip prefix instructions */ 981 for (j = 0; j < sizeof(KiTrapPrefixTable); j++) 982 { 983 /* Is this a prefix instruction? */ 984 if (Instructions[i] == KiTrapPrefixTable[j]) 985 { 986 /* Stop looking */ 987 break; 988 } 989 } 990 991 /* Is this NOT any prefix instruction? */ 992 if (j == sizeof(KiTrapPrefixTable)) 993 { 994 /* We can go ahead and handle the fault now */ 995 Instruction = Instructions[i]; 996 break; 997 } 998 } 999 1000 /* If all we found was prefixes, then this instruction is too long */ 1001 if (i == 15) 1002 { 1003 /* Setup illegal instruction fault */ 1004 KiDispatchException0Args(STATUS_ILLEGAL_INSTRUCTION, 1005 TrapFrame->Eip, 1006 TrapFrame); 1007 } 1008 1009 /* Check for privileged instructions */ 1010 DPRINT("Instruction (%lu) at fault: %lx %lx %lx %lx\n", 1011 i, 1012 Instructions[i], 1013 Instructions[i + 1], 1014 Instructions[i + 2], 1015 Instructions[i + 3]); 1016 if (Instruction == 0xF4) // HLT 1017 { 1018 /* HLT is privileged */ 1019 Privileged = TRUE; 1020 } 1021 else if (Instruction == 0x0F) 1022 { 1023 /* Test if it's any of the privileged two-byte opcodes */ 1024 if (((Instructions[i + 1] == 0x00) && // LLDT or LTR 1025 (((Instructions[i + 2] & 0x38) == 0x10) || // LLDT 1026 (Instructions[i + 2] == 0x18))) || // LTR 1027 ((Instructions[i + 1] == 0x01) && // LGDT or LIDT or LMSW 1028 (((Instructions[i + 2] & 0x38) == 0x10) || // LGDT 1029 (Instructions[i + 2] == 0x18) || // LIDT 1030 (Instructions[i + 2] == 0x30))) || // LMSW 1031 (Instructions[i + 1] == 0x08) || // INVD 1032 (Instructions[i + 1] == 0x09) || // WBINVD 1033 (Instructions[i + 1] == 0x35) || // SYSEXIT 1034 (Instructions[i + 1] == 0x21) || // MOV DR, XXX 1035 (Instructions[i + 1] == 0x06) || // CLTS 1036 (Instructions[i + 1] == 0x20) || // MOV CR, XXX 1037 (Instructions[i + 1] == 0x22) || // MOV XXX, CR 1038 (Instructions[i + 1] == 0x23) || // MOV YYY, DR 1039 (Instructions[i + 1] == 0x30) || // WRMSR 1040 (Instructions[i + 1] == 0x33)) // RDPMC 1041 // INVLPG, INVLPGA, SYSRET 1042 { 1043 /* These are all privileged */ 1044 Privileged = TRUE; 1045 } 1046 } 1047 else 1048 { 1049 /* Get the IOPL and compare with the RPL mask */ 1050 Iopl = (TrapFrame->EFlags & EFLAGS_IOPL) >> 12; 1051 if ((TrapFrame->SegCs & RPL_MASK) > Iopl) 1052 { 1053 /* I/O privilege error -- check for known instructions */ 1054 if ((Instruction == 0xFA) || (Instruction == 0xFB)) // CLI or STI 1055 { 1056 /* These are privileged */ 1057 Privileged = TRUE; 1058 } 1059 else 1060 { 1061 /* Last hope: an IN/OUT instruction */ 1062 for (j = 0; j < sizeof(KiTrapIoTable); j++) 1063 { 1064 /* Is this an I/O instruction? */ 1065 if (Instruction == KiTrapIoTable[j]) 1066 { 1067 /* Then it's privileged */ 1068 Privileged = TRUE; 1069 break; 1070 } 1071 } 1072 } 1073 } 1074 } 1075 1076 /* So now... was the instruction privileged or not? */ 1077 if (Privileged) 1078 { 1079 /* Whew! We have a privileged instruction, so dispatch the fault */ 1080 KiDispatchException0Args(STATUS_PRIVILEGED_INSTRUCTION, 1081 TrapFrame->Eip, 1082 TrapFrame); 1083 } 1084 } 1085 1086 /* If we got here, send an access violation */ 1087 KiDispatchException2Args(STATUS_ACCESS_VIOLATION, 1088 TrapFrame->Eip, 1089 0, 1090 0xFFFFFFFF, 1091 TrapFrame); 1092 } 1093 1094 /* 1095 * Check for a fault during checking of the user instruction. 1096 * 1097 * Note that the SEH handler will catch invalid EIP, but we could be dealing 1098 * with an invalid CS, which will generate another GPF instead. 1099 * 1100 */ 1101 if (((PVOID)TrapFrame->Eip >= (PVOID)KiTrap0DHandler) && 1102 ((PVOID)TrapFrame->Eip < (PVOID)KiTrap0DHandler)) 1103 { 1104 /* Not implemented */ 1105 UNIMPLEMENTED_FATAL(); 1106 } 1107 1108 /* 1109 * NOTE: The ASM trap exit code would restore segment registers by doing 1110 * a POP <SEG>, which could cause an invalid segment if someone had messed 1111 * with the segment values. 1112 * 1113 * Another case is a bogus SS, which would hit a GPF when doing the iret. 1114 * This could only be done through a buggy or malicious driver, or perhaps 1115 * the kernel debugger. 1116 * 1117 * The kernel normally restores the "true" segment if this happens. 1118 * 1119 * However, since we're restoring in C, not ASM, we can't detect 1120 * POP <SEG> since the actual instructions will be different. 1121 * 1122 * A better technique would be to check the EIP and somehow edit the 1123 * trap frame before restarting the instruction -- but we would need to 1124 * know the extract instruction that was used first. 1125 * 1126 * We could force a special instrinsic to use stack instructions, or write 1127 * a simple instruction length checker. 1128 * 1129 * Nevertheless, this is a lot of work for the purpose of avoiding a crash 1130 * when the user is purposedly trying to create one from kernel-mode, so 1131 * we should probably table this for now since it's not a "real" issue. 1132 */ 1133 1134 /* 1135 * NOTE2: Another scenario is the IRET during a V8086 restore (BIOS Call) 1136 * which will cause a GPF since the trap frame is a total mess (on purpose) 1137 * as built in KiEnterV86Mode. 1138 * 1139 * The idea is to scan for IRET, scan for the known EIP adress, validate CS 1140 * and then manually issue a jump to the V8086 return EIP. 1141 */ 1142 Instructions = (PUCHAR)TrapFrame->Eip; 1143 if (Instructions[0] == 0xCF) 1144 { 1145 /* 1146 * Some evil shit is going on here -- this is not the SS:ESP you're 1147 * looking for! Instead, this is actually CS:EIP you're looking at! 1148 * Why? Because part of the trap frame actually corresponds to the IRET 1149 * stack during the trap exit! 1150 */ 1151 if ((TrapFrame->HardwareEsp == (ULONG)Ki386BiosCallReturnAddress) && 1152 (TrapFrame->HardwareSegSs == (KGDT_R0_CODE | RPL_MASK))) 1153 { 1154 /* Exit the V86 trap! */ 1155 Ki386BiosCallReturnAddress(TrapFrame); 1156 } 1157 else 1158 { 1159 /* Otherwise, this is another kind of IRET fault */ 1160 UNIMPLEMENTED_FATAL(); 1161 } 1162 } 1163 1164 /* So since we're not dealing with the above case, check for RDMSR/WRMSR */ 1165 if ((Instructions[0] == 0xF) && // 2-byte opcode 1166 ((Instructions[1] == 0x32) || // RDMSR 1167 (Instructions[1] == 0x30))) // WRMSR 1168 { 1169 /* Unknown CPU MSR, so raise an access violation */ 1170 KiDispatchException0Args(STATUS_ACCESS_VIOLATION, 1171 TrapFrame->Eip, 1172 TrapFrame); 1173 } 1174 1175 /* Check for lazy segment load */ 1176 if (TrapFrame->SegDs != (KGDT_R3_DATA | RPL_MASK)) 1177 { 1178 /* Fix it */ 1179 TrapFrame->SegDs = (KGDT_R3_DATA | RPL_MASK); 1180 } 1181 else if (TrapFrame->SegEs != (KGDT_R3_DATA | RPL_MASK)) 1182 { 1183 /* Fix it */ 1184 TrapFrame->SegEs = (KGDT_R3_DATA | RPL_MASK); 1185 } 1186 else 1187 { 1188 /* Whatever it is, we can't handle it */ 1189 KiSystemFatalException(EXCEPTION_GP_FAULT, TrapFrame); 1190 } 1191 1192 /* Return to where we came from */ 1193 KiTrapReturn(TrapFrame); 1194 } 1195 1196 DECLSPEC_NORETURN 1197 VOID 1198 FASTCALL 1199 KiTrap0EHandler(IN PKTRAP_FRAME TrapFrame) 1200 { 1201 PKTHREAD Thread; 1202 BOOLEAN StoreInstruction; 1203 ULONG_PTR Cr2; 1204 NTSTATUS Status; 1205 1206 /* Save trap frame */ 1207 KiEnterTrap(TrapFrame); 1208 1209 /* Check if this is the base frame */ 1210 Thread = KeGetCurrentThread(); 1211 if (KeGetTrapFrame(Thread) != TrapFrame) 1212 { 1213 /* It isn't, check if this is a second nested frame */ 1214 if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <= 1215 FIELD_OFFSET(KTRAP_FRAME, EFlags)) 1216 { 1217 /* The stack is somewhere in between frames, we need to fix it */ 1218 UNIMPLEMENTED_FATAL(); 1219 } 1220 } 1221 1222 /* Save CR2 */ 1223 Cr2 = __readcr2(); 1224 1225 /* Enable interrupts */ 1226 _enable(); 1227 1228 /* Interpret the error code */ 1229 StoreInstruction = (TrapFrame->ErrCode & 2) != 0; 1230 1231 /* Check if we came in with interrupts disabled */ 1232 if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK)) 1233 { 1234 /* This is completely illegal, bugcheck the system */ 1235 KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL, 1236 Cr2, 1237 (ULONG_PTR)-1, 1238 TrapFrame->ErrCode, 1239 TrapFrame->Eip, 1240 TrapFrame); 1241 } 1242 1243 /* Check for S-List fault 1244 1245 Explanation: An S-List fault can occur due to a race condition between 2 1246 threads simultaneously trying to pop an element from the S-List. After 1247 thread 1 has read the pointer to the top element on the S-List it is 1248 preempted and thread 2 calls InterlockedPopEntrySlist on the same S-List, 1249 removing the top element and freeing it's memory. After that thread 1 1250 resumes and tries to read the address of the Next pointer from the top 1251 element, which it assumes will be the next top element. 1252 But since that memory has been freed, we get a page fault. To handle this 1253 race condition, we let thread 1 repeat the operation. 1254 We do NOT invoke the page fault handler in this case, since we do not 1255 want to trigger any side effects, like paging or a guard page fault. 1256 1257 Sequence of operations: 1258 1259 Thread 1 : mov eax, [ebp] <= eax now points to the first element 1260 Thread 1 : mov edx, [ebp + 4] <= edx is loaded with Depth and Sequence 1261 *** preempted *** 1262 Thread 2 : calls InterlockedPopEntrySlist, changing the top element 1263 Thread 2 : frees the memory of the element that was popped 1264 *** preempted *** 1265 Thread 1 : checks if eax is NULL 1266 Thread 1 : InterlockedPopEntrySListFault: mov ebx, [eax] <= faults 1267 1268 To be sure that we are dealing with exactly the case described above, we 1269 check whether the ListHeader has changed. If Thread 2 only popped one 1270 entry, the Next field in the S-List-header has changed. 1271 If after thread 1 has faulted, thread 2 allocates a new element, by 1272 chance getting the same address as the previously freed element and 1273 pushes it on the list again, we will see the same top element, but the 1274 Sequence member of the S-List header has changed. Therefore we check 1275 both fields to make sure we catch any concurrent modification of the 1276 S-List-header. 1277 */ 1278 if ((TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault) || 1279 (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault)) 1280 { 1281 ULARGE_INTEGER SListHeader; 1282 PVOID ResumeAddress; 1283 1284 /* Sanity check that the assembly is correct: 1285 This must be mov ebx, [eax] 1286 Followed by cmpxchg8b [ebp] */ 1287 ASSERT((((UCHAR*)TrapFrame->Eip)[0] == 0x8B) && 1288 (((UCHAR*)TrapFrame->Eip)[1] == 0x18) && 1289 (((UCHAR*)TrapFrame->Eip)[2] == 0x0F) && 1290 (((UCHAR*)TrapFrame->Eip)[3] == 0xC7) && 1291 (((UCHAR*)TrapFrame->Eip)[4] == 0x4D) && 1292 (((UCHAR*)TrapFrame->Eip)[5] == 0x00)); 1293 1294 /* Check if this is a user fault */ 1295 if (TrapFrame->Eip == (ULONG_PTR)KeUserPopEntrySListFault) 1296 { 1297 /* EBP points to the S-List-header. Copy it inside SEH, to protect 1298 against a bogus pointer from user mode */ 1299 _SEH2_TRY 1300 { 1301 ProbeForRead((PVOID)TrapFrame->Ebp, 1302 sizeof(ULARGE_INTEGER), 1303 TYPE_ALIGNMENT(SLIST_HEADER)); 1304 SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp; 1305 } 1306 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1307 { 1308 /* The S-List pointer is not valid! */ 1309 goto NotSListFault; 1310 } 1311 _SEH2_END; 1312 ResumeAddress = KeUserPopEntrySListResume; 1313 } 1314 else 1315 { 1316 SListHeader = *(PULARGE_INTEGER)TrapFrame->Ebp; 1317 ResumeAddress = ExpInterlockedPopEntrySListResume; 1318 } 1319 1320 /* Check if either the Next pointer or the Sequence member in the 1321 S-List-header has changed. If any of these has changed, we restart 1322 the operation. Otherwise we only have a bogus pointer and let the 1323 page fault handler deal with it. */ 1324 if ((SListHeader.LowPart != TrapFrame->Eax) || 1325 (SListHeader.HighPart != TrapFrame->Edx)) 1326 { 1327 DPRINT1("*** Got an S-List-Fault ***\n"); 1328 KeGetCurrentThread()->SListFaultCount++; 1329 1330 /* Restart the operation */ 1331 TrapFrame->Eip = (ULONG_PTR)ResumeAddress; 1332 1333 /* Continue execution */ 1334 KiEoiHelper(TrapFrame); 1335 } 1336 } 1337 NotSListFault: 1338 1339 /* Call the access fault handler */ 1340 Status = MmAccessFault(TrapFrame->ErrCode, 1341 (PVOID)Cr2, 1342 KiUserTrap(TrapFrame), 1343 TrapFrame); 1344 if (NT_SUCCESS(Status)) 1345 { 1346 #ifdef _WINKD_ 1347 /* Check whether the kernel debugger has owed breakpoints to be inserted */ 1348 KdSetOwedBreakpoints(); 1349 #endif 1350 /* We succeeded, return */ 1351 KiEoiHelper(TrapFrame); 1352 } 1353 1354 /* Check for syscall fault */ 1355 #if 0 1356 if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) || 1357 (TrapFrame->Eip == (ULONG_PTR)ReadBatch)) 1358 { 1359 /* Not yet implemented */ 1360 UNIMPLEMENTED_FATAL(); 1361 } 1362 #endif 1363 1364 /* Check for VDM trap */ 1365 if (KiVdmTrap(TrapFrame)) 1366 { 1367 DPRINT1("VDM PAGE FAULT at %lx:%lx for address %lx\n", 1368 TrapFrame->SegCs, TrapFrame->Eip, Cr2); 1369 if (VdmDispatchPageFault(TrapFrame)) 1370 { 1371 /* Return and end VDM execution */ 1372 DPRINT1("VDM page fault with status 0x%lx resolved\n", Status); 1373 KiEoiHelper(TrapFrame); 1374 } 1375 DPRINT1("VDM page fault with status 0x%lx NOT resolved\n", Status); 1376 } 1377 1378 /* Either kernel or user trap (non VDM) so dispatch exception */ 1379 if (Status == STATUS_ACCESS_VIOLATION) 1380 { 1381 /* This status code is repurposed so we can recognize it later */ 1382 KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION, 1383 TrapFrame->Eip, 1384 StoreInstruction, 1385 Cr2, 1386 TrapFrame); 1387 } 1388 else if ((Status == STATUS_GUARD_PAGE_VIOLATION) || 1389 (Status == STATUS_STACK_OVERFLOW)) 1390 { 1391 /* These faults only have two parameters */ 1392 KiDispatchException2Args(Status, 1393 TrapFrame->Eip, 1394 StoreInstruction, 1395 Cr2, 1396 TrapFrame); 1397 } 1398 1399 /* Only other choice is an in-page error, with 3 parameters */ 1400 KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR, 1401 0, 1402 TrapFrame->Eip, 1403 3, 1404 StoreInstruction, 1405 Cr2, 1406 Status, 1407 TrapFrame); 1408 } 1409 1410 DECLSPEC_NORETURN 1411 VOID 1412 FASTCALL 1413 KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame) 1414 { 1415 /* Save trap frame */ 1416 KiEnterTrap(TrapFrame); 1417 1418 /* FIXME: Kill the system */ 1419 UNIMPLEMENTED; 1420 KiSystemFatalException(EXCEPTION_RESERVED_TRAP, TrapFrame); 1421 } 1422 1423 DECLSPEC_NORETURN 1424 VOID 1425 FASTCALL 1426 KiTrap10Handler(IN PKTRAP_FRAME TrapFrame) 1427 { 1428 PKTHREAD Thread; 1429 PFX_SAVE_AREA SaveArea; 1430 1431 /* Save trap frame */ 1432 KiEnterTrap(TrapFrame); 1433 1434 /* Check if this is the NPX thrad */ 1435 Thread = KeGetCurrentThread(); 1436 SaveArea = KiGetThreadNpxArea(Thread); 1437 if (Thread != KeGetCurrentPrcb()->NpxThread) 1438 { 1439 /* It isn't, enable interrupts and set delayed error */ 1440 _enable(); 1441 SaveArea->Cr0NpxState |= CR0_TS; 1442 1443 /* End trap */ 1444 KiEoiHelper(TrapFrame); 1445 } 1446 1447 /* Otherwise, proceed with NPX fault handling */ 1448 KiNpxHandler(TrapFrame, Thread, SaveArea); 1449 } 1450 1451 DECLSPEC_NORETURN 1452 VOID 1453 FASTCALL 1454 KiTrap11Handler(IN PKTRAP_FRAME TrapFrame) 1455 { 1456 /* Save trap frame */ 1457 KiEnterTrap(TrapFrame); 1458 1459 /* Enable interrupts and kill the system */ 1460 _enable(); 1461 KiSystemFatalException(EXCEPTION_ALIGNMENT_CHECK, TrapFrame); 1462 } 1463 1464 DECLSPEC_NORETURN 1465 VOID 1466 FASTCALL 1467 KiTrap13Handler(IN PKTRAP_FRAME TrapFrame) 1468 { 1469 PKTHREAD Thread; 1470 PFX_SAVE_AREA SaveArea; 1471 ULONG Cr0, MxCsrMask, Error; 1472 1473 /* Save trap frame */ 1474 KiEnterTrap(TrapFrame); 1475 1476 /* Check if this is the NPX thrad */ 1477 Thread = KeGetCurrentThread(); 1478 if (Thread != KeGetCurrentPrcb()->NpxThread) 1479 { 1480 /* It isn't, kill the system */ 1481 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, (ULONG_PTR)Thread, 0, 0, TrapFrame); 1482 } 1483 1484 /* Get the NPX frame */ 1485 SaveArea = KiGetThreadNpxArea(Thread); 1486 1487 /* Check for VDM trap */ 1488 ASSERT((KiVdmTrap(TrapFrame)) == FALSE); 1489 1490 /* Check for user trap */ 1491 if (!KiUserTrap(TrapFrame)) 1492 { 1493 /* Kernel should not fault on XMMI */ 1494 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 2, TrapFrame); 1495 } 1496 1497 /* Update CR0 */ 1498 Cr0 = __readcr0(); 1499 Cr0 &= ~(CR0_MP | CR0_EM | CR0_TS); 1500 __writecr0(Cr0); 1501 1502 /* Save FPU state */ 1503 Ke386SaveFpuState(SaveArea); 1504 1505 /* Mark CR0 state dirty */ 1506 Cr0 |= NPX_STATE_NOT_LOADED; 1507 Cr0 |= SaveArea->Cr0NpxState; 1508 __writecr0(Cr0); 1509 1510 /* Update NPX state */ 1511 Thread->NpxState = NPX_STATE_NOT_LOADED; 1512 KeGetCurrentPrcb()->NpxThread = NULL; 1513 1514 /* Clear the TS bit and re-enable interrupts */ 1515 SaveArea->Cr0NpxState &= ~CR0_TS; 1516 _enable(); 1517 1518 /* Now look at MxCsr to get the mask of errors we should care about */ 1519 MxCsrMask = ~((USHORT)SaveArea->U.FxArea.MXCsr >> 7); 1520 1521 /* Get legal exceptions that software should handle */ 1522 Error = (USHORT)SaveArea->U.FxArea.MXCsr & (FSW_INVALID_OPERATION | 1523 FSW_DENORMAL | 1524 FSW_ZERO_DIVIDE | 1525 FSW_OVERFLOW | 1526 FSW_UNDERFLOW | 1527 FSW_PRECISION); 1528 Error &= MxCsrMask; 1529 1530 /* Now handle any of those legal errors */ 1531 if (Error & (FSW_INVALID_OPERATION | 1532 FSW_DENORMAL | 1533 FSW_ZERO_DIVIDE | 1534 FSW_OVERFLOW | 1535 FSW_UNDERFLOW | 1536 FSW_PRECISION)) 1537 { 1538 /* By issuing an exception */ 1539 KiDispatchException1Args(STATUS_FLOAT_MULTIPLE_TRAPS, 1540 TrapFrame->Eip, 1541 0, 1542 TrapFrame); 1543 } 1544 1545 /* Unknown XMMI fault */ 1546 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame); 1547 } 1548 1549 /* SOFTWARE SERVICES **********************************************************/ 1550 1551 VOID 1552 FASTCALL 1553 KiRaiseSecurityCheckFailureHandler(IN PKTRAP_FRAME TrapFrame) 1554 { 1555 /* Save trap frame */ 1556 KiEnterTrap(TrapFrame); 1557 1558 /* Decrement EIP to point to the INT29 instruction (2 bytes, not 1 like INT3) */ 1559 TrapFrame->Eip -= 2; 1560 1561 /* Check if this is a user trap */ 1562 if (KiUserTrap(TrapFrame)) 1563 { 1564 /* Dispatch exception to user mode */ 1565 KiDispatchExceptionFromTrapFrame(STATUS_STACK_BUFFER_OVERRUN, 1566 EXCEPTION_NONCONTINUABLE, 1567 TrapFrame->Eip, 1568 1, 1569 TrapFrame->Ecx, 1570 0, 1571 0, 1572 TrapFrame); 1573 } 1574 else 1575 { 1576 EXCEPTION_RECORD ExceptionRecord; 1577 1578 /* Bugcheck the system */ 1579 ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; 1580 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 1581 ExceptionRecord.ExceptionRecord = NULL; 1582 ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Eip; 1583 ExceptionRecord.NumberParameters = 1; 1584 ExceptionRecord.ExceptionInformation[0] = TrapFrame->Ecx; 1585 1586 KeBugCheckWithTf(KERNEL_SECURITY_CHECK_FAILURE, 1587 TrapFrame->Ecx, 1588 (ULONG_PTR)TrapFrame, 1589 (ULONG_PTR)&ExceptionRecord, 1590 0, 1591 TrapFrame); 1592 } 1593 } 1594 1595 VOID 1596 FASTCALL 1597 KiGetTickCountHandler(IN PKTRAP_FRAME TrapFrame) 1598 { 1599 /* Save trap frame */ 1600 KiEnterTrap(TrapFrame); 1601 1602 /* 1603 * Just fail the request 1604 */ 1605 DbgPrint("INT 0x2A attempted, returning 0 tick count\n"); 1606 TrapFrame->Eax = 0; 1607 1608 /* Exit the trap */ 1609 KiEoiHelper(TrapFrame); 1610 } 1611 1612 VOID 1613 FASTCALL 1614 KiCallbackReturnHandler(IN PKTRAP_FRAME TrapFrame) 1615 { 1616 PKTHREAD Thread; 1617 NTSTATUS Status; 1618 1619 /* Save the SEH chain, NtCallbackReturn will restore this */ 1620 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; 1621 1622 /* Set thread fields */ 1623 Thread = KeGetCurrentThread(); 1624 Thread->TrapFrame = TrapFrame; 1625 Thread->PreviousMode = KiUserTrap(TrapFrame); 1626 ASSERT(Thread->PreviousMode != KernelMode); 1627 1628 /* Pass the register parameters to NtCallbackReturn. 1629 Result pointer is in ecx, result length in edx, status in eax */ 1630 Status = NtCallbackReturn((PVOID)TrapFrame->Ecx, 1631 TrapFrame->Edx, 1632 TrapFrame->Eax); 1633 1634 /* If we got here, something went wrong. Return an error to the caller */ 1635 KiServiceExit(TrapFrame, Status); 1636 } 1637 1638 DECLSPEC_NORETURN 1639 VOID 1640 FASTCALL 1641 KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame) 1642 { 1643 /* Save trap frame */ 1644 KiEnterTrap(TrapFrame); 1645 1646 /* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */ 1647 TrapFrame->Eip -= 2; 1648 1649 /* Dispatch the exception */ 1650 KiDispatchException0Args(STATUS_ASSERTION_FAILURE, 1651 TrapFrame->Eip, 1652 TrapFrame); 1653 } 1654 1655 DECLSPEC_NORETURN 1656 VOID 1657 FASTCALL 1658 KiDebugServiceHandler(IN PKTRAP_FRAME TrapFrame) 1659 { 1660 /* Save trap frame */ 1661 KiEnterTrap(TrapFrame); 1662 1663 /* Increment EIP to skip the INT3 instruction */ 1664 TrapFrame->Eip++; 1665 1666 /* Continue with the common handler */ 1667 KiDebugHandler(TrapFrame, TrapFrame->Eax, TrapFrame->Ecx, TrapFrame->Edx); 1668 } 1669 1670 1671 FORCEINLINE 1672 VOID 1673 KiDbgPreServiceHook(ULONG SystemCallNumber, PULONG_PTR Arguments) 1674 { 1675 #if DBG && !defined(_WINKD_) 1676 if (SystemCallNumber >= 0x1000 && KeWin32PreServiceHook) 1677 KeWin32PreServiceHook(SystemCallNumber, Arguments); 1678 #endif 1679 } 1680 1681 FORCEINLINE 1682 ULONG_PTR 1683 KiDbgPostServiceHook(ULONG SystemCallNumber, ULONG_PTR Result) 1684 { 1685 #if DBG && !defined(_WINKD_) 1686 if (SystemCallNumber >= 0x1000 && KeWin32PostServiceHook) 1687 return KeWin32PostServiceHook(SystemCallNumber, Result); 1688 #endif 1689 return Result; 1690 } 1691 1692 DECLSPEC_NORETURN 1693 VOID 1694 FASTCALL 1695 KiSystemServiceHandler(IN PKTRAP_FRAME TrapFrame, 1696 IN PVOID Arguments) 1697 { 1698 PKTHREAD Thread; 1699 PKSERVICE_TABLE_DESCRIPTOR DescriptorTable; 1700 ULONG Id, Offset, StackBytes; 1701 NTSTATUS Status; 1702 PVOID Handler; 1703 ULONG SystemCallNumber = TrapFrame->Eax; 1704 1705 /* Get the current thread */ 1706 Thread = KeGetCurrentThread(); 1707 1708 /* Set debug header */ 1709 KiFillTrapFrameDebug(TrapFrame); 1710 1711 /* Chain trap frames */ 1712 TrapFrame->Edx = (ULONG_PTR)Thread->TrapFrame; 1713 1714 /* No error code */ 1715 TrapFrame->ErrCode = 0; 1716 1717 /* Save previous mode */ 1718 TrapFrame->PreviousPreviousMode = Thread->PreviousMode; 1719 1720 /* Save the SEH chain and terminate it for now */ 1721 TrapFrame->ExceptionList = KeGetPcr()->NtTib.ExceptionList; 1722 KeGetPcr()->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 1723 1724 /* Default to debugging disabled */ 1725 TrapFrame->Dr7 = 0; 1726 1727 /* Check if the frame was from user mode */ 1728 if (KiUserTrap(TrapFrame)) 1729 { 1730 /* Check for active debugging */ 1731 if (KeGetCurrentThread()->Header.DebugActive & 0xFF) 1732 { 1733 /* Handle debug registers */ 1734 KiHandleDebugRegistersOnTrapEntry(TrapFrame); 1735 } 1736 } 1737 1738 /* Set thread fields */ 1739 Thread->TrapFrame = TrapFrame; 1740 Thread->PreviousMode = KiUserTrap(TrapFrame); 1741 1742 /* Enable interrupts */ 1743 _enable(); 1744 1745 /* Decode the system call number */ 1746 Offset = (SystemCallNumber >> SERVICE_TABLE_SHIFT) & SERVICE_TABLE_MASK; 1747 Id = SystemCallNumber & SERVICE_NUMBER_MASK; 1748 1749 /* Get descriptor table */ 1750 DescriptorTable = (PVOID)((ULONG_PTR)Thread->ServiceTable + Offset); 1751 1752 /* Validate the system call number */ 1753 if (__builtin_expect(Id >= DescriptorTable->Limit, 0)) 1754 { 1755 /* Check if this is a GUI call */ 1756 if (!(Offset & SERVICE_TABLE_TEST)) 1757 { 1758 /* Fail the call */ 1759 Status = STATUS_INVALID_SYSTEM_SERVICE; 1760 goto ExitCall; 1761 } 1762 1763 /* Convert us to a GUI thread -- must wrap in ASM to get new EBP */ 1764 Status = KiConvertToGuiThread(); 1765 1766 /* Reload trap frame and descriptor table pointer from new stack */ 1767 TrapFrame = *(volatile PVOID*)&Thread->TrapFrame; 1768 DescriptorTable = (PVOID)(*(volatile ULONG_PTR*)&Thread->ServiceTable + Offset); 1769 1770 if (!NT_SUCCESS(Status)) 1771 { 1772 /* Set the last error and fail */ 1773 goto ExitCall; 1774 } 1775 1776 /* Validate the system call number again */ 1777 if (Id >= DescriptorTable->Limit) 1778 { 1779 /* Fail the call */ 1780 Status = STATUS_INVALID_SYSTEM_SERVICE; 1781 goto ExitCall; 1782 } 1783 } 1784 1785 /* Check if this is a GUI call */ 1786 if (__builtin_expect(Offset & SERVICE_TABLE_TEST, 0)) 1787 { 1788 /* Get the batch count and flush if necessary */ 1789 if (NtCurrentTeb()->GdiBatchCount) KeGdiFlushUserBatch(); 1790 } 1791 1792 /* Increase system call count */ 1793 KeGetCurrentPrcb()->KeSystemCalls++; 1794 1795 /* FIXME: Increase individual counts on debug systems */ 1796 //KiIncreaseSystemCallCount(DescriptorTable, Id); 1797 1798 /* Get stack bytes */ 1799 StackBytes = DescriptorTable->Number[Id]; 1800 1801 /* Probe caller stack */ 1802 if (__builtin_expect((Arguments < (PVOID)MmUserProbeAddress) && !(KiUserTrap(TrapFrame)), 0)) 1803 { 1804 /* Access violation */ 1805 UNIMPLEMENTED_FATAL(); 1806 } 1807 1808 /* Call pre-service debug hook */ 1809 KiDbgPreServiceHook(SystemCallNumber, Arguments); 1810 1811 /* Get the handler and make the system call */ 1812 Handler = (PVOID)DescriptorTable->Base[Id]; 1813 Status = KiSystemCallTrampoline(Handler, Arguments, StackBytes); 1814 1815 /* Call post-service debug hook */ 1816 Status = KiDbgPostServiceHook(SystemCallNumber, Status); 1817 1818 /* Make sure we're exiting correctly */ 1819 KiExitSystemCallDebugChecks(Id, TrapFrame); 1820 1821 /* Restore the old trap frame */ 1822 ExitCall: 1823 Thread->TrapFrame = (PKTRAP_FRAME)TrapFrame->Edx; 1824 1825 /* Exit from system call */ 1826 KiServiceExit(TrapFrame, Status); 1827 } 1828 1829 VOID 1830 FASTCALL 1831 KiCheckForSListAddress(IN PKTRAP_FRAME TrapFrame) 1832 { 1833 UNIMPLEMENTED; 1834 } 1835 1836 /* 1837 * @implemented 1838 */ 1839 VOID 1840 NTAPI 1841 Kei386EoiHelper(VOID) 1842 { 1843 /* We should never see this call happening */ 1844 KeBugCheck(MISMATCHED_HAL); 1845 } 1846 1847 /* EOF */ 1848