1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/i386/exp.c 5 * PURPOSE: Exception Dispatching and Context<->Trap Frame Conversion 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 * Gregor Anich 8 * Skywing (skywing@valhallalegends.com) 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <ntoskrnl.h> 14 #define NDEBUG 15 #include <debug.h> 16 17 18 /* FUNCTIONS *****************************************************************/ 19 20 CODE_SEG("INIT") 21 VOID 22 NTAPI 23 KeInitExceptions(VOID) 24 { 25 ULONG i; 26 USHORT FlippedSelector; 27 28 /* Loop the IDT */ 29 for (i = 0; i <= MAXIMUM_IDTVECTOR; i++) 30 { 31 /* Save the current Selector */ 32 FlippedSelector = KiIdt[i].Selector; 33 34 /* Flip Selector and Extended Offset */ 35 KiIdt[i].Selector = KiIdt[i].ExtendedOffset; 36 KiIdt[i].ExtendedOffset = FlippedSelector; 37 } 38 } 39 40 ULONG 41 FASTCALL 42 KiUpdateDr7(IN ULONG Dr7) 43 { 44 ULONG DebugMask = KeGetCurrentThread()->Header.DebugActive; 45 46 /* Check if debugging is enabled */ 47 if (DebugMask & DR_MASK(DR7_OVERRIDE_V)) 48 { 49 /* Sanity checks */ 50 ASSERT((DebugMask & DR_REG_MASK) != 0); 51 ASSERT((Dr7 & ~DR7_RESERVED_MASK) == DR7_OVERRIDE_MASK); 52 return 0; 53 } 54 55 /* Return DR7 itself */ 56 return Dr7; 57 } 58 59 BOOLEAN 60 FASTCALL 61 KiRecordDr7(OUT PULONG Dr7Ptr, 62 OUT PULONG DrMask) 63 { 64 ULONG NewMask, Mask; 65 UCHAR Result; 66 67 /* Check if the caller gave us a mask */ 68 if (!DrMask) 69 { 70 /* He didn't, use the one from the thread */ 71 Mask = KeGetCurrentThread()->Header.DebugActive; 72 } 73 else 74 { 75 /* He did, read it */ 76 Mask = *DrMask; 77 } 78 79 /* Sanity check */ 80 ASSERT((*Dr7Ptr & DR7_RESERVED_MASK) == 0); 81 82 /* Check if DR7 is empty */ 83 NewMask = Mask; 84 if (!(*Dr7Ptr)) 85 { 86 /* Assume failure */ 87 Result = FALSE; 88 89 /* Check the DR mask */ 90 NewMask &= ~(DR_MASK(7)); 91 if (NewMask & DR_REG_MASK) 92 { 93 /* Set the active mask */ 94 NewMask |= DR_MASK(DR7_OVERRIDE_V); 95 96 /* Set DR7 override */ 97 *Dr7Ptr |= DR7_OVERRIDE_MASK; 98 } 99 else 100 { 101 /* Sanity check */ 102 ASSERT(NewMask == 0); 103 } 104 } 105 else 106 { 107 /* Check if we have a mask or not */ 108 Result = NewMask ? TRUE: FALSE; 109 110 /* Update the mask to disable debugging */ 111 NewMask &= ~(DR_MASK(DR7_OVERRIDE_V)); 112 NewMask |= DR_MASK(7); 113 } 114 115 /* Check if caller wants the new mask */ 116 if (DrMask) 117 { 118 /* Update it */ 119 *DrMask = NewMask; 120 } 121 else 122 { 123 /* Check if the mask changed */ 124 if (Mask != NewMask) 125 { 126 /* Update it */ 127 KeGetCurrentThread()->Header.DebugActive = (UCHAR)NewMask; 128 } 129 } 130 131 /* Return the result */ 132 return Result; 133 } 134 135 ULONG 136 NTAPI 137 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame) 138 { 139 /* Check if this is user-mode or V86 */ 140 if (KiUserTrap(TrapFrame) || 141 (TrapFrame->EFlags & EFLAGS_V86_MASK)) 142 { 143 /* Return it directly */ 144 return TrapFrame->HardwareEsp; 145 } 146 else 147 { 148 /* Edited frame */ 149 if (!(TrapFrame->SegCs & FRAME_EDITED)) 150 { 151 /* Return edited value */ 152 return TrapFrame->TempEsp; 153 } 154 else 155 { 156 /* Virgin frame, calculate */ 157 return (ULONG)&TrapFrame->HardwareEsp; 158 } 159 } 160 } 161 162 VOID 163 NTAPI 164 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame, 165 IN ULONG Esp) 166 { 167 KIRQL OldIrql; 168 ULONG Previous; 169 170 /* Raise to APC_LEVEL if needed */ 171 OldIrql = KeGetCurrentIrql(); 172 if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); 173 174 /* Get the old ESP */ 175 Previous = KiEspFromTrapFrame(TrapFrame); 176 177 /* Check if this is user-mode or V86 */ 178 if (KiUserTrap(TrapFrame) || 179 (TrapFrame->EFlags & EFLAGS_V86_MASK)) 180 { 181 /* Write it directly */ 182 TrapFrame->HardwareEsp = Esp; 183 } 184 else 185 { 186 /* Don't allow ESP to be lowered, this is illegal */ 187 if (Esp < Previous) KeBugCheckEx(SET_OF_INVALID_CONTEXT, 188 Esp, 189 Previous, 190 (ULONG_PTR)TrapFrame, 191 0); 192 193 /* Create an edit frame, check if it was alrady */ 194 if (!(TrapFrame->SegCs & FRAME_EDITED)) 195 { 196 /* Update the value */ 197 TrapFrame->TempEsp = Esp; 198 } 199 else 200 { 201 /* Check if ESP changed */ 202 if (Previous != Esp) 203 { 204 /* Save CS */ 205 TrapFrame->TempSegCs = TrapFrame->SegCs; 206 TrapFrame->SegCs &= ~FRAME_EDITED; 207 208 /* Save ESP */ 209 TrapFrame->TempEsp = Esp; 210 } 211 } 212 } 213 214 /* Restore IRQL */ 215 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); 216 } 217 218 ULONG 219 NTAPI 220 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame) 221 { 222 /* Check if this was V86 Mode */ 223 if (TrapFrame->EFlags & EFLAGS_V86_MASK) 224 { 225 /* Just return it */ 226 return TrapFrame->HardwareSegSs; 227 } 228 else if (KiUserTrap(TrapFrame)) 229 { 230 /* User mode, return the User SS */ 231 return TrapFrame->HardwareSegSs | RPL_MASK; 232 } 233 else 234 { 235 /* Kernel mode */ 236 return KGDT_R0_DATA; 237 } 238 } 239 240 VOID 241 NTAPI 242 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame, 243 IN ULONG Ss) 244 { 245 /* Remove the high-bits */ 246 Ss &= 0xFFFF; 247 248 /* If this was V86 Mode */ 249 if (TrapFrame->EFlags & EFLAGS_V86_MASK) 250 { 251 /* Just write it */ 252 TrapFrame->HardwareSegSs = Ss; 253 } 254 else if (KiUserTrap(TrapFrame)) 255 { 256 /* Usermode, save the User SS */ 257 TrapFrame->HardwareSegSs = Ss | RPL_MASK; 258 } 259 } 260 261 USHORT 262 NTAPI 263 KiTagWordFnsaveToFxsave(USHORT TagWord) 264 { 265 INT FxTagWord = ~TagWord; 266 267 /* 268 * Empty is now 00, any 2 bits containing 1 mean valid 269 * Now convert the rest (11->0 and the rest to 1) 270 */ 271 FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ 272 FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ 273 FxTagWord = (FxTagWord | (FxTagWord >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ 274 FxTagWord = (FxTagWord | (FxTagWord >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ 275 return FxTagWord; 276 } 277 278 VOID 279 NTAPI 280 Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame) 281 { 282 PKTHREAD Thread; 283 ULONG_PTR Stack; 284 ULONG EFlags; 285 286 /* Get the current thread's stack */ 287 Thread = KeGetCurrentThread(); 288 Stack = (ULONG_PTR)Thread->InitialStack; 289 290 /* Check if we are in V8086 mode */ 291 if (!(TrapFrame->EFlags & EFLAGS_V86_MASK)) 292 { 293 /* Bias the stack for the V86 segments */ 294 Stack -= sizeof(KTRAP_FRAME) - 295 FIELD_OFFSET(KTRAP_FRAME, V86Es); 296 } 297 298 /* Bias the stack for the FPU area */ 299 Stack -= sizeof(FX_SAVE_AREA); 300 301 /* Disable interrupts */ 302 EFlags = __readeflags(); 303 _disable(); 304 305 /* Set new ESP0 value in the TSS */ 306 KeGetPcr()->TSS->Esp0 = Stack; 307 308 /* Restore old interrupt state */ 309 __writeeflags(EFlags); 310 } 311 312 VOID 313 NTAPI 314 KeContextToTrapFrame(IN PCONTEXT Context, 315 IN OUT PKEXCEPTION_FRAME ExceptionFrame, 316 IN OUT PKTRAP_FRAME TrapFrame, 317 IN ULONG ContextFlags, 318 IN KPROCESSOR_MODE PreviousMode) 319 { 320 PFX_SAVE_AREA FxSaveArea; 321 ULONG i; 322 BOOLEAN V86Switch = FALSE; 323 KIRQL OldIrql; 324 ULONG DrMask = 0; 325 326 /* Do this at APC_LEVEL */ 327 OldIrql = KeGetCurrentIrql(); 328 if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); 329 330 /* Start with the basic Registers */ 331 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) 332 { 333 /* Check if we went through a V86 switch */ 334 if ((Context->EFlags & EFLAGS_V86_MASK) != 335 (TrapFrame->EFlags & EFLAGS_V86_MASK)) 336 { 337 /* We did, remember this for later */ 338 V86Switch = TRUE; 339 } 340 341 /* Copy EFLAGS and sanitize them*/ 342 TrapFrame->EFlags = Ke386SanitizeFlags(Context->EFlags, PreviousMode); 343 344 /* Copy EBP and EIP */ 345 TrapFrame->Ebp = Context->Ebp; 346 TrapFrame->Eip = Context->Eip; 347 348 /* Check if we were in V86 Mode */ 349 if (TrapFrame->EFlags & EFLAGS_V86_MASK) 350 { 351 /* Simply copy the CS value */ 352 TrapFrame->SegCs = Context->SegCs; 353 } 354 else 355 { 356 /* We weren't in V86, so sanitize the CS */ 357 TrapFrame->SegCs = Ke386SanitizeSeg(Context->SegCs, PreviousMode); 358 359 /* Don't let it under 8, that's invalid */ 360 if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8)) 361 { 362 /* Force it to User CS */ 363 TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK; 364 } 365 } 366 367 /* Handle SS Specially for validation */ 368 KiSsToTrapFrame(TrapFrame, Context->SegSs); 369 370 /* Write ESP back; take into account Edited Trap Frames */ 371 KiEspToTrapFrame(TrapFrame, Context->Esp); 372 373 /* Handle our V86 Bias if we went through a switch */ 374 if (V86Switch) Ki386AdjustEsp0(TrapFrame); 375 } 376 377 /* Process the Integer Registers */ 378 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) 379 { 380 /* Copy them manually */ 381 TrapFrame->Eax = Context->Eax; 382 TrapFrame->Ebx = Context->Ebx; 383 TrapFrame->Ecx = Context->Ecx; 384 TrapFrame->Edx = Context->Edx; 385 TrapFrame->Esi = Context->Esi; 386 TrapFrame->Edi = Context->Edi; 387 } 388 389 /* Process the Context Segments */ 390 if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) 391 { 392 /* Check if we were in V86 Mode */ 393 if (TrapFrame->EFlags & EFLAGS_V86_MASK) 394 { 395 /* Copy the V86 Segments directly */ 396 TrapFrame->V86Ds = Context->SegDs; 397 TrapFrame->V86Es = Context->SegEs; 398 TrapFrame->V86Fs = Context->SegFs; 399 TrapFrame->V86Gs = Context->SegGs; 400 } 401 else if (!KiUserTrap(TrapFrame)) 402 { 403 /* For kernel mode, write the standard values */ 404 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK; 405 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK; 406 TrapFrame->SegFs = Ke386SanitizeSeg(Context->SegFs, PreviousMode); 407 TrapFrame->SegGs = 0; 408 } 409 else 410 { 411 /* For user mode, return the values directly */ 412 TrapFrame->SegDs = Context->SegDs; 413 TrapFrame->SegEs = Context->SegEs; 414 TrapFrame->SegFs = Context->SegFs; 415 416 /* Handle GS specially */ 417 if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK)) 418 { 419 /* Don't use it, if user */ 420 TrapFrame->SegGs = 0; 421 } 422 else 423 { 424 /* Copy it if kernel */ 425 TrapFrame->SegGs = Context->SegGs; 426 } 427 } 428 } 429 430 /* Handle the extended registers */ 431 if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) == 432 CONTEXT_EXTENDED_REGISTERS) && KiUserTrap(TrapFrame)) 433 { 434 /* Get the FX Area */ 435 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1); 436 437 /* Check if NPX is present */ 438 if (KeI386NpxPresent) 439 { 440 /* Flush the NPX State */ 441 KiFlushNPXState(NULL); 442 443 /* Copy the FX State */ 444 RtlCopyMemory(&FxSaveArea->U.FxArea, 445 &Context->ExtendedRegisters[0], 446 MAXIMUM_SUPPORTED_EXTENSION); 447 448 /* Remove reserved bits from MXCSR */ 449 FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask; 450 451 /* Mask out any invalid flags */ 452 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS); 453 454 /* Check if this is a VDM app */ 455 if (PsGetCurrentProcess()->VdmObjects) 456 { 457 /* Allow the EM flag */ 458 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & 459 (CR0_EM | CR0_MP); 460 } 461 } 462 } 463 464 /* Handle the floating point state */ 465 if (((ContextFlags & CONTEXT_FLOATING_POINT) == 466 CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame)) 467 { 468 /* Get the FX Area */ 469 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1); 470 471 /* Check if NPX is present */ 472 if (KeI386NpxPresent) 473 { 474 /* Flush the NPX State */ 475 KiFlushNPXState(NULL); 476 477 /* Check if we have Fxsr support */ 478 if (KeI386FxsrPresent) 479 { 480 /* Convert the Fn Floating Point state to Fx */ 481 FxSaveArea->U.FxArea.ControlWord = 482 (USHORT)Context->FloatSave.ControlWord; 483 FxSaveArea->U.FxArea.StatusWord = 484 (USHORT)Context->FloatSave.StatusWord; 485 FxSaveArea->U.FxArea.TagWord = 486 KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord); 487 FxSaveArea->U.FxArea.ErrorOpcode = 488 (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF); 489 FxSaveArea->U.FxArea.ErrorOffset = 490 Context->FloatSave.ErrorOffset; 491 FxSaveArea->U.FxArea.ErrorSelector = 492 Context->FloatSave.ErrorSelector & 0xFFFF; 493 FxSaveArea->U.FxArea.DataOffset = 494 Context->FloatSave.DataOffset; 495 FxSaveArea->U.FxArea.DataSelector = 496 Context->FloatSave.DataSelector; 497 498 /* Clear out the Register Area */ 499 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0], 500 SIZE_OF_FX_REGISTERS); 501 502 /* Loop the 8 floating point registers */ 503 for (i = 0; i < 8; i++) 504 { 505 /* Copy from Fn to Fx */ 506 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16), 507 Context->FloatSave.RegisterArea + (i * 10), 508 10); 509 } 510 } 511 else 512 { 513 /* Copy the structure */ 514 FxSaveArea->U.FnArea.ControlWord = Context->FloatSave. 515 ControlWord; 516 FxSaveArea->U.FnArea.StatusWord = Context->FloatSave. 517 StatusWord; 518 FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord; 519 FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave. 520 ErrorOffset; 521 FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave. 522 ErrorSelector; 523 FxSaveArea->U.FnArea.DataOffset = Context->FloatSave. 524 DataOffset; 525 FxSaveArea->U.FnArea.DataSelector = Context->FloatSave. 526 DataSelector; 527 528 /* Loop registers */ 529 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) 530 { 531 /* Copy registers */ 532 FxSaveArea->U.FnArea.RegisterArea[i] = 533 Context->FloatSave.RegisterArea[i]; 534 } 535 } 536 537 /* Mask out any invalid flags */ 538 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS); 539 540 /* Check if this is a VDM app */ 541 if (PsGetCurrentProcess()->VdmObjects) 542 { 543 /* Allow the EM flag */ 544 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & 545 (CR0_EM | CR0_MP); 546 } 547 } 548 else 549 { 550 /* FIXME: Handle FPU Emulation */ 551 //ASSERT(FALSE); 552 UNIMPLEMENTED; 553 } 554 } 555 556 /* Handle the Debug Registers */ 557 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) 558 { 559 /* Copy Dr0 - Dr4 */ 560 TrapFrame->Dr0 = Context->Dr0; 561 TrapFrame->Dr1 = Context->Dr1; 562 TrapFrame->Dr2 = Context->Dr2; 563 TrapFrame->Dr3 = Context->Dr3; 564 565 /* If we're in user-mode */ 566 if (PreviousMode != KernelMode) 567 { 568 /* Make sure, no Dr address is above user space */ 569 if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0; 570 if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0; 571 if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0; 572 if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0; 573 } 574 575 /* Now sanitize and save DR6 */ 576 TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL; 577 578 /* Update the Dr active mask */ 579 if (TrapFrame->Dr0) DrMask |= DR_MASK(0); 580 if (TrapFrame->Dr1) DrMask |= DR_MASK(1); 581 if (TrapFrame->Dr2) DrMask |= DR_MASK(2); 582 if (TrapFrame->Dr3) DrMask |= DR_MASK(3); 583 if (TrapFrame->Dr6) DrMask |= DR_MASK(6); 584 585 /* Sanitize and save DR7 */ 586 TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL; 587 KiRecordDr7(&TrapFrame->Dr7, &DrMask); 588 589 /* If we're in user-mode */ 590 if (PreviousMode != KernelMode) 591 { 592 /* Save the mask */ 593 KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask; 594 } 595 } 596 597 /* Check if thread has IOPL and force it enabled if so */ 598 if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL; 599 600 /* Restore IRQL */ 601 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); 602 } 603 604 VOID 605 NTAPI 606 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, 607 IN PKEXCEPTION_FRAME ExceptionFrame, 608 IN OUT PCONTEXT Context) 609 { 610 PFX_SAVE_AREA FxSaveArea; 611 struct _AlignHack 612 { 613 UCHAR Hack[15]; 614 FLOATING_SAVE_AREA UnalignedArea; 615 } FloatSaveBuffer; 616 FLOATING_SAVE_AREA *FloatSaveArea; 617 KIRQL OldIrql; 618 ULONG i; 619 620 /* Do this at APC_LEVEL */ 621 OldIrql = KeGetCurrentIrql(); 622 if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); 623 624 /* Start with the Control flags */ 625 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) 626 { 627 /* EBP, EIP and EFLAGS */ 628 Context->Ebp = TrapFrame->Ebp; 629 Context->Eip = TrapFrame->Eip; 630 Context->EFlags = TrapFrame->EFlags; 631 632 /* Return the correct CS */ 633 if (!(TrapFrame->SegCs & FRAME_EDITED) && 634 !(TrapFrame->EFlags & EFLAGS_V86_MASK)) 635 { 636 /* Get it from the Temp location */ 637 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF; 638 } 639 else 640 { 641 /* Return it directly */ 642 Context->SegCs = TrapFrame->SegCs & 0xFFFF; 643 } 644 645 /* Get the Ss and ESP */ 646 Context->SegSs = KiSsFromTrapFrame(TrapFrame); 647 Context->Esp = KiEspFromTrapFrame(TrapFrame); 648 } 649 650 /* Handle the Segments */ 651 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) 652 { 653 /* Do V86 Mode first */ 654 if (TrapFrame->EFlags & EFLAGS_V86_MASK) 655 { 656 /* Return from the V86 location */ 657 Context->SegGs = TrapFrame->V86Gs & 0xFFFF; 658 Context->SegFs = TrapFrame->V86Fs & 0xFFFF; 659 Context->SegEs = TrapFrame->V86Es & 0xFFFF; 660 Context->SegDs = TrapFrame->V86Ds & 0xFFFF; 661 } 662 else 663 { 664 /* Check if this was a Kernel Trap */ 665 if (TrapFrame->SegCs == KGDT_R0_CODE) 666 { 667 /* Set valid selectors */ 668 TrapFrame->SegGs = 0; 669 TrapFrame->SegFs = KGDT_R0_PCR; 670 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK; 671 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK; 672 } 673 674 /* Return the segments */ 675 Context->SegGs = TrapFrame->SegGs & 0xFFFF; 676 Context->SegFs = TrapFrame->SegFs & 0xFFFF; 677 Context->SegEs = TrapFrame->SegEs & 0xFFFF; 678 Context->SegDs = TrapFrame->SegDs & 0xFFFF; 679 } 680 } 681 682 /* Handle the simple registers */ 683 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) 684 { 685 /* Return them directly */ 686 Context->Eax = TrapFrame->Eax; 687 Context->Ebx = TrapFrame->Ebx; 688 Context->Ecx = TrapFrame->Ecx; 689 Context->Edx = TrapFrame->Edx; 690 Context->Esi = TrapFrame->Esi; 691 Context->Edi = TrapFrame->Edi; 692 } 693 694 /* Handle extended registers */ 695 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == 696 CONTEXT_EXTENDED_REGISTERS) && KiUserTrap(TrapFrame)) 697 { 698 /* Get the FX Save Area */ 699 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1); 700 701 /* Make sure NPX is present */ 702 if (KeI386NpxPresent) 703 { 704 /* Flush the NPX State */ 705 KiFlushNPXState(NULL); 706 707 /* Copy the registers */ 708 RtlCopyMemory(&Context->ExtendedRegisters[0], 709 &FxSaveArea->U.FxArea, 710 MAXIMUM_SUPPORTED_EXTENSION); 711 } 712 } 713 714 /* Handle Floating Point */ 715 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) == 716 CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame)) 717 { 718 /* Get the FX Save Area */ 719 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1); 720 721 /* Make sure we have an NPX */ 722 if (KeI386NpxPresent) 723 { 724 /* Check if we have Fxsr support */ 725 if (KeI386FxsrPresent) 726 { 727 /* Align the floating area to 16-bytes */ 728 FloatSaveArea = (FLOATING_SAVE_AREA*) 729 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF); 730 731 /* Get the State */ 732 KiFlushNPXState(FloatSaveArea); 733 } 734 else 735 { 736 /* We don't, use the FN area and flush the NPX State */ 737 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea; 738 KiFlushNPXState(NULL); 739 } 740 741 /* Copy structure */ 742 Context->FloatSave.ControlWord = FloatSaveArea->ControlWord; 743 Context->FloatSave.StatusWord = FloatSaveArea->StatusWord; 744 Context->FloatSave.TagWord = FloatSaveArea->TagWord; 745 Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset; 746 Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector; 747 Context->FloatSave.DataOffset = FloatSaveArea->DataOffset; 748 Context->FloatSave.DataSelector = FloatSaveArea->DataSelector; 749 Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState; 750 751 /* Loop registers */ 752 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) 753 { 754 /* Copy them */ 755 Context->FloatSave.RegisterArea[i] = 756 FloatSaveArea->RegisterArea[i]; 757 } 758 } 759 else 760 { 761 /* FIXME: Handle Emulation */ 762 ASSERT(FALSE); 763 } 764 } 765 766 /* Handle debug registers */ 767 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == 768 CONTEXT_DEBUG_REGISTERS) 769 { 770 /* Make sure DR7 is valid */ 771 if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK) 772 { 773 /* Copy the debug registers */ 774 Context->Dr0 = TrapFrame->Dr0; 775 Context->Dr1 = TrapFrame->Dr1; 776 Context->Dr2 = TrapFrame->Dr2; 777 Context->Dr3 = TrapFrame->Dr3; 778 Context->Dr6 = TrapFrame->Dr6; 779 780 /* Update DR7 */ 781 Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7); 782 } 783 else 784 { 785 /* Otherwise clear DR registers */ 786 Context->Dr0 = 787 Context->Dr1 = 788 Context->Dr2 = 789 Context->Dr3 = 790 Context->Dr6 = 791 Context->Dr7 = 0; 792 } 793 } 794 795 /* Restore IRQL */ 796 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); 797 } 798 799 BOOLEAN 800 FASTCALL 801 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL) 802 { 803 ULONG Eip; 804 PKTRAP_FRAME TrapFrame = TrapInformation; 805 VOID NTAPI ExpInterlockedPopEntrySListFault(VOID); 806 807 /* Don't do anything if we didn't get a trap frame */ 808 if (!TrapInformation) return FALSE; 809 810 /* Check where we came from */ 811 switch (TrapFrame->SegCs) 812 { 813 /* Kernel mode */ 814 case KGDT_R0_CODE: 815 816 /* Allow S-LIST Routine to fail */ 817 Eip = (ULONG)&ExpInterlockedPopEntrySListFault; 818 break; 819 820 /* User code */ 821 case KGDT_R3_CODE | RPL_MASK: 822 823 /* Allow S-LIST Routine to fail */ 824 //Eip = (ULONG)KeUserPopEntrySListFault; 825 Eip = 0; 826 break; 827 828 default: 829 830 /* Anything else gets a bugcheck */ 831 Eip = 0; 832 } 833 834 /* Return TRUE if we want to keep the system up */ 835 return (TrapFrame->Eip == Eip) ? TRUE : FALSE; 836 } 837 838 VOID 839 NTAPI 840 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, 841 IN PKEXCEPTION_FRAME ExceptionFrame, 842 IN PKTRAP_FRAME TrapFrame, 843 IN KPROCESSOR_MODE PreviousMode, 844 IN BOOLEAN FirstChance) 845 { 846 CONTEXT Context; 847 EXCEPTION_RECORD LocalExceptRecord; 848 849 /* Increase number of Exception Dispatches */ 850 KeGetCurrentPrcb()->KeExceptionDispatchCount++; 851 852 /* Set the context flags */ 853 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 854 855 /* Check if User Mode or if the kernel debugger is enabled */ 856 if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock)) 857 { 858 /* Add the FPU Flag */ 859 Context.ContextFlags |= CONTEXT_FLOATING_POINT; 860 861 /* Check for NPX Support */ 862 if (KeI386FxsrPresent) 863 { 864 /* Save those too */ 865 Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS; 866 } 867 } 868 869 /* Get a Context */ 870 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context); 871 872 /* Look at our exception code */ 873 switch (ExceptionRecord->ExceptionCode) 874 { 875 /* Breakpoint */ 876 case STATUS_BREAKPOINT: 877 878 /* Decrement EIP by one */ 879 Context.Eip--; 880 break; 881 882 /* Internal exception */ 883 case KI_EXCEPTION_ACCESS_VIOLATION: 884 885 /* Set correct code */ 886 ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION; 887 if (PreviousMode == UserMode) 888 { 889 /* FIXME: Handle no execute */ 890 } 891 break; 892 } 893 894 /* Sanity check */ 895 ASSERT(!((PreviousMode == KernelMode) && 896 (Context.EFlags & EFLAGS_V86_MASK))); 897 898 /* Handle kernel-mode first, it's simpler */ 899 if (PreviousMode == KernelMode) 900 { 901 /* Check if this is a first-chance exception */ 902 if (FirstChance != FALSE) 903 { 904 /* Break into the debugger for the first time */ 905 if (KiDebugRoutine(TrapFrame, 906 ExceptionFrame, 907 ExceptionRecord, 908 &Context, 909 PreviousMode, 910 FALSE)) 911 { 912 /* Exception was handled */ 913 goto Handled; 914 } 915 916 /* If the Debugger couldn't handle it, dispatch the exception */ 917 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled; 918 } 919 920 /* This is a second-chance exception, only for the debugger */ 921 if (KiDebugRoutine(TrapFrame, 922 ExceptionFrame, 923 ExceptionRecord, 924 &Context, 925 PreviousMode, 926 TRUE)) 927 { 928 /* Exception was handled */ 929 goto Handled; 930 } 931 932 /* Third strike; you're out */ 933 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 934 ExceptionRecord->ExceptionCode, 935 (ULONG_PTR)ExceptionRecord->ExceptionAddress, 936 (ULONG_PTR)TrapFrame, 937 0); 938 } 939 else 940 { 941 /* User mode exception, was it first-chance? */ 942 if (FirstChance) 943 { 944 /* 945 * Break into the kernel debugger unless a user mode debugger 946 * is present or user mode exceptions are ignored, except if this 947 * is a debug service which we must always pass to KD 948 */ 949 if ((!(PsGetCurrentProcess()->DebugPort) && 950 !(KdIgnoreUmExceptions)) || 951 (KdIsThisAKdTrap(ExceptionRecord, 952 &Context, 953 PreviousMode))) 954 { 955 /* Call the kernel debugger */ 956 if (KiDebugRoutine(TrapFrame, 957 ExceptionFrame, 958 ExceptionRecord, 959 &Context, 960 PreviousMode, 961 FALSE)) 962 { 963 /* Exception was handled */ 964 goto Handled; 965 } 966 } 967 968 /* Forward exception to user mode debugger */ 969 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return; 970 971 /* Set up the user-stack */ 972 DispatchToUser: 973 _SEH2_TRY 974 { 975 ULONG Size; 976 ULONG_PTR Stack, NewStack; 977 978 /* Make sure we have a valid SS and that this isn't V86 mode */ 979 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) || 980 (TrapFrame->EFlags & EFLAGS_V86_MASK)) 981 { 982 /* Raise an exception instead */ 983 LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION; 984 LocalExceptRecord.ExceptionFlags = 0; 985 LocalExceptRecord.NumberParameters = 0; 986 RtlRaiseException(&LocalExceptRecord); 987 } 988 989 /* Align context size and get stack pointer */ 990 Size = (sizeof(CONTEXT) + 3) & ~3; 991 Stack = (Context.Esp & ~3) - Size; 992 993 /* Probe stack and copy Context */ 994 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG)); 995 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT)); 996 997 /* Align exception record size and get stack pointer */ 998 Size = (sizeof(EXCEPTION_RECORD) - 999 (EXCEPTION_MAXIMUM_PARAMETERS - 1000 ExceptionRecord->NumberParameters) * 1001 sizeof(ULONG) + 3) & ~3; 1002 NewStack = Stack - Size; 1003 1004 /* Probe stack and copy exception record */ 1005 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)), 1006 Size + 2 * sizeof(ULONG_PTR), 1007 sizeof(ULONG)); 1008 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size); 1009 1010 /* Now write the two params for the user-mode dispatcher */ 1011 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack; 1012 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack; 1013 1014 /* Set new Stack Pointer */ 1015 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA); 1016 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR)); 1017 1018 /* Force correct segments */ 1019 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode); 1020 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode); 1021 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode); 1022 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, PreviousMode); 1023 TrapFrame->SegGs = 0; 1024 1025 /* Set EIP to the User-mode Dispatcher */ 1026 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher; 1027 1028 /* Dispatch exception to user-mode */ 1029 _SEH2_YIELD(return); 1030 } 1031 _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER)) 1032 { 1033 /* Check if we got a stack overflow and raise that instead */ 1034 if ((NTSTATUS)LocalExceptRecord.ExceptionCode == 1035 STATUS_STACK_OVERFLOW) 1036 { 1037 /* Copy the exception address and record */ 1038 LocalExceptRecord.ExceptionAddress = 1039 ExceptionRecord->ExceptionAddress; 1040 RtlCopyMemory(ExceptionRecord, 1041 (PVOID)&LocalExceptRecord, 1042 sizeof(EXCEPTION_RECORD)); 1043 1044 /* Do the exception again */ 1045 _SEH2_YIELD(goto DispatchToUser); 1046 } 1047 } 1048 _SEH2_END; 1049 1050 DPRINT("First chance exception in %.16s, ExceptionCode: %lx, ExceptionAddress: %p, P0: %lx, P1: %lx\n", 1051 PsGetCurrentProcess()->ImageFileName, 1052 ExceptionRecord->ExceptionCode, 1053 ExceptionRecord->ExceptionAddress, 1054 ExceptionRecord->ExceptionInformation[0], 1055 ExceptionRecord->ExceptionInformation[1]); 1056 } 1057 1058 /* Try second chance */ 1059 if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) 1060 { 1061 /* Handled, get out */ 1062 return; 1063 } 1064 else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) 1065 { 1066 /* Handled, get out */ 1067 return; 1068 } 1069 1070 /* 3rd strike, kill the process */ 1071 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %p, BaseAddress: %p, P0: %lx, P1: %lx\n", 1072 PsGetCurrentProcess()->ImageFileName, 1073 ExceptionRecord->ExceptionCode, 1074 ExceptionRecord->ExceptionAddress, 1075 PsGetCurrentProcess()->SectionBaseAddress, 1076 ExceptionRecord->ExceptionInformation[0], 1077 ExceptionRecord->ExceptionInformation[1]); 1078 1079 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode); 1080 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 1081 ExceptionRecord->ExceptionCode, 1082 (ULONG_PTR)ExceptionRecord->ExceptionAddress, 1083 (ULONG_PTR)TrapFrame, 1084 0); 1085 } 1086 1087 Handled: 1088 /* Convert the context back into Trap/Exception Frames */ 1089 KeContextToTrapFrame(&Context, 1090 ExceptionFrame, 1091 TrapFrame, 1092 Context.ContextFlags, 1093 PreviousMode); 1094 return; 1095 } 1096 1097 DECLSPEC_NORETURN 1098 VOID 1099 NTAPI 1100 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code, 1101 IN ULONG Flags, 1102 IN ULONG_PTR Address, 1103 IN ULONG ParameterCount, 1104 IN ULONG_PTR Parameter1, 1105 IN ULONG_PTR Parameter2, 1106 IN ULONG_PTR Parameter3, 1107 IN PKTRAP_FRAME TrapFrame) 1108 { 1109 EXCEPTION_RECORD ExceptionRecord; 1110 1111 /* Build the exception record */ 1112 ExceptionRecord.ExceptionCode = Code; 1113 ExceptionRecord.ExceptionFlags = Flags; 1114 ExceptionRecord.ExceptionRecord = NULL; 1115 ExceptionRecord.ExceptionAddress = (PVOID)Address; 1116 ExceptionRecord.NumberParameters = ParameterCount; 1117 if (ParameterCount) 1118 { 1119 /* Copy extra parameters */ 1120 ExceptionRecord.ExceptionInformation[0] = Parameter1; 1121 ExceptionRecord.ExceptionInformation[1] = Parameter2; 1122 ExceptionRecord.ExceptionInformation[2] = Parameter3; 1123 } 1124 1125 /* Now go dispatch the exception */ 1126 KiDispatchException(&ExceptionRecord, 1127 NULL, 1128 TrapFrame, 1129 TrapFrame->EFlags & EFLAGS_V86_MASK ? 1130 -1 : KiUserTrap(TrapFrame), 1131 TRUE); 1132 1133 /* Return from this trap */ 1134 KiEoiHelper(TrapFrame); 1135 } 1136 1137 DECLSPEC_NORETURN 1138 VOID 1139 FASTCALL 1140 KiSystemFatalException(IN ULONG ExceptionCode, 1141 IN PKTRAP_FRAME TrapFrame) 1142 { 1143 /* Bugcheck the system */ 1144 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP, 1145 ExceptionCode, 1146 0, 1147 0, 1148 0, 1149 TrapFrame); 1150 } 1151 1152 /* PUBLIC FUNCTIONS ***********************************************************/ 1153 1154 /* 1155 * @implemented 1156 */ 1157 NTSTATUS 1158 NTAPI 1159 KeRaiseUserException(IN NTSTATUS ExceptionCode) 1160 { 1161 ULONG OldEip; 1162 PTEB Teb = KeGetCurrentThread()->Teb; 1163 PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame; 1164 1165 /* Make sure we can access the TEB */ 1166 _SEH2_TRY 1167 { 1168 /* Set the exception code */ 1169 Teb->ExceptionCode = ExceptionCode; 1170 } 1171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1172 { 1173 /* Return the exception code */ 1174 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1175 } 1176 _SEH2_END; 1177 1178 /* Get the old EIP */ 1179 OldEip = TrapFrame->Eip; 1180 1181 /* Change it to the user-mode dispatcher */ 1182 TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher; 1183 1184 /* Return the old EIP */ 1185 return (NTSTATUS)OldEip; 1186 } 1187