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 ******************************************************************/
17 /* GLOBALS *******************************************************************/
19 /* DR Registers in the CONTEXT structure */
20 UCHAR KiDebugRegisterContextOffsets
[9] =
22 FIELD_OFFSET(CONTEXT
, Dr0
),
23 FIELD_OFFSET(CONTEXT
, Dr1
),
24 FIELD_OFFSET(CONTEXT
, Dr2
),
25 FIELD_OFFSET(CONTEXT
, Dr3
),
28 FIELD_OFFSET(CONTEXT
, Dr6
),
29 FIELD_OFFSET(CONTEXT
, Dr7
),
33 /* DR Registers in the KTRAP_FRAME structure */
34 UCHAR KiDebugRegisterTrapOffsets
[9] =
36 FIELD_OFFSET(KTRAP_FRAME
, Dr0
),
37 FIELD_OFFSET(KTRAP_FRAME
, Dr1
),
38 FIELD_OFFSET(KTRAP_FRAME
, Dr2
),
39 FIELD_OFFSET(KTRAP_FRAME
, Dr3
),
42 FIELD_OFFSET(KTRAP_FRAME
, Dr6
),
43 FIELD_OFFSET(KTRAP_FRAME
, Dr7
),
47 /* FUNCTIONS *****************************************************************/
49 _SEH_DEFINE_LOCALS(KiCopyInfo
)
51 volatile EXCEPTION_RECORD SehExceptRecord
;
54 _SEH_FILTER(KiCopyInformation
)
56 _SEH_ACCESS_LOCALS(KiCopyInfo
);
58 /* Copy the exception records and return to the handler */
59 RtlCopyMemory((PVOID
)&_SEH_VAR(SehExceptRecord
),
60 _SEH_GetExceptionPointers()->ExceptionRecord
,
61 sizeof(EXCEPTION_RECORD
));
62 return EXCEPTION_EXECUTE_HANDLER
;
68 KeInitExceptions(VOID
)
71 USHORT FlippedSelector
;
72 extern KIDTENTRY KiIdt
[MAXIMUM_IDTVECTOR
];
75 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
77 /* Save the current Selector */
78 FlippedSelector
= KiIdt
[i
].Selector
;
80 /* Flip Selector and Extended Offset */
81 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
82 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
88 KiUpdateDr7(IN ULONG Dr7
)
90 ULONG DebugMask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
92 /* Check if debugging is enabled */
93 if (DebugMask
& DR_MASK(DR7_OVERRIDE_V
))
96 ASSERT((DebugMask
& DR_REG_MASK
) != 0);
97 ASSERT((Dr7
& ~DR7_RESERVED_MASK
) == DR7_OVERRIDE_MASK
);
101 /* Return DR7 itself */
107 KiRecordDr7(OUT PULONG Dr7Ptr
,
113 /* Check if the caller gave us a mask */
116 /* He didn't use the one from the thread */
117 Mask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
121 /* He did, read it */
126 ASSERT((*Dr7Ptr
& DR7_RESERVED_MASK
) == 0);
128 /* Check if DR7 is empty */
135 /* Check the DR mask */
136 NewMask
&= ~(DR_MASK(7));
137 if (NewMask
& DR_REG_MASK
)
139 /* Set the active mask */
140 NewMask
|= DR_MASK(DR7_OVERRIDE_V
);
142 /* Set DR7 override */
143 *DrMask
|= DR7_OVERRIDE_MASK
;
148 ASSERT(NewMask
== 0);
153 /* Check if we have a mask or not */
154 Result
= NewMask
? TRUE
: FALSE
;
156 /* Update the mask to disable debugging */
157 NewMask
&= ~(DR_MASK(DR7_OVERRIDE_V
));
158 NewMask
|= DR_MASK(7);
161 /* Check if caller wants the new mask */
169 /* Check if the mask changed */
173 KeGetCurrentThread()->DispatcherHeader
.DebugActive
= NewMask
;
177 /* Return the result */
183 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
185 /* Check if this is user-mode or V86 */
186 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
187 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
189 /* Return it directly */
190 return TrapFrame
->HardwareEsp
;
195 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
197 /* Return edited value */
198 return TrapFrame
->TempEsp
;
202 /* Virgin frame, calculate */
203 return (ULONG
)&TrapFrame
->HardwareEsp
;
210 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
216 /* Raise to APC_LEVEL if needed */
217 OldIrql
= KeGetCurrentIrql();
218 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
220 /* Get the old ESP */
221 Previous
= KiEspFromTrapFrame(TrapFrame
);
223 /* Check if this is user-mode or V86 */
224 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
225 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
227 /* Write it directly */
228 TrapFrame
->HardwareEsp
= Esp
;
232 /* Don't allow ESP to be lowered, this is illegal */
233 if (Esp
< Previous
) KeBugCheckEx(SET_OF_INVALID_CONTEXT
,
236 (ULONG_PTR
)TrapFrame
,
239 /* Create an edit frame, check if it was alrady */
240 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
242 /* Update the value */
243 TrapFrame
->TempEsp
= Esp
;
247 /* Check if ESP changed */
251 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
252 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
255 TrapFrame
->TempEsp
= Esp
;
261 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
266 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
268 /* If this was V86 Mode */
269 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
272 return TrapFrame
->HardwareSegSs
;
274 else if (TrapFrame
->SegCs
& MODE_MASK
)
276 /* Usermode, return the User SS */
277 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
288 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
291 /* Remove the high-bits */
294 /* If this was V86 Mode */
295 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
298 TrapFrame
->HardwareSegSs
= Ss
;
300 else if (TrapFrame
->SegCs
& MODE_MASK
)
302 /* Usermode, save the User SS */
303 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
309 KiTagWordFnsaveToFxsave(USHORT TagWord
)
311 INT FxTagWord
= ~TagWord
;
314 * Empty is now 00, any 2 bits containing 1 mean valid
315 * Now convert the rest (11->0 and the rest to 1)
317 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
318 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
319 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
320 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
326 KeContextToTrapFrame(IN PCONTEXT Context
,
327 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
328 IN OUT PKTRAP_FRAME TrapFrame
,
329 IN ULONG ContextFlags
,
330 IN KPROCESSOR_MODE PreviousMode
)
332 PFX_SAVE_AREA FxSaveArea
;
334 BOOLEAN V86Switch
= FALSE
;
339 /* Do this at APC_LEVEL */
340 OldIrql
= KeGetCurrentIrql();
341 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
343 /* Start with the basic Registers */
344 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
346 /* Check if we went through a V86 switch */
347 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
348 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
350 /* We did, remember this for later */
354 /* Copy EFLAGS and sanitize them*/
355 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
->EFlags
, PreviousMode
);
357 /* Copy EBP and EIP */
358 TrapFrame
->Ebp
= Context
->Ebp
;
359 TrapFrame
->Eip
= Context
->Eip
;
361 /* Check if we were in V86 Mode */
362 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
364 /* Simply copy the CS value */
365 TrapFrame
->SegCs
= Context
->SegCs
;
369 /* We weren't in V86, so sanitize the CS */
370 TrapFrame
->SegCs
= Ke386SanitizeSeg(Context
->SegCs
, PreviousMode
);
372 /* Don't let it under 8, that's invalid */
373 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
375 /* Force it to User CS */
376 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
380 /* Handle SS Specially for validation */
381 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
383 /* Write ESP back; take into account Edited Trap Frames */
384 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
386 /* Handle our V86 Bias if we went through a switch */
387 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
390 /* Process the Integer Registers */
391 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
393 /* Copy them manually */
394 TrapFrame
->Eax
= Context
->Eax
;
395 TrapFrame
->Ebx
= Context
->Ebx
;
396 TrapFrame
->Ecx
= Context
->Ecx
;
397 TrapFrame
->Edx
= Context
->Edx
;
398 TrapFrame
->Esi
= Context
->Esi
;
399 TrapFrame
->Edi
= Context
->Edi
;
402 /* Process the Context Segments */
403 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
405 /* Check if we were in V86 Mode */
406 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
408 /* Copy the V86 Segments directly */
409 TrapFrame
->V86Ds
= Context
->SegDs
;
410 TrapFrame
->V86Es
= Context
->SegEs
;
411 TrapFrame
->V86Fs
= Context
->SegFs
;
412 TrapFrame
->V86Gs
= Context
->SegGs
;
414 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
416 /* For kernel mode, write the standard values */
417 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
418 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
419 TrapFrame
->SegFs
= Ke386SanitizeSeg(Context
->SegFs
, PreviousMode
);
420 TrapFrame
->SegGs
= 0;
424 /* For user mode, return the values directly */
425 TrapFrame
->SegDs
= Context
->SegDs
;
426 TrapFrame
->SegEs
= Context
->SegEs
;
427 TrapFrame
->SegFs
= Context
->SegFs
;
429 /* Handle GS specially */
430 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
432 /* Don't use it, if user */
433 TrapFrame
->SegGs
= 0;
437 /* Copy it if kernel */
438 TrapFrame
->SegGs
= Context
->SegGs
;
443 /* Handle the extended registers */
444 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
445 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
447 /* Get the FX Area */
448 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
450 /* Check if NPX is present */
451 if (KeI386NpxPresent
)
453 /* Flush the NPX State */
454 KiFlushNPXState(NULL
);
456 /* Copy the FX State */
457 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
458 &Context
->ExtendedRegisters
[0],
459 MAXIMUM_SUPPORTED_EXTENSION
);
461 /* Remove reserved bits from MXCSR */
462 FxSaveArea
->U
.FxArea
.MXCsr
&= ~0xFFBF;
464 /* Mask out any invalid flags */
465 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
467 /* Check if this is a VDM app */
468 if (PsGetCurrentProcess()->VdmObjects
)
470 /* Allow the EM flag */
471 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
477 /* Handle the floating point state */
478 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
479 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
481 /* Get the FX Area */
482 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
484 /* Check if NPX is present */
485 if (KeI386NpxPresent
)
487 /* Flush the NPX State */
488 KiFlushNPXState(NULL
);
490 /* Check if we have Fxsr support */
491 if (KeI386FxsrPresent
)
493 /* Convert the Fn Floating Point state to Fx */
494 FxSaveArea
->U
.FxArea
.ControlWord
=
495 (USHORT
)Context
->FloatSave
.ControlWord
;
496 FxSaveArea
->U
.FxArea
.StatusWord
=
497 (USHORT
)Context
->FloatSave
.StatusWord
;
498 FxSaveArea
->U
.FxArea
.TagWord
=
499 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
500 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
501 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
502 FxSaveArea
->U
.FxArea
.ErrorOffset
=
503 Context
->FloatSave
.ErrorOffset
;
504 FxSaveArea
->U
.FxArea
.ErrorSelector
=
505 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
506 FxSaveArea
->U
.FxArea
.DataOffset
=
507 Context
->FloatSave
.DataOffset
;
508 FxSaveArea
->U
.FxArea
.DataSelector
=
509 Context
->FloatSave
.DataSelector
;
511 /* Clear out the Register Area */
512 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
513 SIZE_OF_FX_REGISTERS
);
515 /* Loop the 8 floating point registers */
516 for (i
= 0; i
< 8; i
++)
518 /* Copy from Fn to Fx */
519 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
520 Context
->FloatSave
.RegisterArea
+ (i
* 10),
526 /* Copy the structure */
527 FxSaveArea
->U
.FnArea
.ControlWord
= Context
->FloatSave
.
529 FxSaveArea
->U
.FnArea
.StatusWord
= Context
->FloatSave
.
531 FxSaveArea
->U
.FnArea
.TagWord
= Context
->FloatSave
.TagWord
;
532 FxSaveArea
->U
.FnArea
.ErrorOffset
= Context
->FloatSave
.
534 FxSaveArea
->U
.FnArea
.ErrorSelector
= Context
->FloatSave
.
536 FxSaveArea
->U
.FnArea
.DataOffset
= Context
->FloatSave
.
538 FxSaveArea
->U
.FnArea
.DataSelector
= Context
->FloatSave
.
542 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
545 FxSaveArea
->U
.FnArea
.RegisterArea
[i
] =
546 Context
->FloatSave
.RegisterArea
[i
];
550 /* Mask out any invalid flags */
551 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
553 /* Check if this is a VDM app */
554 if (PsGetCurrentProcess()->VdmObjects
)
556 /* Allow the EM flag */
557 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
563 /* FIXME: Handle FPU Emulation */
568 /* Handle the Debug Registers */
569 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
571 /* Loop DR registers */
572 for (i
= 0; i
< 4; i
++)
574 /* Sanitize the context DR Address */
575 SafeDr
= Ke386SanitizeDr(KiDrFromContext(i
, Context
), PreviousMode
);
577 /* Save it in the trap frame */
578 *KiDrFromTrapFrame(i
, TrapFrame
) = SafeDr
;
580 /* Check if this DR address is active and add it in the DR mask */
581 if (SafeDr
) DrMask
|= DR_MASK(i
);
584 /* Now save and sanitize DR6 */
585 TrapFrame
->Dr6
= Context
->Dr6
& DR6_LEGAL
;
586 if (TrapFrame
->Dr6
) DrMask
|= DR_MASK(6);
588 /* Save and sanitize DR7 */
589 TrapFrame
->Dr7
= Context
->Dr7
& DR7_LEGAL
;
590 KiRecordDr7(&TrapFrame
->Dr7
, &DrMask
);
592 /* If we're in user-mode */
593 if (PreviousMode
!= KernelMode
)
595 /* FIXME: Save the mask */
596 //KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
600 /* Check if thread has IOPL and force it enabled if so */
601 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= 0x3000;
604 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
609 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
610 IN PKEXCEPTION_FRAME ExceptionFrame
,
611 IN OUT PCONTEXT Context
)
613 PFX_SAVE_AREA FxSaveArea
;
617 FLOATING_SAVE_AREA UnalignedArea
;
619 FLOATING_SAVE_AREA
*FloatSaveArea
;
623 /* Do this at APC_LEVEL */
624 OldIrql
= KeGetCurrentIrql();
625 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
627 /* Start with the Control flags */
628 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
630 /* EBP, EIP and EFLAGS */
631 Context
->Ebp
= TrapFrame
->Ebp
;
632 Context
->Eip
= TrapFrame
->Eip
;
633 Context
->EFlags
= TrapFrame
->EFlags
;
635 /* Return the correct CS */
636 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
637 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
639 /* Get it from the Temp location */
640 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
644 /* Return it directly */
645 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
648 /* Get the Ss and ESP */
649 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
650 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
653 /* Handle the Segments */
654 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
656 /* Do V86 Mode first */
657 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
659 /* Return from the V86 location */
660 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
661 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
662 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
663 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
667 /* Check if this was a Kernel Trap */
668 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
670 /* Set valid selectors */
671 TrapFrame
->SegGs
= 0;
672 TrapFrame
->SegFs
= KGDT_R0_PCR
;
673 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
674 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
677 /* Return the segments */
678 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
679 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
680 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
681 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
685 /* Handle the simple registers */
686 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
688 /* Return them directly */
689 Context
->Eax
= TrapFrame
->Eax
;
690 Context
->Ebx
= TrapFrame
->Ebx
;
691 Context
->Ecx
= TrapFrame
->Ecx
;
692 Context
->Edx
= TrapFrame
->Edx
;
693 Context
->Esi
= TrapFrame
->Esi
;
694 Context
->Edi
= TrapFrame
->Edi
;
697 /* Handle extended registers */
698 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
699 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
701 /* Get the FX Save Area */
702 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
704 /* Make sure NPX is present */
705 if (KeI386NpxPresent
)
707 /* Flush the NPX State */
708 KiFlushNPXState(NULL
);
710 /* Copy the registers */
711 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
712 &FxSaveArea
->U
.FxArea
,
713 MAXIMUM_SUPPORTED_EXTENSION
);
717 /* Handle Floating Point */
718 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
719 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
721 /* Get the FX Save Area */
722 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
724 /* Make sure we have an NPX */
725 if (KeI386NpxPresent
)
727 /* Check if we have Fxsr support */
728 if (KeI386FxsrPresent
)
730 /* Align the floating area to 16-bytes */
731 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
732 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
735 KiFlushNPXState(FloatSaveArea
);
739 /* We don't, use the FN area and flush the NPX State */
740 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
741 KiFlushNPXState(NULL
);
745 Context
->FloatSave
.ControlWord
= FloatSaveArea
->ControlWord
;
746 Context
->FloatSave
.StatusWord
= FloatSaveArea
->StatusWord
;
747 Context
->FloatSave
.TagWord
= FloatSaveArea
->TagWord
;
748 Context
->FloatSave
.ErrorOffset
= FloatSaveArea
->ErrorOffset
;
749 Context
->FloatSave
.ErrorSelector
= FloatSaveArea
->ErrorSelector
;
750 Context
->FloatSave
.DataOffset
= FloatSaveArea
->DataOffset
;
751 Context
->FloatSave
.DataSelector
= FloatSaveArea
->DataSelector
;
752 Context
->FloatSave
.Cr0NpxState
= FxSaveArea
->Cr0NpxState
;
755 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
758 Context
->FloatSave
.RegisterArea
[i
] =
759 FloatSaveArea
->RegisterArea
[i
];
764 /* FIXME: Handle Emulation */
769 /* Handle debug registers */
770 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
771 CONTEXT_DEBUG_REGISTERS
)
773 /* Make sure DR7 is valid */
774 if (TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
)
776 /* Copy the debug registers */
777 Context
->Dr0
= TrapFrame
->Dr0
;
778 Context
->Dr1
= TrapFrame
->Dr1
;
779 Context
->Dr2
= TrapFrame
->Dr2
;
780 Context
->Dr3
= TrapFrame
->Dr3
;
781 Context
->Dr6
= TrapFrame
->Dr6
;
784 //Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
788 /* Otherwise clear DR registers */
798 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
803 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
804 IN PKEXCEPTION_FRAME ExceptionFrame
,
805 IN PKTRAP_FRAME TrapFrame
,
806 IN KPROCESSOR_MODE PreviousMode
,
807 IN BOOLEAN FirstChance
)
810 ULONG_PTR Stack
, NewStack
;
812 EXCEPTION_RECORD LocalExceptRecord
;
813 _SEH_DECLARE_LOCALS(KiCopyInfo
);
815 /* Increase number of Exception Dispatches */
816 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
818 /* Set the context flags */
819 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
821 /* Check if User Mode or if the debugger is enabled */
822 if ((PreviousMode
== UserMode
) || (KdDebuggerEnabled
))
824 /* Add the FPU Flag */
825 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
827 /* Check for NPX Support */
828 if (KeI386FxsrPresent
)
831 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
836 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
838 /* Look at our exception code */
839 switch (ExceptionRecord
->ExceptionCode
)
842 case STATUS_BREAKPOINT
:
844 /* Decrement EIP by one */
848 /* Internal exception */
849 case KI_EXCEPTION_ACCESS_VIOLATION
:
851 /* Set correct code */
852 ExceptionRecord
->ExceptionCode
= STATUS_ACCESS_VIOLATION
;
853 if (PreviousMode
== UserMode
)
855 /* FIXME: Handle no execute */
861 ASSERT(!((PreviousMode
== KernelMode
) &&
862 (Context
.EFlags
& EFLAGS_V86_MASK
)));
864 /* Handle kernel-mode first, it's simpler */
865 if (PreviousMode
== KernelMode
)
867 /* Check if this is a first-chance exception */
868 if (FirstChance
== TRUE
)
870 /* Break into the debugger for the first time */
871 if (KiDebugRoutine(TrapFrame
,
878 /* Exception was handled */
882 /* If the Debugger couldn't handle it, dispatch the exception */
883 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
886 /* This is a second-chance exception, only for the debugger */
887 if (KiDebugRoutine(TrapFrame
,
894 /* Exception was handled */
898 /* Third strike; you're out */
899 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
900 ExceptionRecord
->ExceptionCode
,
901 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
902 (ULONG_PTR
)TrapFrame
,
907 /* User mode exception, was it first-chance? */
910 /* Enter Debugger if available */
911 if (PsGetCurrentProcess()->DebugPort
)
916 else if (KiDebugRoutine(TrapFrame
,
923 /* Exception was handled */
927 /* Forward exception to user mode debugger */
928 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) goto Exit
;
930 /* Set up the user-stack */
934 /* Make sure we have a valid SS and that this isn't V86 mode */
935 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
936 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
938 /* Raise an exception instead */
939 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
940 LocalExceptRecord
.ExceptionFlags
= 0;
941 LocalExceptRecord
.NumberParameters
= 0;
942 RtlRaiseException(&LocalExceptRecord
);
945 /* Align context size and get stack pointer */
946 Size
= (sizeof(CONTEXT
) + 3) & ~3;
947 Stack
= (Context
.Esp
& ~3) - Size
;
949 /* Probe stack and copy Context */
950 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
951 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
953 /* Align exception record size and get stack pointer */
954 Size
= (sizeof(EXCEPTION_RECORD
) -
955 (EXCEPTION_MAXIMUM_PARAMETERS
-
956 ExceptionRecord
->NumberParameters
) *
957 sizeof(ULONG
) + 3) & ~3;
958 NewStack
= Stack
- Size
;
960 /* Probe stack and copy exception record */
961 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
962 Size
+ 2 * sizeof(ULONG_PTR
),
964 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
966 /* Now write the two params for the user-mode dispatcher */
967 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
968 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
970 /* Set new Stack Pointer */
971 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
972 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
974 /* Force correct segments */
975 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, PreviousMode
);
976 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
977 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
978 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, PreviousMode
);
979 TrapFrame
->SegGs
= 0;
981 /* Set EIP to the User-mode Dispatcher */
982 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
985 _SEH_EXCEPT(KiCopyInformation
)
987 /* Check if we got a stack overflow and raise that instead */
988 if (_SEH_VAR(SehExceptRecord
).ExceptionCode
==
989 STATUS_STACK_OVERFLOW
)
991 /* Copy the exception address and record */
992 _SEH_VAR(SehExceptRecord
).ExceptionAddress
=
993 ExceptionRecord
->ExceptionAddress
;
994 RtlCopyMemory(ExceptionRecord
,
995 (PVOID
)&_SEH_VAR(SehExceptRecord
),
996 sizeof(EXCEPTION_RECORD
));
998 /* Do the exception again */
1004 /* Dispatch exception to user-mode */
1008 /* Try second chance */
1009 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
))
1011 /* Handled, get out */
1014 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
1016 /* Handled, get out */
1020 /* 3rd strike, kill the process */
1021 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
1022 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
1023 ExceptionRecord
->ExceptionCode
,
1024 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1025 (ULONG_PTR
)TrapFrame
,
1030 /* Convert the context back into Trap/Exception Frames */
1031 KeContextToTrapFrame(&Context
,
1034 Context
.ContextFlags
,
1045 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1047 NTSTATUS Status
= STATUS_SUCCESS
;
1049 PTEB Teb
= KeGetCurrentThread()->Teb
;
1050 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
1052 /* Make sure we can access the TEB */
1055 /* Set the exception code */
1056 Teb
->ExceptionCode
= ExceptionCode
;
1060 /* Save exception code */
1061 Status
= ExceptionCode
;
1064 if (!NT_SUCCESS(Status
)) return Status
;
1066 /* Get the old EIP */
1067 OldEip
= TrapFrame
->Eip
;
1069 /* Change it to the user-mode dispatcher */
1070 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1072 /* Return the old EIP */
1073 return (NTSTATUS
)OldEip
;