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
=
178 /* Return the result */
184 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
186 /* Check if this is user-mode or V86 */
187 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
188 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
190 /* Return it directly */
191 return TrapFrame
->HardwareEsp
;
196 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
198 /* Return edited value */
199 return TrapFrame
->TempEsp
;
203 /* Virgin frame, calculate */
204 return (ULONG
)&TrapFrame
->HardwareEsp
;
211 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
217 /* Raise to APC_LEVEL if needed */
218 OldIrql
= KeGetCurrentIrql();
219 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
221 /* Get the old ESP */
222 Previous
= KiEspFromTrapFrame(TrapFrame
);
224 /* Check if this is user-mode or V86 */
225 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
226 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
228 /* Write it directly */
229 TrapFrame
->HardwareEsp
= Esp
;
233 /* Don't allow ESP to be lowered, this is illegal */
234 if (Esp
< Previous
) KeBugCheckEx(SET_OF_INVALID_CONTEXT
,
237 (ULONG_PTR
)TrapFrame
,
240 /* Create an edit frame, check if it was alrady */
241 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
243 /* Update the value */
244 TrapFrame
->TempEsp
= Esp
;
248 /* Check if ESP changed */
252 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
253 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
256 TrapFrame
->TempEsp
= Esp
;
262 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
267 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
269 /* Check if this was V86 Mode */
270 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
273 return TrapFrame
->HardwareSegSs
;
275 else if (TrapFrame
->SegCs
& MODE_MASK
)
277 /* User mode, return the User SS */
278 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
289 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
292 /* Remove the high-bits */
295 /* If this was V86 Mode */
296 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
299 TrapFrame
->HardwareSegSs
= Ss
;
301 else if (TrapFrame
->SegCs
& MODE_MASK
)
303 /* Usermode, save the User SS */
304 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
310 KiTagWordFnsaveToFxsave(USHORT TagWord
)
312 INT FxTagWord
= ~TagWord
;
315 * Empty is now 00, any 2 bits containing 1 mean valid
316 * Now convert the rest (11->0 and the rest to 1)
318 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
319 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
320 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
321 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
327 KeContextToTrapFrame(IN PCONTEXT Context
,
328 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
329 IN OUT PKTRAP_FRAME TrapFrame
,
330 IN ULONG ContextFlags
,
331 IN KPROCESSOR_MODE PreviousMode
)
333 PFX_SAVE_AREA FxSaveArea
;
335 BOOLEAN V86Switch
= FALSE
;
340 /* Do this at APC_LEVEL */
341 OldIrql
= KeGetCurrentIrql();
342 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
344 /* Start with the basic Registers */
345 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
347 /* Check if we went through a V86 switch */
348 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
349 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
351 /* We did, remember this for later */
355 /* Copy EFLAGS and sanitize them*/
356 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
->EFlags
, PreviousMode
);
358 /* Copy EBP and EIP */
359 TrapFrame
->Ebp
= Context
->Ebp
;
360 TrapFrame
->Eip
= Context
->Eip
;
362 /* Check if we were in V86 Mode */
363 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
365 /* Simply copy the CS value */
366 TrapFrame
->SegCs
= Context
->SegCs
;
370 /* We weren't in V86, so sanitize the CS */
371 TrapFrame
->SegCs
= Ke386SanitizeSeg(Context
->SegCs
, PreviousMode
);
373 /* Don't let it under 8, that's invalid */
374 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
376 /* Force it to User CS */
377 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
381 /* Handle SS Specially for validation */
382 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
384 /* Write ESP back; take into account Edited Trap Frames */
385 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
387 /* Handle our V86 Bias if we went through a switch */
388 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
391 /* Process the Integer Registers */
392 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
394 /* Copy them manually */
395 TrapFrame
->Eax
= Context
->Eax
;
396 TrapFrame
->Ebx
= Context
->Ebx
;
397 TrapFrame
->Ecx
= Context
->Ecx
;
398 TrapFrame
->Edx
= Context
->Edx
;
399 TrapFrame
->Esi
= Context
->Esi
;
400 TrapFrame
->Edi
= Context
->Edi
;
403 /* Process the Context Segments */
404 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
406 /* Check if we were in V86 Mode */
407 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
409 /* Copy the V86 Segments directly */
410 TrapFrame
->V86Ds
= Context
->SegDs
;
411 TrapFrame
->V86Es
= Context
->SegEs
;
412 TrapFrame
->V86Fs
= Context
->SegFs
;
413 TrapFrame
->V86Gs
= Context
->SegGs
;
415 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
417 /* For kernel mode, write the standard values */
418 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
419 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
420 TrapFrame
->SegFs
= Ke386SanitizeSeg(Context
->SegFs
, PreviousMode
);
421 TrapFrame
->SegGs
= 0;
425 /* For user mode, return the values directly */
426 TrapFrame
->SegDs
= Context
->SegDs
;
427 TrapFrame
->SegEs
= Context
->SegEs
;
428 TrapFrame
->SegFs
= Context
->SegFs
;
430 /* Handle GS specially */
431 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
433 /* Don't use it, if user */
434 TrapFrame
->SegGs
= 0;
438 /* Copy it if kernel */
439 TrapFrame
->SegGs
= Context
->SegGs
;
444 /* Handle the extended registers */
445 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
446 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
448 /* Get the FX Area */
449 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
451 /* Check if NPX is present */
452 if (KeI386NpxPresent
)
454 /* Flush the NPX State */
455 KiFlushNPXState(NULL
);
457 /* Copy the FX State */
458 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
459 &Context
->ExtendedRegisters
[0],
460 MAXIMUM_SUPPORTED_EXTENSION
);
462 /* Remove reserved bits from MXCSR */
463 FxSaveArea
->U
.FxArea
.MXCsr
&= KiMXCsrMask
;
465 /* Mask out any invalid flags */
466 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
468 /* Check if this is a VDM app */
469 if (PsGetCurrentProcess()->VdmObjects
)
471 /* Allow the EM flag */
472 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
478 /* Handle the floating point state */
479 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
480 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
482 /* Get the FX Area */
483 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
485 /* Check if NPX is present */
486 if (KeI386NpxPresent
)
488 /* Flush the NPX State */
489 KiFlushNPXState(NULL
);
491 /* Check if we have Fxsr support */
492 if (KeI386FxsrPresent
)
494 /* Convert the Fn Floating Point state to Fx */
495 FxSaveArea
->U
.FxArea
.ControlWord
=
496 (USHORT
)Context
->FloatSave
.ControlWord
;
497 FxSaveArea
->U
.FxArea
.StatusWord
=
498 (USHORT
)Context
->FloatSave
.StatusWord
;
499 FxSaveArea
->U
.FxArea
.TagWord
=
500 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
501 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
502 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
503 FxSaveArea
->U
.FxArea
.ErrorOffset
=
504 Context
->FloatSave
.ErrorOffset
;
505 FxSaveArea
->U
.FxArea
.ErrorSelector
=
506 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
507 FxSaveArea
->U
.FxArea
.DataOffset
=
508 Context
->FloatSave
.DataOffset
;
509 FxSaveArea
->U
.FxArea
.DataSelector
=
510 Context
->FloatSave
.DataSelector
;
512 /* Clear out the Register Area */
513 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
514 SIZE_OF_FX_REGISTERS
);
516 /* Loop the 8 floating point registers */
517 for (i
= 0; i
< 8; i
++)
519 /* Copy from Fn to Fx */
520 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
521 Context
->FloatSave
.RegisterArea
+ (i
* 10),
527 /* Copy the structure */
528 FxSaveArea
->U
.FnArea
.ControlWord
= Context
->FloatSave
.
530 FxSaveArea
->U
.FnArea
.StatusWord
= Context
->FloatSave
.
532 FxSaveArea
->U
.FnArea
.TagWord
= Context
->FloatSave
.TagWord
;
533 FxSaveArea
->U
.FnArea
.ErrorOffset
= Context
->FloatSave
.
535 FxSaveArea
->U
.FnArea
.ErrorSelector
= Context
->FloatSave
.
537 FxSaveArea
->U
.FnArea
.DataOffset
= Context
->FloatSave
.
539 FxSaveArea
->U
.FnArea
.DataSelector
= Context
->FloatSave
.
543 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
546 FxSaveArea
->U
.FnArea
.RegisterArea
[i
] =
547 Context
->FloatSave
.RegisterArea
[i
];
551 /* Mask out any invalid flags */
552 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
554 /* Check if this is a VDM app */
555 if (PsGetCurrentProcess()->VdmObjects
)
557 /* Allow the EM flag */
558 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
564 /* FIXME: Handle FPU Emulation */
569 /* Handle the Debug Registers */
570 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
572 /* Loop DR registers */
573 for (i
= 0; i
< 4; i
++)
575 /* Sanitize the context DR Address */
576 SafeDr
= Ke386SanitizeDr(KiDrFromContext(i
, Context
), PreviousMode
);
578 /* Save it in the trap frame */
579 *KiDrFromTrapFrame(i
, TrapFrame
) = SafeDr
;
581 /* Check if this DR address is active and add it in the DR mask */
582 if (SafeDr
) DrMask
|= DR_MASK(i
);
585 /* Now save and sanitize DR6 */
586 TrapFrame
->Dr6
= Context
->Dr6
& DR6_LEGAL
;
587 if (TrapFrame
->Dr6
) DrMask
|= DR_MASK(6);
589 /* Save and sanitize DR7 */
590 TrapFrame
->Dr7
= Context
->Dr7
& DR7_LEGAL
;
591 KiRecordDr7(&TrapFrame
->Dr7
, &DrMask
);
593 /* If we're in user-mode */
594 if (PreviousMode
!= KernelMode
)
597 KeGetCurrentThread()->DispatcherHeader
.DebugActive
= DrMask
;
601 /* Check if thread has IOPL and force it enabled if so */
602 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= EFLAGS_IOPL
;
605 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
610 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
611 IN PKEXCEPTION_FRAME ExceptionFrame
,
612 IN OUT PCONTEXT Context
)
614 PFX_SAVE_AREA FxSaveArea
;
618 FLOATING_SAVE_AREA UnalignedArea
;
620 FLOATING_SAVE_AREA
*FloatSaveArea
;
624 /* Do this at APC_LEVEL */
625 OldIrql
= KeGetCurrentIrql();
626 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
628 /* Start with the Control flags */
629 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
631 /* EBP, EIP and EFLAGS */
632 Context
->Ebp
= TrapFrame
->Ebp
;
633 Context
->Eip
= TrapFrame
->Eip
;
634 Context
->EFlags
= TrapFrame
->EFlags
;
636 /* Return the correct CS */
637 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
638 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
640 /* Get it from the Temp location */
641 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
645 /* Return it directly */
646 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
649 /* Get the Ss and ESP */
650 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
651 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
654 /* Handle the Segments */
655 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
657 /* Do V86 Mode first */
658 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
660 /* Return from the V86 location */
661 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
662 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
663 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
664 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
668 /* Check if this was a Kernel Trap */
669 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
671 /* Set valid selectors */
672 TrapFrame
->SegGs
= 0;
673 TrapFrame
->SegFs
= KGDT_R0_PCR
;
674 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
675 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
678 /* Return the segments */
679 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
680 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
681 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
682 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
686 /* Handle the simple registers */
687 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
689 /* Return them directly */
690 Context
->Eax
= TrapFrame
->Eax
;
691 Context
->Ebx
= TrapFrame
->Ebx
;
692 Context
->Ecx
= TrapFrame
->Ecx
;
693 Context
->Edx
= TrapFrame
->Edx
;
694 Context
->Esi
= TrapFrame
->Esi
;
695 Context
->Edi
= TrapFrame
->Edi
;
698 /* Handle extended registers */
699 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
700 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
702 /* Get the FX Save Area */
703 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
705 /* Make sure NPX is present */
706 if (KeI386NpxPresent
)
708 /* Flush the NPX State */
709 KiFlushNPXState(NULL
);
711 /* Copy the registers */
712 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
713 &FxSaveArea
->U
.FxArea
,
714 MAXIMUM_SUPPORTED_EXTENSION
);
718 /* Handle Floating Point */
719 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
720 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
722 /* Get the FX Save Area */
723 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
725 /* Make sure we have an NPX */
726 if (KeI386NpxPresent
)
728 /* Check if we have Fxsr support */
729 if (KeI386FxsrPresent
)
731 /* Align the floating area to 16-bytes */
732 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
733 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
736 KiFlushNPXState(FloatSaveArea
);
740 /* We don't, use the FN area and flush the NPX State */
741 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
742 KiFlushNPXState(NULL
);
746 Context
->FloatSave
.ControlWord
= FloatSaveArea
->ControlWord
;
747 Context
->FloatSave
.StatusWord
= FloatSaveArea
->StatusWord
;
748 Context
->FloatSave
.TagWord
= FloatSaveArea
->TagWord
;
749 Context
->FloatSave
.ErrorOffset
= FloatSaveArea
->ErrorOffset
;
750 Context
->FloatSave
.ErrorSelector
= FloatSaveArea
->ErrorSelector
;
751 Context
->FloatSave
.DataOffset
= FloatSaveArea
->DataOffset
;
752 Context
->FloatSave
.DataSelector
= FloatSaveArea
->DataSelector
;
753 Context
->FloatSave
.Cr0NpxState
= FxSaveArea
->Cr0NpxState
;
756 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
759 Context
->FloatSave
.RegisterArea
[i
] =
760 FloatSaveArea
->RegisterArea
[i
];
765 /* FIXME: Handle Emulation */
770 /* Handle debug registers */
771 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
772 CONTEXT_DEBUG_REGISTERS
)
774 /* Make sure DR7 is valid */
775 if (TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
)
777 /* Copy the debug registers */
778 Context
->Dr0
= TrapFrame
->Dr0
;
779 Context
->Dr1
= TrapFrame
->Dr1
;
780 Context
->Dr2
= TrapFrame
->Dr2
;
781 Context
->Dr3
= TrapFrame
->Dr3
;
782 Context
->Dr6
= TrapFrame
->Dr6
;
785 Context
->Dr7
= KiUpdateDr7(TrapFrame
->Dr7
);
789 /* Otherwise clear DR registers */
799 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
804 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL
)
807 PKTRAP_FRAME TrapFrame
= TrapInformation
;
808 VOID NTAPI
ExpInterlockedPopEntrySListFault(VOID
);
810 /* Don't do anything if we didn't get a trap frame */
811 if (!TrapInformation
) return FALSE
;
813 /* Check where we came from */
814 switch (TrapFrame
->SegCs
)
819 /* Allow S-LIST Routine to fail */
820 Eip
= (ULONG
)&ExpInterlockedPopEntrySListFault
;
824 case KGDT_R3_CODE
| RPL_MASK
:
826 /* Allow S-LIST Routine to fail */
827 //Eip = (ULONG)KeUserPopEntrySListFault;
833 /* Anything else gets a bugcheck */
837 /* Return TRUE if we want to keep the system up */
838 return (TrapFrame
->Eip
== Eip
) ? TRUE
: FALSE
;
843 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
844 IN PKEXCEPTION_FRAME ExceptionFrame
,
845 IN PKTRAP_FRAME TrapFrame
,
846 IN KPROCESSOR_MODE PreviousMode
,
847 IN BOOLEAN FirstChance
)
850 ULONG_PTR Stack
, NewStack
;
852 EXCEPTION_RECORD LocalExceptRecord
;
853 _SEH_DECLARE_LOCALS(KiCopyInfo
);
855 /* Increase number of Exception Dispatches */
856 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
858 /* Set the context flags */
859 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
861 /* Check if User Mode or if the debugger is enabled */
862 if ((PreviousMode
== UserMode
) || (KdDebuggerEnabled
))
864 /* Add the FPU Flag */
865 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
867 /* Check for NPX Support */
868 if (KeI386FxsrPresent
)
871 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
876 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
878 /* Look at our exception code */
879 switch (ExceptionRecord
->ExceptionCode
)
882 case STATUS_BREAKPOINT
:
884 /* Decrement EIP by one */
888 /* Internal exception */
889 case KI_EXCEPTION_ACCESS_VIOLATION
:
891 /* Set correct code */
892 ExceptionRecord
->ExceptionCode
= STATUS_ACCESS_VIOLATION
;
893 if (PreviousMode
== UserMode
)
895 /* FIXME: Handle no execute */
901 ASSERT(!((PreviousMode
== KernelMode
) &&
902 (Context
.EFlags
& EFLAGS_V86_MASK
)));
904 /* Handle kernel-mode first, it's simpler */
905 if (PreviousMode
== KernelMode
)
907 /* Check if this is a first-chance exception */
908 if (FirstChance
== TRUE
)
910 /* Break into the debugger for the first time */
911 if (KiDebugRoutine(TrapFrame
,
918 /* Exception was handled */
922 /* If the Debugger couldn't handle it, dispatch the exception */
923 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
926 /* This is a second-chance exception, only for the debugger */
927 if (KiDebugRoutine(TrapFrame
,
934 /* Exception was handled */
938 /* Third strike; you're out */
939 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
940 ExceptionRecord
->ExceptionCode
,
941 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
942 (ULONG_PTR
)TrapFrame
,
947 /* User mode exception, was it first-chance? */
950 /* Make sure a debugger is present, and ignore user-mode if requested */
951 if ((KiDebugRoutine
) &&
952 (!(PsGetCurrentProcess()->DebugPort
)))
954 /* Call the debugger */
955 if (KiDebugRoutine(TrapFrame
,
962 /* Exception was handled */
967 /* Forward exception to user mode debugger */
968 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) goto Exit
;
970 /* Set up the user-stack */
974 /* Make sure we have a valid SS and that this isn't V86 mode */
975 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
976 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
978 /* Raise an exception instead */
979 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
980 LocalExceptRecord
.ExceptionFlags
= 0;
981 LocalExceptRecord
.NumberParameters
= 0;
982 RtlRaiseException(&LocalExceptRecord
);
985 /* Align context size and get stack pointer */
986 Size
= (sizeof(CONTEXT
) + 3) & ~3;
987 Stack
= (Context
.Esp
& ~3) - Size
;
989 /* Probe stack and copy Context */
990 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
991 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
993 /* Align exception record size and get stack pointer */
994 Size
= (sizeof(EXCEPTION_RECORD
) -
995 (EXCEPTION_MAXIMUM_PARAMETERS
-
996 ExceptionRecord
->NumberParameters
) *
997 sizeof(ULONG
) + 3) & ~3;
998 NewStack
= Stack
- Size
;
1000 /* Probe stack and copy exception record */
1001 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1002 Size
+ 2 * sizeof(ULONG_PTR
),
1004 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1006 /* Now write the two params for the user-mode dispatcher */
1007 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1008 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1010 /* Set new Stack Pointer */
1011 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
1012 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
1014 /* Force correct segments */
1015 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, PreviousMode
);
1016 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1017 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1018 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, PreviousMode
);
1019 TrapFrame
->SegGs
= 0;
1021 /* Set EIP to the User-mode Dispatcher */
1022 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1024 /* Dispatch exception to user-mode */
1027 _SEH_EXCEPT(KiCopyInformation
)
1029 /* Check if we got a stack overflow and raise that instead */
1030 if (_SEH_VAR(SehExceptRecord
).ExceptionCode
==
1031 STATUS_STACK_OVERFLOW
)
1033 /* Copy the exception address and record */
1034 _SEH_VAR(SehExceptRecord
).ExceptionAddress
=
1035 ExceptionRecord
->ExceptionAddress
;
1036 RtlCopyMemory(ExceptionRecord
,
1037 (PVOID
)&_SEH_VAR(SehExceptRecord
),
1038 sizeof(EXCEPTION_RECORD
));
1040 /* Do the exception again */
1041 _SEH_YIELD(goto DispatchToUser
);
1047 /* Try second chance */
1048 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
))
1050 /* Handled, get out */
1053 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
1055 /* Handled, get out */
1059 /* 3rd strike, kill the process */
1060 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx\n",
1061 PsGetCurrentProcess()->ImageFileName
,
1062 ExceptionRecord
->ExceptionCode
,
1063 ExceptionRecord
->ExceptionAddress
);
1065 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
1066 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
1067 ExceptionRecord
->ExceptionCode
,
1068 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1069 (ULONG_PTR
)TrapFrame
,
1074 /* Convert the context back into Trap/Exception Frames */
1075 KeContextToTrapFrame(&Context
,
1078 Context
.ContextFlags
,
1089 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1091 NTSTATUS Status
= STATUS_SUCCESS
;
1093 PTEB Teb
= KeGetCurrentThread()->Teb
;
1094 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
1096 /* Make sure we can access the TEB */
1099 /* Set the exception code */
1100 Teb
->ExceptionCode
= ExceptionCode
;
1104 /* Save exception code */
1105 Status
= ExceptionCode
;
1108 if (!NT_SUCCESS(Status
)) return Status
;
1110 /* Get the old EIP */
1111 OldEip
= TrapFrame
->Eip
;
1113 /* Change it to the user-mode dispatcher */
1114 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1116 /* Return the old EIP */
1117 return (NTSTATUS
)OldEip
;