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 *****************************************************************/
52 KeInitExceptions(VOID
)
55 USHORT FlippedSelector
;
56 extern KIDTENTRY KiIdt
[MAXIMUM_IDTVECTOR
];
59 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
61 /* Save the current Selector */
62 FlippedSelector
= KiIdt
[i
].Selector
;
64 /* Flip Selector and Extended Offset */
65 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
66 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
72 KiUpdateDr7(IN ULONG Dr7
)
74 ULONG DebugMask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
76 /* Check if debugging is enabled */
77 if (DebugMask
& DR_MASK(DR7_OVERRIDE_V
))
80 ASSERT((DebugMask
& DR_REG_MASK
) != 0);
81 ASSERT((Dr7
& ~DR7_RESERVED_MASK
) == DR7_OVERRIDE_MASK
);
85 /* Return DR7 itself */
91 KiRecordDr7(OUT PULONG Dr7Ptr
,
97 /* Check if the caller gave us a mask */
100 /* He didn't, use the one from the thread */
101 Mask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
105 /* He did, read it */
110 ASSERT((*Dr7Ptr
& DR7_RESERVED_MASK
) == 0);
112 /* Check if DR7 is empty */
119 /* Check the DR mask */
120 NewMask
&= ~(DR_MASK(7));
121 if (NewMask
& DR_REG_MASK
)
123 /* Set the active mask */
124 NewMask
|= DR_MASK(DR7_OVERRIDE_V
);
126 /* Set DR7 override */
127 *Dr7Ptr
|= DR7_OVERRIDE_MASK
;
132 ASSERT(NewMask
== 0);
137 /* Check if we have a mask or not */
138 Result
= NewMask
? TRUE
: FALSE
;
140 /* Update the mask to disable debugging */
141 NewMask
&= ~(DR_MASK(DR7_OVERRIDE_V
));
142 NewMask
|= DR_MASK(7);
145 /* Check if caller wants the new mask */
153 /* Check if the mask changed */
157 KeGetCurrentThread()->DispatcherHeader
.DebugActive
=
162 /* Return the result */
168 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
170 /* Check if this is user-mode or V86 */
171 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
172 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
174 /* Return it directly */
175 return TrapFrame
->HardwareEsp
;
180 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
182 /* Return edited value */
183 return TrapFrame
->TempEsp
;
187 /* Virgin frame, calculate */
188 return (ULONG
)&TrapFrame
->HardwareEsp
;
195 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
201 /* Raise to APC_LEVEL if needed */
202 OldIrql
= KeGetCurrentIrql();
203 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
205 /* Get the old ESP */
206 Previous
= KiEspFromTrapFrame(TrapFrame
);
208 /* Check if this is user-mode or V86 */
209 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
210 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
212 /* Write it directly */
213 TrapFrame
->HardwareEsp
= Esp
;
217 /* Don't allow ESP to be lowered, this is illegal */
218 if (Esp
< Previous
) KeBugCheckEx(SET_OF_INVALID_CONTEXT
,
221 (ULONG_PTR
)TrapFrame
,
224 /* Create an edit frame, check if it was alrady */
225 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
227 /* Update the value */
228 TrapFrame
->TempEsp
= Esp
;
232 /* Check if ESP changed */
236 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
237 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
240 TrapFrame
->TempEsp
= Esp
;
246 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
251 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
253 /* Check if this was V86 Mode */
254 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
257 return TrapFrame
->HardwareSegSs
;
259 else if (TrapFrame
->SegCs
& MODE_MASK
)
261 /* User mode, return the User SS */
262 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
273 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
276 /* Remove the high-bits */
279 /* If this was V86 Mode */
280 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
283 TrapFrame
->HardwareSegSs
= Ss
;
285 else if (TrapFrame
->SegCs
& MODE_MASK
)
287 /* Usermode, save the User SS */
288 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
294 KiTagWordFnsaveToFxsave(USHORT TagWord
)
296 INT FxTagWord
= ~TagWord
;
299 * Empty is now 00, any 2 bits containing 1 mean valid
300 * Now convert the rest (11->0 and the rest to 1)
302 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
303 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
304 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
305 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
311 KeContextToTrapFrame(IN PCONTEXT Context
,
312 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
313 IN OUT PKTRAP_FRAME TrapFrame
,
314 IN ULONG ContextFlags
,
315 IN KPROCESSOR_MODE PreviousMode
)
317 PFX_SAVE_AREA FxSaveArea
;
319 BOOLEAN V86Switch
= FALSE
;
324 /* Do this at APC_LEVEL */
325 OldIrql
= KeGetCurrentIrql();
326 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
328 /* Start with the basic Registers */
329 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
331 /* Check if we went through a V86 switch */
332 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
333 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
335 /* We did, remember this for later */
339 /* Copy EFLAGS and sanitize them*/
340 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
->EFlags
, PreviousMode
);
342 /* Copy EBP and EIP */
343 TrapFrame
->Ebp
= Context
->Ebp
;
344 TrapFrame
->Eip
= Context
->Eip
;
346 /* Check if we were in V86 Mode */
347 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
349 /* Simply copy the CS value */
350 TrapFrame
->SegCs
= Context
->SegCs
;
354 /* We weren't in V86, so sanitize the CS */
355 TrapFrame
->SegCs
= Ke386SanitizeSeg(Context
->SegCs
, PreviousMode
);
357 /* Don't let it under 8, that's invalid */
358 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
360 /* Force it to User CS */
361 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
365 /* Handle SS Specially for validation */
366 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
368 /* Write ESP back; take into account Edited Trap Frames */
369 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
371 /* Handle our V86 Bias if we went through a switch */
372 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
375 /* Process the Integer Registers */
376 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
378 /* Copy them manually */
379 TrapFrame
->Eax
= Context
->Eax
;
380 TrapFrame
->Ebx
= Context
->Ebx
;
381 TrapFrame
->Ecx
= Context
->Ecx
;
382 TrapFrame
->Edx
= Context
->Edx
;
383 TrapFrame
->Esi
= Context
->Esi
;
384 TrapFrame
->Edi
= Context
->Edi
;
387 /* Process the Context Segments */
388 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
390 /* Check if we were in V86 Mode */
391 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
393 /* Copy the V86 Segments directly */
394 TrapFrame
->V86Ds
= Context
->SegDs
;
395 TrapFrame
->V86Es
= Context
->SegEs
;
396 TrapFrame
->V86Fs
= Context
->SegFs
;
397 TrapFrame
->V86Gs
= Context
->SegGs
;
399 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
401 /* For kernel mode, write the standard values */
402 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
403 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
404 TrapFrame
->SegFs
= Ke386SanitizeSeg(Context
->SegFs
, PreviousMode
);
405 TrapFrame
->SegGs
= 0;
409 /* For user mode, return the values directly */
410 TrapFrame
->SegDs
= Context
->SegDs
;
411 TrapFrame
->SegEs
= Context
->SegEs
;
412 TrapFrame
->SegFs
= Context
->SegFs
;
414 /* Handle GS specially */
415 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
417 /* Don't use it, if user */
418 TrapFrame
->SegGs
= 0;
422 /* Copy it if kernel */
423 TrapFrame
->SegGs
= Context
->SegGs
;
428 /* Handle the extended registers */
429 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
430 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
432 /* Get the FX Area */
433 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
435 /* Check if NPX is present */
436 if (KeI386NpxPresent
)
438 /* Flush the NPX State */
439 KiFlushNPXState(NULL
);
441 /* Copy the FX State */
442 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
443 &Context
->ExtendedRegisters
[0],
444 MAXIMUM_SUPPORTED_EXTENSION
);
446 /* Remove reserved bits from MXCSR */
447 FxSaveArea
->U
.FxArea
.MXCsr
&= KiMXCsrMask
;
449 /* Mask out any invalid flags */
450 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
452 /* Check if this is a VDM app */
453 if (PsGetCurrentProcess()->VdmObjects
)
455 /* Allow the EM flag */
456 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
462 /* Handle the floating point state */
463 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
464 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
466 /* Get the FX Area */
467 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
469 /* Check if NPX is present */
470 if (KeI386NpxPresent
)
472 /* Flush the NPX State */
473 KiFlushNPXState(NULL
);
475 /* Check if we have Fxsr support */
476 if (KeI386FxsrPresent
)
478 /* Convert the Fn Floating Point state to Fx */
479 FxSaveArea
->U
.FxArea
.ControlWord
=
480 (USHORT
)Context
->FloatSave
.ControlWord
;
481 FxSaveArea
->U
.FxArea
.StatusWord
=
482 (USHORT
)Context
->FloatSave
.StatusWord
;
483 FxSaveArea
->U
.FxArea
.TagWord
=
484 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
485 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
486 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
487 FxSaveArea
->U
.FxArea
.ErrorOffset
=
488 Context
->FloatSave
.ErrorOffset
;
489 FxSaveArea
->U
.FxArea
.ErrorSelector
=
490 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
491 FxSaveArea
->U
.FxArea
.DataOffset
=
492 Context
->FloatSave
.DataOffset
;
493 FxSaveArea
->U
.FxArea
.DataSelector
=
494 Context
->FloatSave
.DataSelector
;
496 /* Clear out the Register Area */
497 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
498 SIZE_OF_FX_REGISTERS
);
500 /* Loop the 8 floating point registers */
501 for (i
= 0; i
< 8; i
++)
503 /* Copy from Fn to Fx */
504 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
505 Context
->FloatSave
.RegisterArea
+ (i
* 10),
511 /* Copy the structure */
512 FxSaveArea
->U
.FnArea
.ControlWord
= Context
->FloatSave
.
514 FxSaveArea
->U
.FnArea
.StatusWord
= Context
->FloatSave
.
516 FxSaveArea
->U
.FnArea
.TagWord
= Context
->FloatSave
.TagWord
;
517 FxSaveArea
->U
.FnArea
.ErrorOffset
= Context
->FloatSave
.
519 FxSaveArea
->U
.FnArea
.ErrorSelector
= Context
->FloatSave
.
521 FxSaveArea
->U
.FnArea
.DataOffset
= Context
->FloatSave
.
523 FxSaveArea
->U
.FnArea
.DataSelector
= Context
->FloatSave
.
527 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
530 FxSaveArea
->U
.FnArea
.RegisterArea
[i
] =
531 Context
->FloatSave
.RegisterArea
[i
];
535 /* Mask out any invalid flags */
536 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
538 /* Check if this is a VDM app */
539 if (PsGetCurrentProcess()->VdmObjects
)
541 /* Allow the EM flag */
542 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
548 /* FIXME: Handle FPU Emulation */
553 /* Handle the Debug Registers */
554 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
556 /* Loop DR registers */
557 for (i
= 0; i
< 4; i
++)
559 /* Sanitize the context DR Address */
560 SafeDr
= Ke386SanitizeDr(KiDrFromContext(i
, Context
), PreviousMode
);
562 /* Save it in the trap frame */
563 *KiDrFromTrapFrame(i
, TrapFrame
) = SafeDr
;
565 /* Check if this DR address is active and add it in the DR mask */
566 if (SafeDr
) DrMask
|= DR_MASK(i
);
569 /* Now save and sanitize DR6 */
570 TrapFrame
->Dr6
= Context
->Dr6
& DR6_LEGAL
;
571 if (TrapFrame
->Dr6
) DrMask
|= DR_MASK(6);
573 /* Save and sanitize DR7 */
574 TrapFrame
->Dr7
= Context
->Dr7
& DR7_LEGAL
;
575 KiRecordDr7(&TrapFrame
->Dr7
, &DrMask
);
577 /* If we're in user-mode */
578 if (PreviousMode
!= KernelMode
)
581 KeGetCurrentThread()->DispatcherHeader
.DebugActive
= DrMask
;
585 /* Check if thread has IOPL and force it enabled if so */
586 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= EFLAGS_IOPL
;
589 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
594 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
595 IN PKEXCEPTION_FRAME ExceptionFrame
,
596 IN OUT PCONTEXT Context
)
598 PFX_SAVE_AREA FxSaveArea
;
602 FLOATING_SAVE_AREA UnalignedArea
;
604 FLOATING_SAVE_AREA
*FloatSaveArea
;
608 /* Do this at APC_LEVEL */
609 OldIrql
= KeGetCurrentIrql();
610 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
612 /* Start with the Control flags */
613 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
615 /* EBP, EIP and EFLAGS */
616 Context
->Ebp
= TrapFrame
->Ebp
;
617 Context
->Eip
= TrapFrame
->Eip
;
618 Context
->EFlags
= TrapFrame
->EFlags
;
620 /* Return the correct CS */
621 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
622 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
624 /* Get it from the Temp location */
625 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
629 /* Return it directly */
630 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
633 /* Get the Ss and ESP */
634 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
635 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
638 /* Handle the Segments */
639 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
641 /* Do V86 Mode first */
642 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
644 /* Return from the V86 location */
645 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
646 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
647 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
648 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
652 /* Check if this was a Kernel Trap */
653 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
655 /* Set valid selectors */
656 TrapFrame
->SegGs
= 0;
657 TrapFrame
->SegFs
= KGDT_R0_PCR
;
658 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
659 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
662 /* Return the segments */
663 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
664 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
665 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
666 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
670 /* Handle the simple registers */
671 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
673 /* Return them directly */
674 Context
->Eax
= TrapFrame
->Eax
;
675 Context
->Ebx
= TrapFrame
->Ebx
;
676 Context
->Ecx
= TrapFrame
->Ecx
;
677 Context
->Edx
= TrapFrame
->Edx
;
678 Context
->Esi
= TrapFrame
->Esi
;
679 Context
->Edi
= TrapFrame
->Edi
;
682 /* Handle extended registers */
683 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
684 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
686 /* Get the FX Save Area */
687 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
689 /* Make sure NPX is present */
690 if (KeI386NpxPresent
)
692 /* Flush the NPX State */
693 KiFlushNPXState(NULL
);
695 /* Copy the registers */
696 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
697 &FxSaveArea
->U
.FxArea
,
698 MAXIMUM_SUPPORTED_EXTENSION
);
702 /* Handle Floating Point */
703 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
704 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
706 /* Get the FX Save Area */
707 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
709 /* Make sure we have an NPX */
710 if (KeI386NpxPresent
)
712 /* Check if we have Fxsr support */
713 if (KeI386FxsrPresent
)
715 /* Align the floating area to 16-bytes */
716 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
717 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
720 KiFlushNPXState(FloatSaveArea
);
724 /* We don't, use the FN area and flush the NPX State */
725 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
726 KiFlushNPXState(NULL
);
730 Context
->FloatSave
.ControlWord
= FloatSaveArea
->ControlWord
;
731 Context
->FloatSave
.StatusWord
= FloatSaveArea
->StatusWord
;
732 Context
->FloatSave
.TagWord
= FloatSaveArea
->TagWord
;
733 Context
->FloatSave
.ErrorOffset
= FloatSaveArea
->ErrorOffset
;
734 Context
->FloatSave
.ErrorSelector
= FloatSaveArea
->ErrorSelector
;
735 Context
->FloatSave
.DataOffset
= FloatSaveArea
->DataOffset
;
736 Context
->FloatSave
.DataSelector
= FloatSaveArea
->DataSelector
;
737 Context
->FloatSave
.Cr0NpxState
= FxSaveArea
->Cr0NpxState
;
740 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
743 Context
->FloatSave
.RegisterArea
[i
] =
744 FloatSaveArea
->RegisterArea
[i
];
749 /* FIXME: Handle Emulation */
754 /* Handle debug registers */
755 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
756 CONTEXT_DEBUG_REGISTERS
)
758 /* Make sure DR7 is valid */
759 if (TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
)
761 /* Copy the debug registers */
762 Context
->Dr0
= TrapFrame
->Dr0
;
763 Context
->Dr1
= TrapFrame
->Dr1
;
764 Context
->Dr2
= TrapFrame
->Dr2
;
765 Context
->Dr3
= TrapFrame
->Dr3
;
766 Context
->Dr6
= TrapFrame
->Dr6
;
769 Context
->Dr7
= KiUpdateDr7(TrapFrame
->Dr7
);
773 /* Otherwise clear DR registers */
783 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
788 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL
)
791 PKTRAP_FRAME TrapFrame
= TrapInformation
;
792 VOID NTAPI
ExpInterlockedPopEntrySListFault(VOID
);
794 /* Don't do anything if we didn't get a trap frame */
795 if (!TrapInformation
) return FALSE
;
797 /* Check where we came from */
798 switch (TrapFrame
->SegCs
)
803 /* Allow S-LIST Routine to fail */
804 Eip
= (ULONG
)&ExpInterlockedPopEntrySListFault
;
808 case KGDT_R3_CODE
| RPL_MASK
:
810 /* Allow S-LIST Routine to fail */
811 //Eip = (ULONG)KeUserPopEntrySListFault;
817 /* Anything else gets a bugcheck */
821 /* Return TRUE if we want to keep the system up */
822 return (TrapFrame
->Eip
== Eip
) ? TRUE
: FALSE
;
827 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
828 IN PKEXCEPTION_FRAME ExceptionFrame
,
829 IN PKTRAP_FRAME TrapFrame
,
830 IN KPROCESSOR_MODE PreviousMode
,
831 IN BOOLEAN FirstChance
)
834 ULONG_PTR Stack
, NewStack
;
836 EXCEPTION_RECORD LocalExceptRecord
;
837 EXCEPTION_RECORD SehExceptRecord
;
839 /* Increase number of Exception Dispatches */
840 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
842 /* Set the context flags */
843 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
845 /* Check if User Mode or if the debugger is enabled */
846 if ((PreviousMode
== UserMode
) || (KdDebuggerEnabled
))
848 /* Add the FPU Flag */
849 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
851 /* Check for NPX Support */
852 if (KeI386FxsrPresent
)
855 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
860 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
862 /* Look at our exception code */
863 switch (ExceptionRecord
->ExceptionCode
)
866 case STATUS_BREAKPOINT
:
868 /* Decrement EIP by one */
872 /* Internal exception */
873 case KI_EXCEPTION_ACCESS_VIOLATION
:
875 /* Set correct code */
876 ExceptionRecord
->ExceptionCode
= STATUS_ACCESS_VIOLATION
;
877 if (PreviousMode
== UserMode
)
879 /* FIXME: Handle no execute */
885 ASSERT(!((PreviousMode
== KernelMode
) &&
886 (Context
.EFlags
& EFLAGS_V86_MASK
)));
888 /* Handle kernel-mode first, it's simpler */
889 if (PreviousMode
== KernelMode
)
891 /* Check if this is a first-chance exception */
892 if (FirstChance
== TRUE
)
894 /* Break into the debugger for the first time */
895 if (KiDebugRoutine(TrapFrame
,
902 /* Exception was handled */
906 /* If the Debugger couldn't handle it, dispatch the exception */
907 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
910 /* This is a second-chance exception, only for the debugger */
911 if (KiDebugRoutine(TrapFrame
,
918 /* Exception was handled */
922 /* Third strike; you're out */
923 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
924 ExceptionRecord
->ExceptionCode
,
925 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
926 (ULONG_PTR
)TrapFrame
,
931 /* User mode exception, was it first-chance? */
934 /* Make sure a debugger is present, and ignore user-mode if requested */
935 if ((KiDebugRoutine
) &&
936 (!(PsGetCurrentProcess()->DebugPort
)))
938 /* Call the debugger */
939 if (KiDebugRoutine(TrapFrame
,
946 /* Exception was handled */
951 /* Forward exception to user mode debugger */
952 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) goto Exit
;
954 /* Set up the user-stack */
958 /* Make sure we have a valid SS and that this isn't V86 mode */
959 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
960 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
962 /* Raise an exception instead */
963 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
964 LocalExceptRecord
.ExceptionFlags
= 0;
965 LocalExceptRecord
.NumberParameters
= 0;
966 RtlRaiseException(&LocalExceptRecord
);
969 /* Align context size and get stack pointer */
970 Size
= (sizeof(CONTEXT
) + 3) & ~3;
971 Stack
= (Context
.Esp
& ~3) - Size
;
973 /* Probe stack and copy Context */
974 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
975 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
977 /* Align exception record size and get stack pointer */
978 Size
= (sizeof(EXCEPTION_RECORD
) -
979 (EXCEPTION_MAXIMUM_PARAMETERS
-
980 ExceptionRecord
->NumberParameters
) *
981 sizeof(ULONG
) + 3) & ~3;
982 NewStack
= Stack
- Size
;
984 /* Probe stack and copy exception record */
985 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
986 Size
+ 2 * sizeof(ULONG_PTR
),
988 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
990 /* Now write the two params for the user-mode dispatcher */
991 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
992 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
994 /* Set new Stack Pointer */
995 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
996 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
998 /* Force correct segments */
999 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, PreviousMode
);
1000 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1001 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1002 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, PreviousMode
);
1003 TrapFrame
->SegGs
= 0;
1005 /* Set EIP to the User-mode Dispatcher */
1006 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1008 /* Dispatch exception to user-mode */
1009 _SEH2_YIELD(return);
1011 _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord
, _SEH2_GetExceptionInformation()->ExceptionRecord
, sizeof(EXCEPTION_RECORD
)), EXCEPTION_EXECUTE_HANDLER
))
1013 /* Check if we got a stack overflow and raise that instead */
1014 if ((NTSTATUS
)SehExceptRecord
.ExceptionCode
==
1015 STATUS_STACK_OVERFLOW
)
1017 /* Copy the exception address and record */
1018 SehExceptRecord
.ExceptionAddress
=
1019 ExceptionRecord
->ExceptionAddress
;
1020 RtlCopyMemory(ExceptionRecord
,
1021 (PVOID
)&SehExceptRecord
,
1022 sizeof(EXCEPTION_RECORD
));
1024 /* Do the exception again */
1025 _SEH2_YIELD(goto DispatchToUser
);
1031 /* Try second chance */
1032 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
))
1034 /* Handled, get out */
1037 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
1039 /* Handled, get out */
1043 /* 3rd strike, kill the process */
1044 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx\n",
1045 PsGetCurrentProcess()->ImageFileName
,
1046 ExceptionRecord
->ExceptionCode
,
1047 ExceptionRecord
->ExceptionAddress
);
1049 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
1050 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
1051 ExceptionRecord
->ExceptionCode
,
1052 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1053 (ULONG_PTR
)TrapFrame
,
1058 /* Convert the context back into Trap/Exception Frames */
1059 KeContextToTrapFrame(&Context
,
1062 Context
.ContextFlags
,
1073 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1075 NTSTATUS Status
= STATUS_SUCCESS
;
1077 PTEB Teb
= KeGetCurrentThread()->Teb
;
1078 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
1080 /* Make sure we can access the TEB */
1083 /* Set the exception code */
1084 Teb
->ExceptionCode
= ExceptionCode
;
1086 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1088 /* Save exception code */
1089 Status
= ExceptionCode
;
1092 if (!NT_SUCCESS(Status
)) return Status
;
1094 /* Get the old EIP */
1095 OldEip
= TrapFrame
->Eip
;
1097 /* Change it to the user-mode dispatcher */
1098 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1100 /* Return the old EIP */
1101 return (NTSTATUS
)OldEip
;