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_ACTIVE_MASK
)
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 */
137 if (NewMask
& DR_REG_MASK
)
139 /* Set the active mask */
140 NewMask
|= DR_ACTIVE_MASK
;
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_ACTIVE_MASK
;
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
,
213 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
215 /* Check if this is user-mode or V86 */
216 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
218 /* Write it directly */
219 TrapFrame
->HardwareEsp
= Esp
;
223 /* Don't allow ESP to be lowered, this is illegal */
224 if (Esp
< Previous
) KeBugCheck(SET_OF_INVALID_CONTEXT
);
226 /* Create an edit frame, check if it was alrady */
227 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
229 /* Update the value */
230 TrapFrame
->TempEsp
= Esp
;
234 /* Check if ESP changed */
238 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
239 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
242 TrapFrame
->TempEsp
= Esp
;
250 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
252 /* If this was V86 Mode */
253 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
256 return TrapFrame
->HardwareSegSs
;
258 else if (TrapFrame
->SegCs
& MODE_MASK
)
260 /* Usermode, return the User SS */
261 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
272 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
275 /* Remove the high-bits */
278 /* If this was V86 Mode */
279 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
282 TrapFrame
->HardwareSegSs
= Ss
;
284 else if (TrapFrame
->SegCs
& MODE_MASK
)
286 /* Usermode, save the User SS */
287 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
293 KiTagWordFnsaveToFxsave(USHORT TagWord
)
295 INT FxTagWord
= ~TagWord
;
298 * Empty is now 00, any 2 bits containing 1 mean valid
299 * Now convert the rest (11->0 and the rest to 1)
301 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
302 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
303 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
304 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
310 KeContextToTrapFrame(IN PCONTEXT Context
,
311 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
312 IN OUT PKTRAP_FRAME TrapFrame
,
313 IN ULONG ContextFlags
,
314 IN KPROCESSOR_MODE PreviousMode
)
316 PFX_SAVE_AREA FxSaveArea
;
318 BOOLEAN V86Switch
= FALSE
;
319 KIRQL OldIrql
= APC_LEVEL
;
323 /* Do this at APC_LEVEL */
324 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
326 /* Start with the basic Registers */
327 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
329 /* Check if we went through a V86 switch */
330 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
331 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
333 /* We did, remember this for later */
337 /* Copy EFLAGS and sanitize them*/
338 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
->EFlags
, PreviousMode
);
340 /* Copy EBP and EIP */
341 TrapFrame
->Ebp
= Context
->Ebp
;
342 TrapFrame
->Eip
= Context
->Eip
;
344 /* Check if we were in V86 Mode */
345 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
347 /* Simply copy the CS value */
348 TrapFrame
->SegCs
= Context
->SegCs
;
352 /* We weren't in V86, so sanitize the CS */
353 TrapFrame
->SegCs
= Ke386SanitizeSeg(Context
->SegCs
, PreviousMode
);
355 /* Don't let it under 8, that's invalid */
356 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
358 /* Force it to User CS */
359 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
363 /* Handle SS Specially for validation */
364 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
366 /* Write ESP back; take into account Edited Trap Frames */
367 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
369 /* Handle our V86 Bias if we went through a switch */
370 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
373 /* Process the Integer Registers */
374 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
376 /* Copy them manually */
377 TrapFrame
->Eax
= Context
->Eax
;
378 TrapFrame
->Ebx
= Context
->Ebx
;
379 TrapFrame
->Ecx
= Context
->Ecx
;
380 TrapFrame
->Edx
= Context
->Edx
;
381 TrapFrame
->Esi
= Context
->Esi
;
382 TrapFrame
->Edi
= Context
->Edi
;
385 /* Process the Context Segments */
386 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
388 /* Check if we were in V86 Mode */
389 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
391 /* Copy the V86 Segments directly */
392 TrapFrame
->V86Ds
= Context
->SegDs
;
393 TrapFrame
->V86Es
= Context
->SegEs
;
394 TrapFrame
->V86Fs
= Context
->SegFs
;
395 TrapFrame
->V86Gs
= Context
->SegGs
;
397 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
399 /* For kernel mode, write the standard values */
400 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
401 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
402 TrapFrame
->SegFs
= Ke386SanitizeSeg(Context
->SegFs
, PreviousMode
);
403 TrapFrame
->SegGs
= 0;
407 /* For user mode, return the values directly */
408 TrapFrame
->SegDs
= Context
->SegDs
;
409 TrapFrame
->SegEs
= Context
->SegEs
;
410 TrapFrame
->SegFs
= Context
->SegFs
;
412 /* Handle GS specially */
413 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
415 /* Don't use it, if user */
416 TrapFrame
->SegGs
= 0;
420 /* Copy it if kernel */
421 TrapFrame
->SegGs
= Context
->SegGs
;
426 /* Handle the extended registers */
427 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
428 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
430 /* Get the FX Area */
431 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
433 /* Check if NPX is present */
434 if (KeI386NpxPresent
)
436 /* Flush the NPX State */
437 KiFlushNPXState(NULL
);
439 /* Copy the FX State */
440 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
441 &Context
->ExtendedRegisters
[0],
442 MAXIMUM_SUPPORTED_EXTENSION
);
444 /* Remove reserved bits from MXCSR */
445 FxSaveArea
->U
.FxArea
.MXCsr
&= ~0xFFBF;
447 /* Mask out any invalid flags */
448 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
450 /* Check if this is a VDM app */
451 if (PsGetCurrentProcess()->VdmObjects
)
453 /* Allow the EM flag */
454 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
460 /* Handle the floating point state */
461 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
462 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
464 /* Get the FX Area */
465 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
467 /* Check if NPX is present */
468 if (KeI386NpxPresent
)
470 /* Flush the NPX State */
471 KiFlushNPXState(NULL
);
473 /* Check if we have Fxsr support */
474 if (KeI386FxsrPresent
)
476 /* Convert the Fn Floating Point state to Fx */
477 FxSaveArea
->U
.FxArea
.ControlWord
=
478 (USHORT
)Context
->FloatSave
.ControlWord
;
479 FxSaveArea
->U
.FxArea
.StatusWord
=
480 (USHORT
)Context
->FloatSave
.StatusWord
;
481 FxSaveArea
->U
.FxArea
.TagWord
=
482 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
483 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
484 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
485 FxSaveArea
->U
.FxArea
.ErrorOffset
=
486 Context
->FloatSave
.ErrorOffset
;
487 FxSaveArea
->U
.FxArea
.ErrorSelector
=
488 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
489 FxSaveArea
->U
.FxArea
.DataOffset
=
490 Context
->FloatSave
.DataOffset
;
491 FxSaveArea
->U
.FxArea
.DataSelector
=
492 Context
->FloatSave
.DataSelector
;
494 /* Clear out the Register Area */
495 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
496 SIZE_OF_FX_REGISTERS
);
498 /* Loop the 8 floating point registers */
499 for (i
= 0; i
< 8; i
++)
501 /* Copy from Fn to Fx */
502 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
503 Context
->FloatSave
.RegisterArea
+ (i
* 10),
509 /* Copy the structure */
510 FxSaveArea
->U
.FnArea
.ControlWord
= Context
->FloatSave
.
512 FxSaveArea
->U
.FnArea
.StatusWord
= Context
->FloatSave
.
514 FxSaveArea
->U
.FnArea
.TagWord
= Context
->FloatSave
.TagWord
;
515 FxSaveArea
->U
.FnArea
.ErrorOffset
= Context
->FloatSave
.
517 FxSaveArea
->U
.FnArea
.ErrorSelector
= Context
->FloatSave
.
519 FxSaveArea
->U
.FnArea
.DataOffset
= Context
->FloatSave
.
521 FxSaveArea
->U
.FnArea
.DataSelector
= Context
->FloatSave
.
525 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
528 FxSaveArea
->U
.FnArea
.RegisterArea
[i
] =
529 Context
->FloatSave
.RegisterArea
[i
];
533 /* Mask out any invalid flags */
534 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
536 /* Check if this is a VDM app */
537 if (PsGetCurrentProcess()->VdmObjects
)
539 /* Allow the EM flag */
540 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
546 /* FIXME: Handle FPU Emulation */
551 /* Handle the Debug Registers */
552 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
554 /* Loop DR registers */
555 for (i
= 0; i
< 4; i
++)
557 /* Sanitize the context DR Address */
558 SafeDr
= Ke386SanitizeDr(KiDrFromContext(i
, Context
), PreviousMode
);
560 /* Save it in the trap frame */
561 *KiDrFromTrapFrame(i
, TrapFrame
) = SafeDr
;
563 /* Check if this DR address is active and add it in the DR mask */
564 if (SafeDr
) DrMask
|= DR_MASK(i
);
567 /* Now save and sanitize DR6 */
568 TrapFrame
->Dr6
= Context
->Dr6
& DR6_LEGAL
;
569 if (TrapFrame
->Dr6
) DrMask
|= DR_MASK(6);
571 /* Save and sanitize DR7 */
572 TrapFrame
->Dr7
= Context
->Dr7
& DR7_LEGAL
;
573 KiRecordDr7(&TrapFrame
->Dr7
, &DrMask
);
575 /* If we're in user-mode */
576 if (PreviousMode
!= KernelMode
)
578 /* FIXME: Save the mask */
579 //KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
583 /* Check if thread has IOPL and force it enabled if so */
584 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= 0x3000;
587 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
592 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
593 IN PKEXCEPTION_FRAME ExceptionFrame
,
594 IN OUT PCONTEXT Context
)
596 PFX_SAVE_AREA FxSaveArea
;
600 FLOATING_SAVE_AREA UnalignedArea
;
602 FLOATING_SAVE_AREA
*FloatSaveArea
;
603 KIRQL OldIrql
= APC_LEVEL
;
606 /* Do this at APC_LEVEL */
607 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
609 /* Start with the Control flags */
610 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
612 /* EBP, EIP and EFLAGS */
613 Context
->Ebp
= TrapFrame
->Ebp
;
614 Context
->Eip
= TrapFrame
->Eip
;
615 Context
->EFlags
= TrapFrame
->EFlags
;
617 /* Return the correct CS */
618 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
619 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
621 /* Get it from the Temp location */
622 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
626 /* Return it directly */
627 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
630 /* Get the Ss and ESP */
631 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
632 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
635 /* Handle the Segments */
636 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
638 /* Do V86 Mode first */
639 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
641 /* Return from the V86 location */
642 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
643 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
644 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
645 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
649 /* Check if this was a Kernel Trap */
650 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
652 /* Set valid selectors */
653 TrapFrame
->SegGs
= 0;
654 TrapFrame
->SegFs
= KGDT_R0_PCR
;
655 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
656 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
659 /* Return the segments */
660 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
661 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
662 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
663 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
667 /* Handle the simple registers */
668 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
670 /* Return them directly */
671 Context
->Eax
= TrapFrame
->Eax
;
672 Context
->Ebx
= TrapFrame
->Ebx
;
673 Context
->Ecx
= TrapFrame
->Ecx
;
674 Context
->Edx
= TrapFrame
->Edx
;
675 Context
->Esi
= TrapFrame
->Esi
;
676 Context
->Edi
= TrapFrame
->Edi
;
679 /* Handle extended registers */
680 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
681 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
683 /* Get the FX Save Area */
684 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
686 /* Make sure NPX is present */
687 if (KeI386NpxPresent
)
689 /* Flush the NPX State */
690 KiFlushNPXState(NULL
);
692 /* Copy the registers */
693 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
694 &FxSaveArea
->U
.FxArea
,
695 MAXIMUM_SUPPORTED_EXTENSION
);
699 /* Handle Floating Point */
700 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
701 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
703 /* Get the FX Save Area */
704 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
706 /* Make sure we have an NPX */
707 if (KeI386NpxPresent
)
709 /* Check if we have Fxsr support */
710 if (KeI386FxsrPresent
)
712 /* Align the floating area to 16-bytes */
713 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
714 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
717 KiFlushNPXState(FloatSaveArea
);
721 /* We don't, use the FN area and flush the NPX State */
722 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
723 KiFlushNPXState(NULL
);
727 Context
->FloatSave
.ControlWord
= FloatSaveArea
->ControlWord
;
728 Context
->FloatSave
.StatusWord
= FloatSaveArea
->StatusWord
;
729 Context
->FloatSave
.TagWord
= FloatSaveArea
->TagWord
;
730 Context
->FloatSave
.ErrorOffset
= FloatSaveArea
->ErrorOffset
;
731 Context
->FloatSave
.ErrorSelector
= FloatSaveArea
->ErrorSelector
;
732 Context
->FloatSave
.DataOffset
= FloatSaveArea
->DataOffset
;
733 Context
->FloatSave
.DataSelector
= FloatSaveArea
->DataSelector
;
734 Context
->FloatSave
.Cr0NpxState
= FxSaveArea
->Cr0NpxState
;
737 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
740 Context
->FloatSave
.RegisterArea
[i
] =
741 FloatSaveArea
->RegisterArea
[i
];
746 /* FIXME: Handle Emulation */
751 /* Handle debug registers */
752 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
753 CONTEXT_DEBUG_REGISTERS
)
755 /* Make sure DR7 is valid */
756 if (TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
)
758 /* Copy the debug registers */
759 Context
->Dr0
= TrapFrame
->Dr0
;
760 Context
->Dr1
= TrapFrame
->Dr1
;
761 Context
->Dr2
= TrapFrame
->Dr2
;
762 Context
->Dr3
= TrapFrame
->Dr3
;
763 Context
->Dr6
= TrapFrame
->Dr6
;
766 //Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
770 /* Otherwise clear DR registers */
780 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
785 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
786 IN PKEXCEPTION_FRAME ExceptionFrame
,
787 IN PKTRAP_FRAME TrapFrame
,
788 IN KPROCESSOR_MODE PreviousMode
,
789 IN BOOLEAN FirstChance
)
792 ULONG_PTR Stack
, NewStack
;
794 EXCEPTION_RECORD LocalExceptRecord
;
795 _SEH_DECLARE_LOCALS(KiCopyInfo
);
797 /* Increase number of Exception Dispatches */
798 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
800 /* Set the context flags */
801 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
803 /* Check if User Mode or if the debugger isenabled */
804 if ((PreviousMode
== UserMode
) || (KdDebuggerEnabled
))
806 /* Add the FPU Flag */
807 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
809 /* Check for NPX Support */
810 if (KeI386FxsrPresent
)
813 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
818 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
821 if (ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
)
823 /* Decrement EIP by one */
828 ASSERT(!((PreviousMode
== KernelMode
) &&
829 (Context
.EFlags
& EFLAGS_V86_MASK
)));
831 /* Handle kernel-mode first, it's simpler */
832 if (PreviousMode
== KernelMode
)
834 /* Check if this is a first-chance exception */
835 if (FirstChance
== TRUE
)
837 /* Break into the debugger for the first time */
838 if (KiDebugRoutine(TrapFrame
,
845 /* Exception was handled */
849 /* HACK: GDB Entry */
850 if (KdpCallGdb(TrapFrame
, ExceptionRecord
, &Context
)) goto Handled
;
852 /* If the Debugger couldn't handle it, dispatch the exception */
853 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
856 /* This is a second-chance exception, only for the debugger */
857 if (KiDebugRoutine(TrapFrame
,
864 /* Exception was handled */
868 /* Third strike; you're out */
869 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
870 ExceptionRecord
->ExceptionCode
,
871 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
872 ExceptionRecord
->ExceptionInformation
[0],
873 ExceptionRecord
->ExceptionInformation
[1]);
877 /* User mode exception, was it first-chance? */
880 /* Enter Debugger if available */
881 if (PsGetCurrentProcess()->DebugPort
)
886 else if (KiDebugRoutine(TrapFrame
,
893 /* Exception was handled */
897 /* HACK: GDB Entry */
898 if (KdpCallGdb(TrapFrame
, ExceptionRecord
, &Context
)) goto Handled
;
900 /* Forward exception to user mode debugger */
901 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) goto Exit
;
903 /* Set up the user-stack */
907 /* Make sure we have a valid SS and that this isn't V86 mode */
908 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
909 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
911 /* Raise an exception instead */
912 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
913 LocalExceptRecord
.ExceptionFlags
= 0;
914 LocalExceptRecord
.NumberParameters
= 0;
915 RtlRaiseException(&LocalExceptRecord
);
918 /* Align context size and get stack pointer */
919 Size
= (sizeof(CONTEXT
) + 3) & ~3;
920 Stack
= (Context
.Esp
& ~3) - Size
;
922 /* Probe stack and copy Context */
923 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
924 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
926 /* Align exception record size and get stack pointer */
927 Size
= (sizeof(EXCEPTION_RECORD
) -
928 (EXCEPTION_MAXIMUM_PARAMETERS
-
929 ExceptionRecord
->NumberParameters
) *
930 sizeof(ULONG
) + 3) & ~3;
931 NewStack
= Stack
- Size
;
933 /* Probe stack and copy exception record */
934 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
935 Size
+ 2 * sizeof(ULONG_PTR
),
937 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
939 /* Now write the two params for the user-mode dispatcher */
940 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
941 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
943 /* Set new Stack Pointer */
944 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
945 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
947 /* Force correct segments */
948 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, PreviousMode
);
949 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
950 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
951 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, PreviousMode
);
952 TrapFrame
->SegGs
= 0;
954 /* Set EIP to the User-mode Dispatcher */
955 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
958 _SEH_EXCEPT(KiCopyInformation
)
960 /* Check if we got a stack overflow and raise that instead */
961 if (_SEH_VAR(SehExceptRecord
).ExceptionCode
==
962 STATUS_STACK_OVERFLOW
)
964 /* Copy the exception address and record */
965 _SEH_VAR(SehExceptRecord
).ExceptionAddress
=
966 ExceptionRecord
->ExceptionAddress
;
967 RtlCopyMemory(ExceptionRecord
,
968 (PVOID
)&_SEH_VAR(SehExceptRecord
),
969 sizeof(EXCEPTION_RECORD
));
971 /* Do the exception again */
977 /* Dispatch exception to user-mode */
981 /* Try second chance */
982 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
))
984 /* Handled, get out */
987 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
989 /* Handled, get out */
993 /* 3rd strike, kill the process */
994 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
995 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
996 ExceptionRecord
->ExceptionCode
,
997 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
998 ExceptionRecord
->ExceptionInformation
[0],
999 ExceptionRecord
->ExceptionInformation
[1]);
1003 /* Convert the context back into Trap/Exception Frames */
1004 KeContextToTrapFrame(&Context
,
1007 Context
.ContextFlags
,
1018 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1020 NTSTATUS Status
= STATUS_SUCCESS
;
1022 PTEB Teb
= KeGetCurrentThread()->Teb
;
1023 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
1025 /* Make sure we can access the TEB */
1028 /* Set the exception code */
1029 Teb
->ExceptionCode
= ExceptionCode
;
1033 /* Save exception code */
1034 Status
= ExceptionCode
;
1037 if (!NT_SUCCESS(Status
)) return Status
;
1039 /* Get the old EIP */
1040 OldEip
= TrapFrame
->Eip
;
1042 /* Change it to the user-mode dispatcher */
1043 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1045 /* Return the old EIP */
1046 return (NTSTATUS
)OldEip
;