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 /* Flush the NPX State */ 438 KiFlushNPXState(NULL); 439 440 /* Copy the FX State */ 441 RtlCopyMemory(&FxSaveArea->U.FxArea, 442 &Context->ExtendedRegisters[0], 443 MAXIMUM_SUPPORTED_EXTENSION); 444 445 /* Remove reserved bits from MXCSR */ 446 FxSaveArea->U.FxArea.MXCsr &= KiMXCsrMask; 447 448 /* Mask out any invalid flags */ 449 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS); 450 451 /* Check if this is a VDM app */ 452 if (PsGetCurrentProcess()->VdmObjects) 453 { 454 /* Allow the EM flag */ 455 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & (CR0_EM | CR0_MP); 456 } 457 } 458 459 /* Handle the floating point state */ 460 if (((ContextFlags & CONTEXT_FLOATING_POINT) == 461 CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame)) 462 { 463 /* Get the FX Area */ 464 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1); 465 466 /* Flush the NPX State */ 467 KiFlushNPXState(NULL); 468 469 /* Check if we have Fxsr support */ 470 if (KeI386FxsrPresent) 471 { 472 /* Convert the Fn Floating Point state to Fx */ 473 FxSaveArea->U.FxArea.ControlWord = (USHORT)Context->FloatSave.ControlWord; 474 FxSaveArea->U.FxArea.StatusWord = (USHORT)Context->FloatSave.StatusWord; 475 FxSaveArea->U.FxArea.TagWord = 476 KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord); 477 FxSaveArea->U.FxArea.ErrorOpcode = 478 (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF); 479 FxSaveArea->U.FxArea.ErrorOffset = Context->FloatSave.ErrorOffset; 480 FxSaveArea->U.FxArea.ErrorSelector = Context->FloatSave.ErrorSelector & 0xFFFF; 481 FxSaveArea->U.FxArea.DataOffset = Context->FloatSave.DataOffset; 482 FxSaveArea->U.FxArea.DataSelector = Context->FloatSave.DataSelector; 483 484 /* Clear out the Register Area */ 485 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0], SIZE_OF_FX_REGISTERS); 486 487 /* Loop the 8 floating point registers */ 488 for (i = 0; i < 8; i++) 489 { 490 /* Copy from Fn to Fx */ 491 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16), 492 Context->FloatSave.RegisterArea + (i * 10), 493 10); 494 } 495 } 496 else 497 { 498 /* Copy the structure */ 499 FxSaveArea->U.FnArea.ControlWord = Context->FloatSave.ControlWord; 500 FxSaveArea->U.FnArea.StatusWord = Context->FloatSave.StatusWord; 501 FxSaveArea->U.FnArea.TagWord = Context->FloatSave.TagWord; 502 FxSaveArea->U.FnArea.ErrorOffset = Context->FloatSave.ErrorOffset; 503 FxSaveArea->U.FnArea.ErrorSelector = Context->FloatSave.ErrorSelector; 504 FxSaveArea->U.FnArea.DataOffset = Context->FloatSave.DataOffset; 505 FxSaveArea->U.FnArea.DataSelector = Context->FloatSave.DataSelector; 506 507 /* Loop registers */ 508 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) 509 { 510 /* Copy registers */ 511 FxSaveArea->U.FnArea.RegisterArea[i] = Context->FloatSave.RegisterArea[i]; 512 } 513 } 514 515 /* Mask out any invalid flags */ 516 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS); 517 518 /* Check if this is a VDM app */ 519 if (PsGetCurrentProcess()->VdmObjects) 520 { 521 /* Allow the EM flag */ 522 FxSaveArea->Cr0NpxState |= Context->FloatSave.Cr0NpxState & (CR0_EM | CR0_MP); 523 } 524 } 525 526 /* Handle the Debug Registers */ 527 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) 528 { 529 /* Copy Dr0 - Dr4 */ 530 TrapFrame->Dr0 = Context->Dr0; 531 TrapFrame->Dr1 = Context->Dr1; 532 TrapFrame->Dr2 = Context->Dr2; 533 TrapFrame->Dr3 = Context->Dr3; 534 535 /* If we're in user-mode */ 536 if (PreviousMode != KernelMode) 537 { 538 /* Make sure, no Dr address is above user space */ 539 if (Context->Dr0 > (ULONG)MmHighestUserAddress) TrapFrame->Dr0 = 0; 540 if (Context->Dr1 > (ULONG)MmHighestUserAddress) TrapFrame->Dr1 = 0; 541 if (Context->Dr2 > (ULONG)MmHighestUserAddress) TrapFrame->Dr2 = 0; 542 if (Context->Dr3 > (ULONG)MmHighestUserAddress) TrapFrame->Dr3 = 0; 543 } 544 545 /* Now sanitize and save DR6 */ 546 TrapFrame->Dr6 = Context->Dr6 & DR6_LEGAL; 547 548 /* Update the Dr active mask */ 549 if (TrapFrame->Dr0) DrMask |= DR_MASK(0); 550 if (TrapFrame->Dr1) DrMask |= DR_MASK(1); 551 if (TrapFrame->Dr2) DrMask |= DR_MASK(2); 552 if (TrapFrame->Dr3) DrMask |= DR_MASK(3); 553 if (TrapFrame->Dr6) DrMask |= DR_MASK(6); 554 555 /* Sanitize and save DR7 */ 556 TrapFrame->Dr7 = Context->Dr7 & DR7_LEGAL; 557 KiRecordDr7(&TrapFrame->Dr7, &DrMask); 558 559 /* If we're in user-mode */ 560 if (PreviousMode != KernelMode) 561 { 562 /* Save the mask */ 563 KeGetCurrentThread()->Header.DebugActive = (UCHAR)DrMask; 564 } 565 } 566 567 /* Check if thread has IOPL and force it enabled if so */ 568 if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL; 569 570 /* Restore IRQL */ 571 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); 572 } 573 574 VOID 575 NTAPI 576 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, 577 IN PKEXCEPTION_FRAME ExceptionFrame, 578 IN OUT PCONTEXT Context) 579 { 580 PFX_SAVE_AREA FxSaveArea; 581 struct _AlignHack 582 { 583 UCHAR Hack[15]; 584 FLOATING_SAVE_AREA UnalignedArea; 585 } FloatSaveBuffer; 586 FLOATING_SAVE_AREA *FloatSaveArea; 587 KIRQL OldIrql; 588 ULONG i; 589 590 /* Do this at APC_LEVEL */ 591 OldIrql = KeGetCurrentIrql(); 592 if (OldIrql < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql); 593 594 /* Start with the Control flags */ 595 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) 596 { 597 /* EBP, EIP and EFLAGS */ 598 Context->Ebp = TrapFrame->Ebp; 599 Context->Eip = TrapFrame->Eip; 600 Context->EFlags = TrapFrame->EFlags; 601 602 /* Return the correct CS */ 603 if (!(TrapFrame->SegCs & FRAME_EDITED) && 604 !(TrapFrame->EFlags & EFLAGS_V86_MASK)) 605 { 606 /* Get it from the Temp location */ 607 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF; 608 } 609 else 610 { 611 /* Return it directly */ 612 Context->SegCs = TrapFrame->SegCs & 0xFFFF; 613 } 614 615 /* Get the Ss and ESP */ 616 Context->SegSs = KiSsFromTrapFrame(TrapFrame); 617 Context->Esp = KiEspFromTrapFrame(TrapFrame); 618 } 619 620 /* Handle the Segments */ 621 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) 622 { 623 /* Do V86 Mode first */ 624 if (TrapFrame->EFlags & EFLAGS_V86_MASK) 625 { 626 /* Return from the V86 location */ 627 Context->SegGs = TrapFrame->V86Gs & 0xFFFF; 628 Context->SegFs = TrapFrame->V86Fs & 0xFFFF; 629 Context->SegEs = TrapFrame->V86Es & 0xFFFF; 630 Context->SegDs = TrapFrame->V86Ds & 0xFFFF; 631 } 632 else 633 { 634 /* Check if this was a Kernel Trap */ 635 if (TrapFrame->SegCs == KGDT_R0_CODE) 636 { 637 /* Set valid selectors */ 638 TrapFrame->SegGs = 0; 639 TrapFrame->SegFs = KGDT_R0_PCR; 640 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK; 641 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK; 642 } 643 644 /* Return the segments */ 645 Context->SegGs = TrapFrame->SegGs & 0xFFFF; 646 Context->SegFs = TrapFrame->SegFs & 0xFFFF; 647 Context->SegEs = TrapFrame->SegEs & 0xFFFF; 648 Context->SegDs = TrapFrame->SegDs & 0xFFFF; 649 } 650 } 651 652 /* Handle the simple registers */ 653 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) 654 { 655 /* Return them directly */ 656 Context->Eax = TrapFrame->Eax; 657 Context->Ebx = TrapFrame->Ebx; 658 Context->Ecx = TrapFrame->Ecx; 659 Context->Edx = TrapFrame->Edx; 660 Context->Esi = TrapFrame->Esi; 661 Context->Edi = TrapFrame->Edi; 662 } 663 664 /* Handle extended registers */ 665 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == 666 CONTEXT_EXTENDED_REGISTERS) && KiUserTrap(TrapFrame)) 667 { 668 /* Get the FX Save Area */ 669 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1); 670 671 /* Flush the NPX State */ 672 KiFlushNPXState(NULL); 673 674 /* Copy the registers */ 675 RtlCopyMemory(&Context->ExtendedRegisters[0], 676 &FxSaveArea->U.FxArea, 677 MAXIMUM_SUPPORTED_EXTENSION); 678 } 679 680 /* Handle Floating Point */ 681 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) == 682 CONTEXT_FLOATING_POINT) && KiUserTrap(TrapFrame)) 683 { 684 /* Get the FX Save Area */ 685 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1); 686 687 /* Check if we have Fxsr support */ 688 if (KeI386FxsrPresent) 689 { 690 /* Align the floating area to 16-bytes */ 691 FloatSaveArea = (FLOATING_SAVE_AREA*)((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF); 692 693 /* Get the State */ 694 KiFlushNPXState(FloatSaveArea); 695 } 696 else 697 { 698 /* We don't, use the FN area and flush the NPX State */ 699 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea; 700 KiFlushNPXState(NULL); 701 } 702 703 /* Copy structure */ 704 Context->FloatSave.ControlWord = FloatSaveArea->ControlWord; 705 Context->FloatSave.StatusWord = FloatSaveArea->StatusWord; 706 Context->FloatSave.TagWord = FloatSaveArea->TagWord; 707 Context->FloatSave.ErrorOffset = FloatSaveArea->ErrorOffset; 708 Context->FloatSave.ErrorSelector = FloatSaveArea->ErrorSelector; 709 Context->FloatSave.DataOffset = FloatSaveArea->DataOffset; 710 Context->FloatSave.DataSelector = FloatSaveArea->DataSelector; 711 Context->FloatSave.Cr0NpxState = FxSaveArea->Cr0NpxState; 712 713 /* Loop registers */ 714 for (i = 0; i < SIZE_OF_80387_REGISTERS; i++) 715 { 716 /* Copy them */ 717 Context->FloatSave.RegisterArea[i] = FloatSaveArea->RegisterArea[i]; 718 } 719 } 720 721 /* Handle debug registers */ 722 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == 723 CONTEXT_DEBUG_REGISTERS) 724 { 725 /* Make sure DR7 is valid */ 726 if (TrapFrame->Dr7 & ~DR7_RESERVED_MASK) 727 { 728 /* Copy the debug registers */ 729 Context->Dr0 = TrapFrame->Dr0; 730 Context->Dr1 = TrapFrame->Dr1; 731 Context->Dr2 = TrapFrame->Dr2; 732 Context->Dr3 = TrapFrame->Dr3; 733 Context->Dr6 = TrapFrame->Dr6; 734 735 /* Update DR7 */ 736 Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7); 737 } 738 else 739 { 740 /* Otherwise clear DR registers */ 741 Context->Dr0 = 742 Context->Dr1 = 743 Context->Dr2 = 744 Context->Dr3 = 745 Context->Dr6 = 746 Context->Dr7 = 0; 747 } 748 } 749 750 /* Restore IRQL */ 751 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql); 752 } 753 754 BOOLEAN 755 FASTCALL 756 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL) 757 { 758 ULONG Eip; 759 PKTRAP_FRAME TrapFrame = TrapInformation; 760 VOID NTAPI ExpInterlockedPopEntrySListFault(VOID); 761 762 /* Don't do anything if we didn't get a trap frame */ 763 if (!TrapInformation) return FALSE; 764 765 /* Check where we came from */ 766 switch (TrapFrame->SegCs) 767 { 768 /* Kernel mode */ 769 case KGDT_R0_CODE: 770 771 /* Allow S-LIST Routine to fail */ 772 Eip = (ULONG)&ExpInterlockedPopEntrySListFault; 773 break; 774 775 /* User code */ 776 case KGDT_R3_CODE | RPL_MASK: 777 778 /* Allow S-LIST Routine to fail */ 779 //Eip = (ULONG)KeUserPopEntrySListFault; 780 Eip = 0; 781 break; 782 783 default: 784 785 /* Anything else gets a bugcheck */ 786 Eip = 0; 787 } 788 789 /* Return TRUE if we want to keep the system up */ 790 return (TrapFrame->Eip == Eip) ? TRUE : FALSE; 791 } 792 793 VOID 794 NTAPI 795 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, 796 IN PKEXCEPTION_FRAME ExceptionFrame, 797 IN PKTRAP_FRAME TrapFrame, 798 IN KPROCESSOR_MODE PreviousMode, 799 IN BOOLEAN FirstChance) 800 { 801 CONTEXT Context; 802 EXCEPTION_RECORD LocalExceptRecord; 803 804 /* Increase number of Exception Dispatches */ 805 KeGetCurrentPrcb()->KeExceptionDispatchCount++; 806 807 /* Set the context flags */ 808 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 809 810 /* Check if User Mode or if the kernel debugger is enabled */ 811 if ((PreviousMode == UserMode) || (KeGetPcr()->KdVersionBlock)) 812 { 813 /* Add the FPU Flag */ 814 Context.ContextFlags |= CONTEXT_FLOATING_POINT; 815 816 /* Check for NPX Support */ 817 if (KeI386FxsrPresent) 818 { 819 /* Save those too */ 820 Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS; 821 } 822 } 823 824 /* Get a Context */ 825 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context); 826 827 /* Look at our exception code */ 828 switch (ExceptionRecord->ExceptionCode) 829 { 830 /* Breakpoint */ 831 case STATUS_BREAKPOINT: 832 833 /* Decrement EIP by one */ 834 Context.Eip--; 835 break; 836 837 /* Internal exception */ 838 case KI_EXCEPTION_ACCESS_VIOLATION: 839 840 /* Set correct code */ 841 ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION; 842 if (PreviousMode == UserMode) 843 { 844 /* FIXME: Handle no execute */ 845 } 846 break; 847 } 848 849 /* Sanity check */ 850 ASSERT(!((PreviousMode == KernelMode) && 851 (Context.EFlags & EFLAGS_V86_MASK))); 852 853 /* Handle kernel-mode first, it's simpler */ 854 if (PreviousMode == KernelMode) 855 { 856 /* Check if this is a first-chance exception */ 857 if (FirstChance != FALSE) 858 { 859 /* Break into the debugger for the first time */ 860 if (KiDebugRoutine(TrapFrame, 861 ExceptionFrame, 862 ExceptionRecord, 863 &Context, 864 PreviousMode, 865 FALSE)) 866 { 867 /* Exception was handled */ 868 goto Handled; 869 } 870 871 /* If the Debugger couldn't handle it, dispatch the exception */ 872 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled; 873 } 874 875 /* This is a second-chance exception, only for the debugger */ 876 if (KiDebugRoutine(TrapFrame, 877 ExceptionFrame, 878 ExceptionRecord, 879 &Context, 880 PreviousMode, 881 TRUE)) 882 { 883 /* Exception was handled */ 884 goto Handled; 885 } 886 887 /* Third strike; you're out */ 888 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 889 ExceptionRecord->ExceptionCode, 890 (ULONG_PTR)ExceptionRecord->ExceptionAddress, 891 (ULONG_PTR)TrapFrame, 892 0); 893 } 894 else 895 { 896 /* User mode exception, was it first-chance? */ 897 if (FirstChance) 898 { 899 /* 900 * Break into the kernel debugger unless a user mode debugger 901 * is present or user mode exceptions are ignored, except if this 902 * is a debug service which we must always pass to KD 903 */ 904 if ((!(PsGetCurrentProcess()->DebugPort) && 905 !(KdIgnoreUmExceptions)) || 906 (KdIsThisAKdTrap(ExceptionRecord, 907 &Context, 908 PreviousMode))) 909 { 910 /* Call the kernel debugger */ 911 if (KiDebugRoutine(TrapFrame, 912 ExceptionFrame, 913 ExceptionRecord, 914 &Context, 915 PreviousMode, 916 FALSE)) 917 { 918 /* Exception was handled */ 919 goto Handled; 920 } 921 } 922 923 /* Forward exception to user mode debugger */ 924 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return; 925 926 /* Set up the user-stack */ 927 DispatchToUser: 928 _SEH2_TRY 929 { 930 ULONG Size; 931 ULONG_PTR Stack, NewStack; 932 933 /* Make sure we have a valid SS and that this isn't V86 mode */ 934 if ((TrapFrame->HardwareSegSs != (KGDT_R3_DATA | RPL_MASK)) || 935 (TrapFrame->EFlags & EFLAGS_V86_MASK)) 936 { 937 /* Raise an exception instead */ 938 LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION; 939 LocalExceptRecord.ExceptionFlags = 0; 940 LocalExceptRecord.NumberParameters = 0; 941 RtlRaiseException(&LocalExceptRecord); 942 } 943 944 /* Align context size and get stack pointer */ 945 Size = (sizeof(CONTEXT) + 3) & ~3; 946 Stack = (Context.Esp & ~3) - Size; 947 948 /* Probe stack and copy Context */ 949 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG)); 950 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT)); 951 952 /* Align exception record size and get stack pointer */ 953 Size = (sizeof(EXCEPTION_RECORD) - 954 (EXCEPTION_MAXIMUM_PARAMETERS - 955 ExceptionRecord->NumberParameters) * 956 sizeof(ULONG) + 3) & ~3; 957 NewStack = Stack - Size; 958 959 /* Probe stack and copy exception record */ 960 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)), 961 Size + 2 * sizeof(ULONG_PTR), 962 sizeof(ULONG)); 963 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size); 964 965 /* Now write the two params for the user-mode dispatcher */ 966 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack; 967 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack; 968 969 /* Set new Stack Pointer */ 970 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA); 971 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR)); 972 973 /* Force correct segments */ 974 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, PreviousMode); 975 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode); 976 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, PreviousMode); 977 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, PreviousMode); 978 TrapFrame->SegGs = 0; 979 980 /* Set EIP to the User-mode Dispatcher */ 981 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher; 982 983 /* Dispatch exception to user-mode */ 984 _SEH2_YIELD(return); 985 } 986 _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER)) 987 { 988 /* Check if we got a stack overflow and raise that instead */ 989 if ((NTSTATUS)LocalExceptRecord.ExceptionCode == 990 STATUS_STACK_OVERFLOW) 991 { 992 /* Copy the exception address and record */ 993 LocalExceptRecord.ExceptionAddress = 994 ExceptionRecord->ExceptionAddress; 995 RtlCopyMemory(ExceptionRecord, 996 (PVOID)&LocalExceptRecord, 997 sizeof(EXCEPTION_RECORD)); 998 999 /* Do the exception again */ 1000 _SEH2_YIELD(goto DispatchToUser); 1001 } 1002 } 1003 _SEH2_END; 1004 1005 DPRINT("First chance exception in %.16s, ExceptionCode: %lx, ExceptionAddress: %p, P0: %lx, P1: %lx\n", 1006 PsGetCurrentProcess()->ImageFileName, 1007 ExceptionRecord->ExceptionCode, 1008 ExceptionRecord->ExceptionAddress, 1009 ExceptionRecord->ExceptionInformation[0], 1010 ExceptionRecord->ExceptionInformation[1]); 1011 } 1012 1013 /* Try second chance */ 1014 if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) 1015 { 1016 /* Handled, get out */ 1017 return; 1018 } 1019 else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) 1020 { 1021 /* Handled, get out */ 1022 return; 1023 } 1024 1025 /* 3rd strike, kill the process */ 1026 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %p, BaseAddress: %p, P0: %lx, P1: %lx\n", 1027 PsGetCurrentProcess()->ImageFileName, 1028 ExceptionRecord->ExceptionCode, 1029 ExceptionRecord->ExceptionAddress, 1030 PsGetCurrentProcess()->SectionBaseAddress, 1031 ExceptionRecord->ExceptionInformation[0], 1032 ExceptionRecord->ExceptionInformation[1]); 1033 1034 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode); 1035 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 1036 ExceptionRecord->ExceptionCode, 1037 (ULONG_PTR)ExceptionRecord->ExceptionAddress, 1038 (ULONG_PTR)TrapFrame, 1039 0); 1040 } 1041 1042 Handled: 1043 /* Convert the context back into Trap/Exception Frames */ 1044 KeContextToTrapFrame(&Context, 1045 ExceptionFrame, 1046 TrapFrame, 1047 Context.ContextFlags, 1048 PreviousMode); 1049 return; 1050 } 1051 1052 DECLSPEC_NORETURN 1053 VOID 1054 NTAPI 1055 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code, 1056 IN ULONG Flags, 1057 IN ULONG_PTR Address, 1058 IN ULONG ParameterCount, 1059 IN ULONG_PTR Parameter1, 1060 IN ULONG_PTR Parameter2, 1061 IN ULONG_PTR Parameter3, 1062 IN PKTRAP_FRAME TrapFrame) 1063 { 1064 EXCEPTION_RECORD ExceptionRecord; 1065 1066 /* Build the exception record */ 1067 ExceptionRecord.ExceptionCode = Code; 1068 ExceptionRecord.ExceptionFlags = Flags; 1069 ExceptionRecord.ExceptionRecord = NULL; 1070 ExceptionRecord.ExceptionAddress = (PVOID)Address; 1071 ExceptionRecord.NumberParameters = ParameterCount; 1072 if (ParameterCount) 1073 { 1074 /* Copy extra parameters */ 1075 ExceptionRecord.ExceptionInformation[0] = Parameter1; 1076 ExceptionRecord.ExceptionInformation[1] = Parameter2; 1077 ExceptionRecord.ExceptionInformation[2] = Parameter3; 1078 } 1079 1080 /* Now go dispatch the exception */ 1081 KiDispatchException(&ExceptionRecord, 1082 NULL, 1083 TrapFrame, 1084 TrapFrame->EFlags & EFLAGS_V86_MASK ? 1085 -1 : KiUserTrap(TrapFrame), 1086 TRUE); 1087 1088 /* Return from this trap */ 1089 KiEoiHelper(TrapFrame); 1090 } 1091 1092 DECLSPEC_NORETURN 1093 VOID 1094 FASTCALL 1095 KiSystemFatalException(IN ULONG ExceptionCode, 1096 IN PKTRAP_FRAME TrapFrame) 1097 { 1098 /* Bugcheck the system */ 1099 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP, 1100 ExceptionCode, 1101 0, 1102 0, 1103 0, 1104 TrapFrame); 1105 } 1106 1107 /* PUBLIC FUNCTIONS ***********************************************************/ 1108 1109 /* 1110 * @implemented 1111 */ 1112 NTSTATUS 1113 NTAPI 1114 KeRaiseUserException(IN NTSTATUS ExceptionCode) 1115 { 1116 ULONG OldEip; 1117 PTEB Teb = KeGetCurrentThread()->Teb; 1118 PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame; 1119 1120 /* Make sure we can access the TEB */ 1121 _SEH2_TRY 1122 { 1123 /* Set the exception code */ 1124 Teb->ExceptionCode = ExceptionCode; 1125 } 1126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1127 { 1128 /* Return the exception code */ 1129 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1130 } 1131 _SEH2_END; 1132 1133 /* Get the old EIP */ 1134 OldEip = TrapFrame->Eip; 1135 1136 /* Change it to the user-mode dispatcher */ 1137 TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher; 1138 1139 /* Return the old EIP */ 1140 return (NTSTATUS)OldEip; 1141 } 1142