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 *******************************************************************/
21 KdpEnterDebuggerException(IN PKTRAP_FRAME TrapFrame
,
22 IN PKEXCEPTION_FRAME ExceptionFrame
,
23 IN PEXCEPTION_RECORD ExceptionRecord
,
25 IN KPROCESSOR_MODE PreviousMode
,
26 IN BOOLEAN SecondChance
)
28 /* HACK (just like all this routine */
29 if (ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
)
40 KdInitSystem(IN ULONG BootPhase
,
41 IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
55 BOOLEAN _KdDebuggerEnabled
= FALSE
;
56 BOOLEAN _KdDebuggerNotPresent
= TRUE
;
57 BOOLEAN KdBreakAfterSymbolLoad
= FALSE
;
58 PKDEBUG_ROUTINE KiDebugRoutine
= KdpEnterDebuggerException
;
60 /* DR Registers in the CONTEXT structure */
61 UCHAR KiDebugRegisterContextOffsets
[9] =
63 FIELD_OFFSET(CONTEXT
, Dr0
),
64 FIELD_OFFSET(CONTEXT
, Dr1
),
65 FIELD_OFFSET(CONTEXT
, Dr2
),
66 FIELD_OFFSET(CONTEXT
, Dr3
),
69 FIELD_OFFSET(CONTEXT
, Dr6
),
70 FIELD_OFFSET(CONTEXT
, Dr7
),
74 /* DR Registers in the KTRAP_FRAME structure */
75 UCHAR KiDebugRegisterTrapOffsets
[9] =
77 FIELD_OFFSET(KTRAP_FRAME
, Dr0
),
78 FIELD_OFFSET(KTRAP_FRAME
, Dr1
),
79 FIELD_OFFSET(KTRAP_FRAME
, Dr2
),
80 FIELD_OFFSET(KTRAP_FRAME
, Dr3
),
83 FIELD_OFFSET(KTRAP_FRAME
, Dr6
),
84 FIELD_OFFSET(KTRAP_FRAME
, Dr7
),
88 /* FUNCTIONS *****************************************************************/
90 _SEH_DEFINE_LOCALS(KiCopyInfo
)
92 volatile EXCEPTION_RECORD SehExceptRecord
;
95 _SEH_FILTER(KiCopyInformation
)
97 _SEH_ACCESS_LOCALS(KiCopyInfo
);
99 /* Copy the exception records and return to the handler */
100 RtlCopyMemory((PVOID
)&_SEH_VAR(SehExceptRecord
),
101 _SEH_GetExceptionPointers()->ExceptionRecord
,
102 sizeof(EXCEPTION_RECORD
));
103 return EXCEPTION_EXECUTE_HANDLER
;
109 KeInitExceptions(VOID
)
112 USHORT FlippedSelector
;
113 extern KIDTENTRY KiIdt
[MAXIMUM_IDTVECTOR
];
116 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
118 /* Save the current Selector */
119 FlippedSelector
= KiIdt
[i
].Selector
;
121 /* Flip Selector and Extended Offset */
122 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
123 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
129 KiUpdateDr7(IN ULONG Dr7
)
131 ULONG DebugMask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
133 /* Check if debugging is enabled */
134 if (DebugMask
& DR_ACTIVE_MASK
)
137 ASSERT((DebugMask
& DR_REG_MASK
) != 0);
138 ASSERT((Dr7
& ~DR7_RESERVED_MASK
) == DR7_OVERRIDE_MASK
);
142 /* Return DR7 itself */
148 KiRecordDr7(OUT PULONG Dr7Ptr
,
154 /* Check if the caller gave us a mask */
157 /* He didn't use the one from the thread */
158 Mask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
162 /* He did, read it */
167 ASSERT((*Dr7Ptr
& DR7_RESERVED_MASK
) == 0);
169 /* Check if DR7 is empty */
176 /* Check the DR mask */
178 if (NewMask
& DR_REG_MASK
)
180 /* Set the active mask */
181 NewMask
|= DR_ACTIVE_MASK
;
183 /* Set DR7 override */
184 *DrMask
= DR7_OVERRIDE_MASK
;
189 ASSERT(NewMask
== 0);
194 /* Check if we have a mask or not */
195 Result
= NewMask
? TRUE
: FALSE
;
197 /* Update the mask to disable debugging */
198 NewMask
&= ~DR_ACTIVE_MASK
;
202 /* Check if caller wants the new mask */
210 /* Check if the mask changed */
214 KeGetCurrentThread()->DispatcherHeader
.DebugActive
= NewMask
;
218 /* Return the result */
224 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
226 /* Check if this is user-mode or V86 */
227 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
228 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
230 /* Return it directly */
231 return TrapFrame
->HardwareEsp
;
236 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
238 /* Return edited value */
239 return TrapFrame
->TempEsp
;
243 /* Virgin frame, calculate */
244 return (ULONG
)&TrapFrame
->HardwareEsp
;
251 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
254 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
256 /* Check if this is user-mode or V86 */
257 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
259 /* Write it directly */
260 TrapFrame
->HardwareEsp
= Esp
;
264 /* Don't allow ESP to be lowered, this is illegal */
265 if (Esp
< Previous
) KeBugCheck(SET_OF_INVALID_CONTEXT
);
267 /* Create an edit frame, check if it was alrady */
268 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
270 /* Update the value */
271 TrapFrame
->TempEsp
= Esp
;
275 /* Check if ESP changed */
279 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
280 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
283 TrapFrame
->TempEsp
= Esp
;
291 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
293 /* If this was V86 Mode */
294 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
297 return TrapFrame
->HardwareSegSs
;
299 else if (TrapFrame
->SegCs
& MODE_MASK
)
301 /* Usermode, return the User SS */
302 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
313 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
316 /* Remove the high-bits */
319 /* If this was V86 Mode */
320 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
323 TrapFrame
->HardwareSegSs
= Ss
;
325 else if (TrapFrame
->SegCs
& MODE_MASK
)
327 /* Usermode, save the User SS */
328 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
334 KiTagWordFnsaveToFxsave(USHORT TagWord
)
336 INT FxTagWord
= ~TagWord
;
339 * Empty is now 00, any 2 bits containing 1 mean valid
340 * Now convert the rest (11->0 and the rest to 1)
342 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
343 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
344 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
345 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
351 KeContextToTrapFrame(IN PCONTEXT Context
,
352 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
353 IN OUT PKTRAP_FRAME TrapFrame
,
354 IN ULONG ContextFlags
,
355 IN KPROCESSOR_MODE PreviousMode
)
357 PFX_SAVE_AREA FxSaveArea
;
359 BOOLEAN V86Switch
= FALSE
;
360 KIRQL OldIrql
= APC_LEVEL
;
364 /* Do this at APC_LEVEL */
365 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
367 /* Start with the basic Registers */
368 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
370 /* Check if we went through a V86 switch */
371 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
372 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
374 /* We did, remember this for later */
378 /* Copy EFLAGS and sanitize them*/
379 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
->EFlags
, PreviousMode
);
381 /* Copy EBP and EIP */
382 TrapFrame
->Ebp
= Context
->Ebp
;
383 TrapFrame
->Eip
= Context
->Eip
;
385 /* Check if we were in V86 Mode */
386 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
388 /* Simply copy the CS value */
389 TrapFrame
->SegCs
= Context
->SegCs
;
393 /* We weren't in V86, so sanitize the CS */
394 TrapFrame
->SegCs
= Ke386SanitizeSeg(Context
->SegCs
, PreviousMode
);
396 /* Don't let it under 8, that's invalid */
397 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
399 /* Force it to User CS */
400 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
404 /* Handle SS Specially for validation */
405 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
407 /* Write ESP back; take into account Edited Trap Frames */
408 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
410 /* Handle our V86 Bias if we went through a switch */
411 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
414 /* Process the Integer Registers */
415 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
417 /* Copy them manually */
418 TrapFrame
->Eax
= Context
->Eax
;
419 TrapFrame
->Ebx
= Context
->Ebx
;
420 TrapFrame
->Ecx
= Context
->Ecx
;
421 TrapFrame
->Edx
= Context
->Edx
;
422 TrapFrame
->Esi
= Context
->Esi
;
423 TrapFrame
->Edi
= Context
->Edi
;
426 /* Process the Context Segments */
427 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
429 /* Check if we were in V86 Mode */
430 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
432 /* Copy the V86 Segments directly */
433 TrapFrame
->V86Ds
= Context
->SegDs
;
434 TrapFrame
->V86Es
= Context
->SegEs
;
435 TrapFrame
->V86Fs
= Context
->SegFs
;
436 TrapFrame
->V86Gs
= Context
->SegGs
;
438 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
440 /* For kernel mode, write the standard values */
441 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
442 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
443 TrapFrame
->SegFs
= Ke386SanitizeSeg(Context
->SegFs
, PreviousMode
);
444 TrapFrame
->SegGs
= 0;
448 /* For user mode, return the values directly */
449 TrapFrame
->SegDs
= Context
->SegDs
;
450 TrapFrame
->SegEs
= Context
->SegEs
;
451 TrapFrame
->SegFs
= Context
->SegFs
;
453 /* Handle GS specially */
454 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
456 /* Don't use it, if user */
457 TrapFrame
->SegGs
= 0;
461 /* Copy it if kernel */
462 TrapFrame
->SegGs
= Context
->SegGs
;
467 /* Handle the extended registers */
468 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
469 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
471 /* Get the FX Area */
472 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
474 /* Check if NPX is present */
475 if (KeI386NpxPresent
)
477 /* Flush the NPX State */
478 KiFlushNPXState(NULL
);
480 /* Copy the FX State */
481 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
482 &Context
->ExtendedRegisters
[0],
483 MAXIMUM_SUPPORTED_EXTENSION
);
485 /* Remove reserved bits from MXCSR */
486 FxSaveArea
->U
.FxArea
.MXCsr
&= ~0xFFBF;
488 /* Mask out any invalid flags */
489 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
491 /* Check if this is a VDM app */
492 if (PsGetCurrentProcess()->VdmObjects
)
494 /* Allow the EM flag */
495 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
501 /* Handle the floating point state */
502 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
503 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
505 /* Get the FX Area */
506 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
508 /* Check if NPX is present */
509 if (KeI386NpxPresent
)
511 /* Flush the NPX State */
512 KiFlushNPXState(NULL
);
514 /* Check if we have Fxsr support */
515 if (KeI386FxsrPresent
)
517 /* Convert the Fn Floating Point state to Fx */
518 FxSaveArea
->U
.FxArea
.ControlWord
=
519 (USHORT
)Context
->FloatSave
.ControlWord
;
520 FxSaveArea
->U
.FxArea
.StatusWord
=
521 (USHORT
)Context
->FloatSave
.StatusWord
;
522 FxSaveArea
->U
.FxArea
.TagWord
=
523 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
524 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
525 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
526 FxSaveArea
->U
.FxArea
.ErrorOffset
=
527 Context
->FloatSave
.ErrorOffset
;
528 FxSaveArea
->U
.FxArea
.ErrorSelector
=
529 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
530 FxSaveArea
->U
.FxArea
.DataOffset
=
531 Context
->FloatSave
.DataOffset
;
532 FxSaveArea
->U
.FxArea
.DataSelector
=
533 Context
->FloatSave
.DataSelector
;
535 /* Clear out the Register Area */
536 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
537 SIZE_OF_FX_REGISTERS
);
539 /* Loop the 8 floating point registers */
540 for (i
= 0; i
< 8; i
++)
542 /* Copy from Fn to Fx */
543 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
544 Context
->FloatSave
.RegisterArea
+ (i
* 10),
550 /* Copy the structure */
551 FxSaveArea
->U
.FnArea
.ControlWord
= Context
->FloatSave
.
553 FxSaveArea
->U
.FnArea
.StatusWord
= Context
->FloatSave
.
555 FxSaveArea
->U
.FnArea
.TagWord
= Context
->FloatSave
.TagWord
;
556 FxSaveArea
->U
.FnArea
.ErrorOffset
= Context
->FloatSave
.
558 FxSaveArea
->U
.FnArea
.ErrorSelector
= Context
->FloatSave
.
560 FxSaveArea
->U
.FnArea
.DataOffset
= Context
->FloatSave
.
562 FxSaveArea
->U
.FnArea
.DataSelector
= Context
->FloatSave
.
566 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
569 FxSaveArea
->U
.FnArea
.RegisterArea
[i
] =
570 Context
->FloatSave
.RegisterArea
[i
];
574 /* Mask out any invalid flags */
575 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
577 /* Check if this is a VDM app */
578 if (PsGetCurrentProcess()->VdmObjects
)
580 /* Allow the EM flag */
581 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
587 /* FIXME: Handle FPU Emulation */
592 /* Handle the Debug Registers */
593 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
595 /* Loop DR registers */
596 for (i
= 0; i
< 4; i
++)
598 /* Sanitize the context DR Address */
599 SafeDr
= Ke386SanitizeDr(KiDrFromContext(i
, Context
), PreviousMode
);
601 /* Save it in the trap frame */
602 *KiDrFromTrapFrame(i
, TrapFrame
) = SafeDr
;
604 /* Check if this DR address is active and add it in the DR mask */
605 if (SafeDr
) DrMask
|= DR_MASK(i
);
608 /* Now save and sanitize DR6 */
609 TrapFrame
->Dr6
= Context
->Dr6
& DR6_LEGAL
;
610 if (TrapFrame
->Dr6
) DrMask
|= DR_MASK(6);
612 /* Save and sanitize DR7 */
613 TrapFrame
->Dr7
= Context
->Dr7
& DR7_LEGAL
;
614 KiRecordDr7(&TrapFrame
->Dr7
, &DrMask
);
616 /* If we're in user-mode */
617 if (PreviousMode
!= KernelMode
)
619 /* FIXME: Save the mask */
620 //KeGetCurrentThread()->DispatcherHeader.DebugActive = DrMask;
624 /* Check if thread has IOPL and force it enabled if so */
625 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= 0x3000;
628 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
633 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
634 IN PKEXCEPTION_FRAME ExceptionFrame
,
635 IN OUT PCONTEXT Context
)
637 PFX_SAVE_AREA FxSaveArea
;
641 FLOATING_SAVE_AREA UnalignedArea
;
643 FLOATING_SAVE_AREA
*FloatSaveArea
;
644 KIRQL OldIrql
= APC_LEVEL
;
647 /* Do this at APC_LEVEL */
648 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
650 /* Start with the Control flags */
651 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
653 /* EBP, EIP and EFLAGS */
654 Context
->Ebp
= TrapFrame
->Ebp
;
655 Context
->Eip
= TrapFrame
->Eip
;
656 Context
->EFlags
= TrapFrame
->EFlags
;
658 /* Return the correct CS */
659 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
660 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
662 /* Get it from the Temp location */
663 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
667 /* Return it directly */
668 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
671 /* Get the Ss and ESP */
672 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
673 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
676 /* Handle the Segments */
677 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
679 /* Do V86 Mode first */
680 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
682 /* Return from the V86 location */
683 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
684 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
685 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
686 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
690 /* Check if this was a Kernel Trap */
691 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
693 /* Set valid selectors */
694 TrapFrame
->SegGs
= 0;
695 TrapFrame
->SegFs
= KGDT_R0_PCR
;
696 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
697 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
700 /* Return the segments */
701 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
702 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
703 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
704 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
708 /* Handle the simple registers */
709 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
711 /* Return them directly */
712 Context
->Eax
= TrapFrame
->Eax
;
713 Context
->Ebx
= TrapFrame
->Ebx
;
714 Context
->Ecx
= TrapFrame
->Ecx
;
715 Context
->Edx
= TrapFrame
->Edx
;
716 Context
->Esi
= TrapFrame
->Esi
;
717 Context
->Edi
= TrapFrame
->Edi
;
720 /* Handle extended registers */
721 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
722 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
724 /* Get the FX Save Area */
725 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
727 /* Make sure NPX is present */
728 if (KeI386NpxPresent
)
730 /* Flush the NPX State */
731 KiFlushNPXState(NULL
);
733 /* Copy the registers */
734 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
735 &FxSaveArea
->U
.FxArea
,
736 MAXIMUM_SUPPORTED_EXTENSION
);
740 /* Handle Floating Point */
741 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
742 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
744 /* Get the FX Save Area */
745 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
747 /* Make sure we have an NPX */
748 if (KeI386NpxPresent
)
750 /* Check if we have Fxsr support */
751 if (KeI386FxsrPresent
)
753 /* Align the floating area to 16-bytes */
754 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
755 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
758 KiFlushNPXState(FloatSaveArea
);
762 /* We don't, use the FN area and flush the NPX State */
763 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
764 KiFlushNPXState(NULL
);
768 Context
->FloatSave
.ControlWord
= FloatSaveArea
->ControlWord
;
769 Context
->FloatSave
.StatusWord
= FloatSaveArea
->StatusWord
;
770 Context
->FloatSave
.TagWord
= FloatSaveArea
->TagWord
;
771 Context
->FloatSave
.ErrorOffset
= FloatSaveArea
->ErrorOffset
;
772 Context
->FloatSave
.ErrorSelector
= FloatSaveArea
->ErrorSelector
;
773 Context
->FloatSave
.DataOffset
= FloatSaveArea
->DataOffset
;
774 Context
->FloatSave
.DataSelector
= FloatSaveArea
->DataSelector
;
775 Context
->FloatSave
.Cr0NpxState
= FxSaveArea
->Cr0NpxState
;
778 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
781 Context
->FloatSave
.RegisterArea
[i
] =
782 FloatSaveArea
->RegisterArea
[i
];
787 /* FIXME: Handle Emulation */
792 /* Handle debug registers */
793 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
794 CONTEXT_DEBUG_REGISTERS
)
796 /* Make sure DR7 is valid */
797 if (TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
)
799 /* Copy the debug registers */
800 Context
->Dr0
= TrapFrame
->Dr0
;
801 Context
->Dr1
= TrapFrame
->Dr1
;
802 Context
->Dr2
= TrapFrame
->Dr2
;
803 Context
->Dr3
= TrapFrame
->Dr3
;
804 Context
->Dr6
= TrapFrame
->Dr6
;
807 //Context->Dr7 = KiUpdateDr7(TrapFrame->Dr7);
811 /* Otherwise clear DR registers */
821 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
826 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
827 IN PKEXCEPTION_FRAME ExceptionFrame
,
828 IN PKTRAP_FRAME TrapFrame
,
829 IN KPROCESSOR_MODE PreviousMode
,
830 IN BOOLEAN FirstChance
)
833 ULONG_PTR Stack
, NewStack
;
835 EXCEPTION_RECORD LocalExceptRecord
;
836 _SEH_DECLARE_LOCALS(KiCopyInfo
);
838 /* Increase number of Exception Dispatches */
839 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
841 /* Set the context flags */
842 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
844 /* Check if User Mode or if the debugger is enabled */
845 if ((PreviousMode
== UserMode
) || (KdDebuggerEnabled
))
847 /* Add the FPU Flag */
848 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
850 /* Check for NPX Support */
851 if (KeI386FxsrPresent
)
854 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
859 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
862 if (ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
)
864 /* Decrement EIP by one */
869 ASSERT(!((PreviousMode
== KernelMode
) &&
870 (Context
.EFlags
& EFLAGS_V86_MASK
)));
872 /* Handle kernel-mode first, it's simpler */
873 if (PreviousMode
== KernelMode
)
875 /* Check if this is a first-chance exception */
876 if (FirstChance
== TRUE
)
878 /* Break into the debugger for the first time */
879 if (KiDebugRoutine(TrapFrame
,
886 /* Exception was handled */
890 /* If the Debugger couldn't handle it, dispatch the exception */
891 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
894 /* This is a second-chance exception, only for the debugger */
895 if (KiDebugRoutine(TrapFrame
,
902 /* Exception was handled */
906 /* Third strike; you're out */
907 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
908 ExceptionRecord
->ExceptionCode
,
909 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
910 ExceptionRecord
->ExceptionInformation
[0],
911 ExceptionRecord
->ExceptionInformation
[1]);
915 /* User mode exception, was it first-chance? */
918 /* Enter Debugger if available */
919 if (PsGetCurrentProcess()->DebugPort
)
924 else if (KiDebugRoutine(TrapFrame
,
931 /* Exception was handled */
935 /* Forward exception to user mode debugger */
936 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) goto Exit
;
938 /* Set up the user-stack */
942 /* Make sure we have a valid SS and that this isn't V86 mode */
943 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
944 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
946 /* Raise an exception instead */
947 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
948 LocalExceptRecord
.ExceptionFlags
= 0;
949 LocalExceptRecord
.NumberParameters
= 0;
950 RtlRaiseException(&LocalExceptRecord
);
953 /* Align context size and get stack pointer */
954 Size
= (sizeof(CONTEXT
) + 3) & ~3;
955 Stack
= (Context
.Esp
& ~3) - Size
;
957 /* Probe stack and copy Context */
958 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
959 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
961 /* Align exception record size and get stack pointer */
962 Size
= (sizeof(EXCEPTION_RECORD
) -
963 (EXCEPTION_MAXIMUM_PARAMETERS
-
964 ExceptionRecord
->NumberParameters
) *
965 sizeof(ULONG
) + 3) & ~3;
966 NewStack
= Stack
- Size
;
968 /* Probe stack and copy exception record */
969 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
970 Size
+ 2 * sizeof(ULONG_PTR
),
972 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
974 /* Now write the two params for the user-mode dispatcher */
975 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
976 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
978 /* Set new Stack Pointer */
979 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
980 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
982 /* Force correct segments */
983 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, PreviousMode
);
984 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
985 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
986 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, PreviousMode
);
987 TrapFrame
->SegGs
= 0;
989 /* Set EIP to the User-mode Dispatcher */
990 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
993 _SEH_EXCEPT(KiCopyInformation
)
995 /* Check if we got a stack overflow and raise that instead */
996 if (_SEH_VAR(SehExceptRecord
).ExceptionCode
==
997 STATUS_STACK_OVERFLOW
)
999 /* Copy the exception address and record */
1000 _SEH_VAR(SehExceptRecord
).ExceptionAddress
=
1001 ExceptionRecord
->ExceptionAddress
;
1002 RtlCopyMemory(ExceptionRecord
,
1003 (PVOID
)&_SEH_VAR(SehExceptRecord
),
1004 sizeof(EXCEPTION_RECORD
));
1006 /* Do the exception again */
1007 goto DispatchToUser
;
1012 /* Dispatch exception to user-mode */
1016 /* Try second chance */
1017 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
))
1019 /* Handled, get out */
1022 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
1024 /* Handled, get out */
1028 /* 3rd strike, kill the process */
1029 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
1030 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
1031 ExceptionRecord
->ExceptionCode
,
1032 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1033 ExceptionRecord
->ExceptionInformation
[0],
1034 ExceptionRecord
->ExceptionInformation
[1]);
1038 /* Convert the context back into Trap/Exception Frames */
1039 KeContextToTrapFrame(&Context
,
1042 Context
.ContextFlags
,
1053 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1055 NTSTATUS Status
= STATUS_SUCCESS
;
1057 PTEB Teb
= KeGetCurrentThread()->Teb
;
1058 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
1060 /* Make sure we can access the TEB */
1063 /* Set the exception code */
1064 Teb
->ExceptionCode
= ExceptionCode
;
1068 /* Save exception code */
1069 Status
= ExceptionCode
;
1072 if (!NT_SUCCESS(Status
)) return Status
;
1074 /* Get the old EIP */
1075 OldEip
= TrapFrame
->Eip
;
1077 /* Change it to the user-mode dispatcher */
1078 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1080 /* Return the old EIP */
1081 return (NTSTATUS
)OldEip
;