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)
8 * Skywing (skywing@valhallalegends.com)
11 /* INCLUDES ******************************************************************/
18 /* FUNCTIONS *****************************************************************/
23 KeInitExceptions(VOID
)
26 USHORT FlippedSelector
;
29 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
31 /* Save the current Selector */
32 FlippedSelector
= KiIdt
[i
].Selector
;
34 /* Flip Selector and Extended Offset */
35 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
36 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
42 KiUpdateDr7(IN ULONG Dr7
)
44 ULONG DebugMask
= KeGetCurrentThread()->Header
.DebugActive
;
46 /* Check if debugging is enabled */
47 if (DebugMask
& DR_MASK(DR7_OVERRIDE_V
))
50 ASSERT((DebugMask
& DR_REG_MASK
) != 0);
51 ASSERT((Dr7
& ~DR7_RESERVED_MASK
) == DR7_OVERRIDE_MASK
);
55 /* Return DR7 itself */
61 KiRecordDr7(OUT PULONG Dr7Ptr
,
67 /* Check if the caller gave us a mask */
70 /* He didn't, use the one from the thread */
71 Mask
= KeGetCurrentThread()->Header
.DebugActive
;
80 ASSERT((*Dr7Ptr
& DR7_RESERVED_MASK
) == 0);
82 /* Check if DR7 is empty */
89 /* Check the DR mask */
90 NewMask
&= ~(DR_MASK(7));
91 if (NewMask
& DR_REG_MASK
)
93 /* Set the active mask */
94 NewMask
|= DR_MASK(DR7_OVERRIDE_V
);
96 /* Set DR7 override */
97 *Dr7Ptr
|= DR7_OVERRIDE_MASK
;
102 ASSERT(NewMask
== 0);
107 /* Check if we have a mask or not */
108 Result
= NewMask
? TRUE
: FALSE
;
110 /* Update the mask to disable debugging */
111 NewMask
&= ~(DR_MASK(DR7_OVERRIDE_V
));
112 NewMask
|= DR_MASK(7);
115 /* Check if caller wants the new mask */
123 /* Check if the mask changed */
127 KeGetCurrentThread()->Header
.DebugActive
= (UCHAR
)NewMask
;
131 /* Return the result */
137 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
139 /* Check if this is user-mode or V86 */
140 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
141 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
143 /* Return it directly */
144 return TrapFrame
->HardwareEsp
;
149 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
151 /* Return edited value */
152 return TrapFrame
->TempEsp
;
156 /* Virgin frame, calculate */
157 return (ULONG
)&TrapFrame
->HardwareEsp
;
164 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
170 /* Raise to APC_LEVEL if needed */
171 OldIrql
= KeGetCurrentIrql();
172 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
174 /* Get the old ESP */
175 Previous
= KiEspFromTrapFrame(TrapFrame
);
177 /* Check if this is user-mode or V86 */
178 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
179 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
181 /* Write it directly */
182 TrapFrame
->HardwareEsp
= Esp
;
186 /* Don't allow ESP to be lowered, this is illegal */
187 if (Esp
< Previous
) KeBugCheckEx(SET_OF_INVALID_CONTEXT
,
190 (ULONG_PTR
)TrapFrame
,
193 /* Create an edit frame, check if it was alrady */
194 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
196 /* Update the value */
197 TrapFrame
->TempEsp
= Esp
;
201 /* Check if ESP changed */
205 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
206 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
209 TrapFrame
->TempEsp
= Esp
;
215 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
220 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
222 /* Check if this was V86 Mode */
223 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
226 return TrapFrame
->HardwareSegSs
;
228 else if (TrapFrame
->SegCs
& MODE_MASK
)
230 /* User mode, return the User SS */
231 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
242 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
245 /* Remove the high-bits */
248 /* If this was V86 Mode */
249 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
252 TrapFrame
->HardwareSegSs
= Ss
;
254 else if (TrapFrame
->SegCs
& MODE_MASK
)
256 /* Usermode, save the User SS */
257 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
263 KiTagWordFnsaveToFxsave(USHORT TagWord
)
265 INT FxTagWord
= ~TagWord
;
268 * Empty is now 00, any 2 bits containing 1 mean valid
269 * Now convert the rest (11->0 and the rest to 1)
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 */
280 Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame
)
286 /* Get the current thread's stack */
287 Thread
= KeGetCurrentThread();
288 Stack
= (ULONG_PTR
)Thread
->InitialStack
;
290 /* Check if we are in V8086 mode */
291 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
293 /* Bias the stack for the V86 segments */
294 Stack
-= (FIELD_OFFSET(KTRAP_FRAME
, V86Gs
) -
295 FIELD_OFFSET(KTRAP_FRAME
, HardwareSegSs
));
298 /* Bias the stack for the FPU area */
299 Stack
-= sizeof(FX_SAVE_AREA
);
301 /* Disable interrupts */
302 EFlags
= __readeflags();
305 /* Set new ESP0 value in the TSS */
306 KeGetPcr()->TSS
->Esp0
= Stack
;
308 /* Restore old interrupt state */
309 __writeeflags(EFlags
);
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
)
320 PFX_SAVE_AREA FxSaveArea
;
322 BOOLEAN V86Switch
= FALSE
;
326 /* Do this at APC_LEVEL */
327 OldIrql
= KeGetCurrentIrql();
328 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
330 /* Start with the basic Registers */
331 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
333 /* Check if we went through a V86 switch */
334 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
335 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
337 /* We did, remember this for later */
341 /* Copy EFLAGS and sanitize them*/
342 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
->EFlags
, PreviousMode
);
344 /* Copy EBP and EIP */
345 TrapFrame
->Ebp
= Context
->Ebp
;
346 TrapFrame
->Eip
= Context
->Eip
;
348 /* Check if we were in V86 Mode */
349 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
351 /* Simply copy the CS value */
352 TrapFrame
->SegCs
= Context
->SegCs
;
356 /* We weren't in V86, so sanitize the CS */
357 TrapFrame
->SegCs
= Ke386SanitizeSeg(Context
->SegCs
, PreviousMode
);
359 /* Don't let it under 8, that's invalid */
360 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
362 /* Force it to User CS */
363 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
367 /* Handle SS Specially for validation */
368 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
370 /* Write ESP back; take into account Edited Trap Frames */
371 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
373 /* Handle our V86 Bias if we went through a switch */
374 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
377 /* Process the Integer Registers */
378 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
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
;
389 /* Process the Context Segments */
390 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
392 /* Check if we were in V86 Mode */
393 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
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
;
401 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
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;
411 /* For user mode, return the values directly */
412 TrapFrame
->SegDs
= Context
->SegDs
;
413 TrapFrame
->SegEs
= Context
->SegEs
;
414 TrapFrame
->SegFs
= Context
->SegFs
;
416 /* Handle GS specially */
417 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
419 /* Don't use it, if user */
420 TrapFrame
->SegGs
= 0;
424 /* Copy it if kernel */
425 TrapFrame
->SegGs
= Context
->SegGs
;
430 /* Handle the extended registers */
431 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
432 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
434 /* Get the FX Area */
435 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
437 /* Check if NPX is present */
438 if (KeI386NpxPresent
)
440 /* Flush the NPX State */
441 KiFlushNPXState(NULL
);
443 /* Copy the FX State */
444 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
445 &Context
->ExtendedRegisters
[0],
446 MAXIMUM_SUPPORTED_EXTENSION
);
448 /* Remove reserved bits from MXCSR */
449 FxSaveArea
->U
.FxArea
.MXCsr
&= KiMXCsrMask
;
451 /* Mask out any invalid flags */
452 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
454 /* Check if this is a VDM app */
455 if (PsGetCurrentProcess()->VdmObjects
)
457 /* Allow the EM flag */
458 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
464 /* Handle the floating point state */
465 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
466 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
468 /* Get the FX Area */
469 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
471 /* Check if NPX is present */
472 if (KeI386NpxPresent
)
474 /* Flush the NPX State */
475 KiFlushNPXState(NULL
);
477 /* Check if we have Fxsr support */
478 if (KeI386FxsrPresent
)
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
;
498 /* Clear out the Register Area */
499 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
500 SIZE_OF_FX_REGISTERS
);
502 /* Loop the 8 floating point registers */
503 for (i
= 0; i
< 8; i
++)
505 /* Copy from Fn to Fx */
506 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
507 Context
->FloatSave
.RegisterArea
+ (i
* 10),
513 /* Copy the structure */
514 FxSaveArea
->U
.FnArea
.ControlWord
= Context
->FloatSave
.
516 FxSaveArea
->U
.FnArea
.StatusWord
= Context
->FloatSave
.
518 FxSaveArea
->U
.FnArea
.TagWord
= Context
->FloatSave
.TagWord
;
519 FxSaveArea
->U
.FnArea
.ErrorOffset
= Context
->FloatSave
.
521 FxSaveArea
->U
.FnArea
.ErrorSelector
= Context
->FloatSave
.
523 FxSaveArea
->U
.FnArea
.DataOffset
= Context
->FloatSave
.
525 FxSaveArea
->U
.FnArea
.DataSelector
= Context
->FloatSave
.
529 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
532 FxSaveArea
->U
.FnArea
.RegisterArea
[i
] =
533 Context
->FloatSave
.RegisterArea
[i
];
537 /* Mask out any invalid flags */
538 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
540 /* Check if this is a VDM app */
541 if (PsGetCurrentProcess()->VdmObjects
)
543 /* Allow the EM flag */
544 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
550 /* FIXME: Handle FPU Emulation */
555 /* Handle the Debug Registers */
556 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
559 TrapFrame
->Dr0
= Context
->Dr0
;
560 TrapFrame
->Dr1
= Context
->Dr1
;
561 TrapFrame
->Dr2
= Context
->Dr2
;
562 TrapFrame
->Dr3
= Context
->Dr3
;
564 /* If we're in user-mode */
565 if (PreviousMode
!= KernelMode
)
567 /* Make sure, no Dr address is above user space */
568 if (Context
->Dr0
> (ULONG
)MmHighestUserAddress
) TrapFrame
->Dr0
= 0;
569 if (Context
->Dr1
> (ULONG
)MmHighestUserAddress
) TrapFrame
->Dr1
= 0;
570 if (Context
->Dr2
> (ULONG
)MmHighestUserAddress
) TrapFrame
->Dr2
= 0;
571 if (Context
->Dr3
> (ULONG
)MmHighestUserAddress
) TrapFrame
->Dr3
= 0;
574 /* Now sanitize and save DR6 */
575 TrapFrame
->Dr6
= Context
->Dr6
& DR6_LEGAL
;
577 /* Update the Dr active mask */
578 if (TrapFrame
->Dr0
) DrMask
|= DR_MASK(0);
579 if (TrapFrame
->Dr1
) DrMask
|= DR_MASK(1);
580 if (TrapFrame
->Dr2
) DrMask
|= DR_MASK(2);
581 if (TrapFrame
->Dr3
) DrMask
|= DR_MASK(3);
582 if (TrapFrame
->Dr6
) DrMask
|= DR_MASK(6);
584 /* Sanitize and save DR7 */
585 TrapFrame
->Dr7
= Context
->Dr7
& DR7_LEGAL
;
586 KiRecordDr7(&TrapFrame
->Dr7
, &DrMask
);
588 /* If we're in user-mode */
589 if (PreviousMode
!= KernelMode
)
592 KeGetCurrentThread()->Header
.DebugActive
= (UCHAR
)DrMask
;
596 /* Check if thread has IOPL and force it enabled if so */
597 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= EFLAGS_IOPL
;
600 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
605 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
606 IN PKEXCEPTION_FRAME ExceptionFrame
,
607 IN OUT PCONTEXT Context
)
609 PFX_SAVE_AREA FxSaveArea
;
613 FLOATING_SAVE_AREA UnalignedArea
;
615 FLOATING_SAVE_AREA
*FloatSaveArea
;
619 /* Do this at APC_LEVEL */
620 OldIrql
= KeGetCurrentIrql();
621 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
623 /* Start with the Control flags */
624 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
626 /* EBP, EIP and EFLAGS */
627 Context
->Ebp
= TrapFrame
->Ebp
;
628 Context
->Eip
= TrapFrame
->Eip
;
629 Context
->EFlags
= TrapFrame
->EFlags
;
631 /* Return the correct CS */
632 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
633 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
635 /* Get it from the Temp location */
636 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
640 /* Return it directly */
641 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
644 /* Get the Ss and ESP */
645 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
646 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
649 /* Handle the Segments */
650 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
652 /* Do V86 Mode first */
653 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
655 /* Return from the V86 location */
656 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
657 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
658 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
659 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
663 /* Check if this was a Kernel Trap */
664 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
666 /* Set valid selectors */
667 TrapFrame
->SegGs
= 0;
668 TrapFrame
->SegFs
= KGDT_R0_PCR
;
669 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
670 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
673 /* Return the segments */
674 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
675 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
676 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
677 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
681 /* Handle the simple registers */
682 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
684 /* Return them directly */
685 Context
->Eax
= TrapFrame
->Eax
;
686 Context
->Ebx
= TrapFrame
->Ebx
;
687 Context
->Ecx
= TrapFrame
->Ecx
;
688 Context
->Edx
= TrapFrame
->Edx
;
689 Context
->Esi
= TrapFrame
->Esi
;
690 Context
->Edi
= TrapFrame
->Edi
;
693 /* Handle extended registers */
694 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
695 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
697 /* Get the FX Save Area */
698 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
700 /* Make sure NPX is present */
701 if (KeI386NpxPresent
)
703 /* Flush the NPX State */
704 KiFlushNPXState(NULL
);
706 /* Copy the registers */
707 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
708 &FxSaveArea
->U
.FxArea
,
709 MAXIMUM_SUPPORTED_EXTENSION
);
713 /* Handle Floating Point */
714 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
715 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
717 /* Get the FX Save Area */
718 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
720 /* Make sure we have an NPX */
721 if (KeI386NpxPresent
)
723 /* Check if we have Fxsr support */
724 if (KeI386FxsrPresent
)
726 /* Align the floating area to 16-bytes */
727 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
728 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
731 KiFlushNPXState(FloatSaveArea
);
735 /* We don't, use the FN area and flush the NPX State */
736 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
737 KiFlushNPXState(NULL
);
741 Context
->FloatSave
.ControlWord
= FloatSaveArea
->ControlWord
;
742 Context
->FloatSave
.StatusWord
= FloatSaveArea
->StatusWord
;
743 Context
->FloatSave
.TagWord
= FloatSaveArea
->TagWord
;
744 Context
->FloatSave
.ErrorOffset
= FloatSaveArea
->ErrorOffset
;
745 Context
->FloatSave
.ErrorSelector
= FloatSaveArea
->ErrorSelector
;
746 Context
->FloatSave
.DataOffset
= FloatSaveArea
->DataOffset
;
747 Context
->FloatSave
.DataSelector
= FloatSaveArea
->DataSelector
;
748 Context
->FloatSave
.Cr0NpxState
= FxSaveArea
->Cr0NpxState
;
751 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
754 Context
->FloatSave
.RegisterArea
[i
] =
755 FloatSaveArea
->RegisterArea
[i
];
760 /* FIXME: Handle Emulation */
765 /* Handle debug registers */
766 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
767 CONTEXT_DEBUG_REGISTERS
)
769 /* Make sure DR7 is valid */
770 if (TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
)
772 /* Copy the debug registers */
773 Context
->Dr0
= TrapFrame
->Dr0
;
774 Context
->Dr1
= TrapFrame
->Dr1
;
775 Context
->Dr2
= TrapFrame
->Dr2
;
776 Context
->Dr3
= TrapFrame
->Dr3
;
777 Context
->Dr6
= TrapFrame
->Dr6
;
780 Context
->Dr7
= KiUpdateDr7(TrapFrame
->Dr7
);
784 /* Otherwise clear DR registers */
795 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
800 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL
)
803 PKTRAP_FRAME TrapFrame
= TrapInformation
;
804 VOID NTAPI
ExpInterlockedPopEntrySListFault(VOID
);
806 /* Don't do anything if we didn't get a trap frame */
807 if (!TrapInformation
) return FALSE
;
809 /* Check where we came from */
810 switch (TrapFrame
->SegCs
)
815 /* Allow S-LIST Routine to fail */
816 Eip
= (ULONG
)&ExpInterlockedPopEntrySListFault
;
820 case KGDT_R3_CODE
| RPL_MASK
:
822 /* Allow S-LIST Routine to fail */
823 //Eip = (ULONG)KeUserPopEntrySListFault;
829 /* Anything else gets a bugcheck */
833 /* Return TRUE if we want to keep the system up */
834 return (TrapFrame
->Eip
== Eip
) ? TRUE
: FALSE
;
839 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
840 IN PKEXCEPTION_FRAME ExceptionFrame
,
841 IN PKTRAP_FRAME TrapFrame
,
842 IN KPROCESSOR_MODE PreviousMode
,
843 IN BOOLEAN FirstChance
)
846 EXCEPTION_RECORD LocalExceptRecord
;
848 /* Increase number of Exception Dispatches */
849 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
851 /* Set the context flags */
852 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
854 /* Check if User Mode or if the kernel debugger is enabled */
855 if ((PreviousMode
== UserMode
) || (KeGetPcr()->KdVersionBlock
))
857 /* Add the FPU Flag */
858 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
860 /* Check for NPX Support */
861 if (KeI386FxsrPresent
)
864 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
869 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
871 /* Look at our exception code */
872 switch (ExceptionRecord
->ExceptionCode
)
875 case STATUS_BREAKPOINT
:
877 /* Decrement EIP by one */
881 /* Internal exception */
882 case KI_EXCEPTION_ACCESS_VIOLATION
:
884 /* Set correct code */
885 ExceptionRecord
->ExceptionCode
= STATUS_ACCESS_VIOLATION
;
886 if (PreviousMode
== UserMode
)
888 /* FIXME: Handle no execute */
894 ASSERT(!((PreviousMode
== KernelMode
) &&
895 (Context
.EFlags
& EFLAGS_V86_MASK
)));
897 /* Handle kernel-mode first, it's simpler */
898 if (PreviousMode
== KernelMode
)
900 /* Check if this is a first-chance exception */
901 if (FirstChance
== TRUE
)
903 /* Break into the debugger for the first time */
904 if (KiDebugRoutine(TrapFrame
,
911 /* Exception was handled */
915 /* If the Debugger couldn't handle it, dispatch the exception */
916 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
919 /* This is a second-chance exception, only for the debugger */
920 if (KiDebugRoutine(TrapFrame
,
927 /* Exception was handled */
931 /* Third strike; you're out */
932 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
933 ExceptionRecord
->ExceptionCode
,
934 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
935 (ULONG_PTR
)TrapFrame
,
940 /* User mode exception, was it first-chance? */
944 * Break into the kernel debugger unless a user mode debugger
945 * is present or user mode exceptions are ignored, except if this
946 * is a debug service which we must always pass to KD
948 if ((!(PsGetCurrentProcess()->DebugPort
) &&
949 !(KdIgnoreUmExceptions
)) ||
950 (KdIsThisAKdTrap(ExceptionRecord
,
954 /* Call the kernel debugger */
955 if (KiDebugRoutine(TrapFrame
,
962 /* Exception was handled */
967 /* Forward exception to user mode debugger */
968 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) return;
970 /* Set up the user-stack */
975 ULONG_PTR Stack
, NewStack
;
977 /* Make sure we have a valid SS and that this isn't V86 mode */
978 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
979 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
981 /* Raise an exception instead */
982 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
983 LocalExceptRecord
.ExceptionFlags
= 0;
984 LocalExceptRecord
.NumberParameters
= 0;
985 RtlRaiseException(&LocalExceptRecord
);
988 /* Align context size and get stack pointer */
989 Size
= (sizeof(CONTEXT
) + 3) & ~3;
990 Stack
= (Context
.Esp
& ~3) - Size
;
992 /* Probe stack and copy Context */
993 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
994 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
996 /* Align exception record size and get stack pointer */
997 Size
= (sizeof(EXCEPTION_RECORD
) -
998 (EXCEPTION_MAXIMUM_PARAMETERS
-
999 ExceptionRecord
->NumberParameters
) *
1000 sizeof(ULONG
) + 3) & ~3;
1001 NewStack
= Stack
- Size
;
1003 /* Probe stack and copy exception record */
1004 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1005 Size
+ 2 * sizeof(ULONG_PTR
),
1007 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1009 /* Now write the two params for the user-mode dispatcher */
1010 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1011 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1013 /* Set new Stack Pointer */
1014 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
1015 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
1017 /* Force correct segments */
1018 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, PreviousMode
);
1019 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1020 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1021 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, PreviousMode
);
1022 TrapFrame
->SegGs
= 0;
1024 /* Set EIP to the User-mode Dispatcher */
1025 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1027 /* Dispatch exception to user-mode */
1028 _SEH2_YIELD(return);
1030 _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord
, _SEH2_GetExceptionInformation()->ExceptionRecord
, sizeof(EXCEPTION_RECORD
)), EXCEPTION_EXECUTE_HANDLER
))
1032 /* Check if we got a stack overflow and raise that instead */
1033 if ((NTSTATUS
)LocalExceptRecord
.ExceptionCode
==
1034 STATUS_STACK_OVERFLOW
)
1036 /* Copy the exception address and record */
1037 LocalExceptRecord
.ExceptionAddress
=
1038 ExceptionRecord
->ExceptionAddress
;
1039 RtlCopyMemory(ExceptionRecord
,
1040 (PVOID
)&LocalExceptRecord
,
1041 sizeof(EXCEPTION_RECORD
));
1043 /* Do the exception again */
1044 _SEH2_YIELD(goto DispatchToUser
);
1050 /* Try second chance */
1051 if (DbgkForwardException(ExceptionRecord
, TRUE
, TRUE
))
1053 /* Handled, get out */
1056 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
1058 /* Handled, get out */
1062 /* 3rd strike, kill the process */
1063 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx, BaseAddress: %lx\n",
1064 PsGetCurrentProcess()->ImageFileName
,
1065 ExceptionRecord
->ExceptionCode
,
1066 ExceptionRecord
->ExceptionAddress
,
1067 PsGetCurrentProcess()->SectionBaseAddress
);
1069 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
1070 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
1071 ExceptionRecord
->ExceptionCode
,
1072 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1073 (ULONG_PTR
)TrapFrame
,
1078 /* Convert the context back into Trap/Exception Frames */
1079 KeContextToTrapFrame(&Context
,
1082 Context
.ContextFlags
,
1090 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code
,
1091 IN ULONG_PTR Address
,
1092 IN ULONG ParameterCount
,
1093 IN ULONG_PTR Parameter1
,
1094 IN ULONG_PTR Parameter2
,
1095 IN ULONG_PTR Parameter3
,
1096 IN PKTRAP_FRAME TrapFrame
)
1098 EXCEPTION_RECORD ExceptionRecord
;
1100 /* Build the exception record */
1101 ExceptionRecord
.ExceptionCode
= Code
;
1102 ExceptionRecord
.ExceptionFlags
= 0;
1103 ExceptionRecord
.ExceptionRecord
= NULL
;
1104 ExceptionRecord
.ExceptionAddress
= (PVOID
)Address
;
1105 ExceptionRecord
.NumberParameters
= ParameterCount
;
1108 /* Copy extra parameters */
1109 ExceptionRecord
.ExceptionInformation
[0] = Parameter1
;
1110 ExceptionRecord
.ExceptionInformation
[1] = Parameter2
;
1111 ExceptionRecord
.ExceptionInformation
[2] = Parameter3
;
1114 /* Now go dispatch the exception */
1115 KiDispatchException(&ExceptionRecord
,
1118 TrapFrame
->EFlags
& EFLAGS_V86_MASK
?
1119 -1 : KiUserTrap(TrapFrame
),
1122 /* Return from this trap */
1123 KiEoiHelper(TrapFrame
);
1129 KiSystemFatalException(IN ULONG ExceptionCode
,
1130 IN PKTRAP_FRAME TrapFrame
)
1132 /* Bugcheck the system */
1133 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP
,
1141 /* PUBLIC FUNCTIONS ***********************************************************/
1148 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1151 PTEB Teb
= KeGetCurrentThread()->Teb
;
1152 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
1154 /* Make sure we can access the TEB */
1157 /* Set the exception code */
1158 Teb
->ExceptionCode
= ExceptionCode
;
1160 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1162 /* Return the exception code */
1163 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1167 /* Get the old EIP */
1168 OldEip
= TrapFrame
->Eip
;
1170 /* Change it to the user-mode dispatcher */
1171 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1173 /* Return the old EIP */
1174 return (NTSTATUS
)OldEip
;