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
;
58 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
60 /* Save the current Selector */
61 FlippedSelector
= KiIdt
[i
].Selector
;
63 /* Flip Selector and Extended Offset */
64 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
65 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
71 KiUpdateDr7(IN ULONG Dr7
)
73 ULONG DebugMask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
75 /* Check if debugging is enabled */
76 if (DebugMask
& DR_MASK(DR7_OVERRIDE_V
))
79 ASSERT((DebugMask
& DR_REG_MASK
) != 0);
80 ASSERT((Dr7
& ~DR7_RESERVED_MASK
) == DR7_OVERRIDE_MASK
);
84 /* Return DR7 itself */
90 KiRecordDr7(OUT PULONG Dr7Ptr
,
96 /* Check if the caller gave us a mask */
99 /* He didn't, use the one from the thread */
100 Mask
= KeGetCurrentThread()->DispatcherHeader
.DebugActive
;
104 /* He did, read it */
109 ASSERT((*Dr7Ptr
& DR7_RESERVED_MASK
) == 0);
111 /* Check if DR7 is empty */
118 /* Check the DR mask */
119 NewMask
&= ~(DR_MASK(7));
120 if (NewMask
& DR_REG_MASK
)
122 /* Set the active mask */
123 NewMask
|= DR_MASK(DR7_OVERRIDE_V
);
125 /* Set DR7 override */
126 *Dr7Ptr
|= DR7_OVERRIDE_MASK
;
131 ASSERT(NewMask
== 0);
136 /* Check if we have a mask or not */
137 Result
= NewMask
? TRUE
: FALSE
;
139 /* Update the mask to disable debugging */
140 NewMask
&= ~(DR_MASK(DR7_OVERRIDE_V
));
141 NewMask
|= DR_MASK(7);
144 /* Check if caller wants the new mask */
152 /* Check if the mask changed */
156 KeGetCurrentThread()->DispatcherHeader
.DebugActive
=
161 /* Return the result */
167 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
169 /* Check if this is user-mode or V86 */
170 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
171 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
173 /* Return it directly */
174 return TrapFrame
->HardwareEsp
;
179 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
181 /* Return edited value */
182 return TrapFrame
->TempEsp
;
186 /* Virgin frame, calculate */
187 return (ULONG
)&TrapFrame
->HardwareEsp
;
194 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
200 /* Raise to APC_LEVEL if needed */
201 OldIrql
= KeGetCurrentIrql();
202 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
204 /* Get the old ESP */
205 Previous
= KiEspFromTrapFrame(TrapFrame
);
207 /* Check if this is user-mode or V86 */
208 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
209 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
211 /* Write it directly */
212 TrapFrame
->HardwareEsp
= Esp
;
216 /* Don't allow ESP to be lowered, this is illegal */
217 if (Esp
< Previous
) KeBugCheckEx(SET_OF_INVALID_CONTEXT
,
220 (ULONG_PTR
)TrapFrame
,
223 /* Create an edit frame, check if it was alrady */
224 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
226 /* Update the value */
227 TrapFrame
->TempEsp
= Esp
;
231 /* Check if ESP changed */
235 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
236 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
239 TrapFrame
->TempEsp
= Esp
;
245 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
250 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
252 /* Check if this was V86 Mode */
253 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
256 return TrapFrame
->HardwareSegSs
;
258 else if (TrapFrame
->SegCs
& MODE_MASK
)
260 /* User mode, 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 Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame
)
316 /* Get the current thread's stack */
317 Thread
= KeGetCurrentThread();
318 Stack
= (ULONG_PTR
)Thread
->InitialStack
;
320 /* Check if we are in V8086 mode */
321 if (!(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
323 /* Bias the stack for the V86 segments */
324 Stack
-= (FIELD_OFFSET(KTRAP_FRAME
, V86Gs
) -
325 FIELD_OFFSET(KTRAP_FRAME
, HardwareSegSs
));
328 /* Bias the stack for the FPU area */
329 Stack
-= sizeof(FX_SAVE_AREA
);
331 /* Disable interrupts */
332 EFlags
= __readeflags();
335 /* Set new ESP0 value in the TSS */
336 KeGetPcr()->TSS
->Esp0
= Stack
;
338 /* Restore old interrupt state */
339 __writeeflags(EFlags
);
344 KeContextToTrapFrame(IN PCONTEXT Context
,
345 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
346 IN OUT PKTRAP_FRAME TrapFrame
,
347 IN ULONG ContextFlags
,
348 IN KPROCESSOR_MODE PreviousMode
)
350 PFX_SAVE_AREA FxSaveArea
;
352 BOOLEAN V86Switch
= FALSE
;
357 /* Do this at APC_LEVEL */
358 OldIrql
= KeGetCurrentIrql();
359 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
361 /* Start with the basic Registers */
362 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
364 /* Check if we went through a V86 switch */
365 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
366 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
368 /* We did, remember this for later */
372 /* Copy EFLAGS and sanitize them*/
373 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
->EFlags
, PreviousMode
);
375 /* Copy EBP and EIP */
376 TrapFrame
->Ebp
= Context
->Ebp
;
377 TrapFrame
->Eip
= Context
->Eip
;
379 /* Check if we were in V86 Mode */
380 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
382 /* Simply copy the CS value */
383 TrapFrame
->SegCs
= Context
->SegCs
;
387 /* We weren't in V86, so sanitize the CS */
388 TrapFrame
->SegCs
= Ke386SanitizeSeg(Context
->SegCs
, PreviousMode
);
390 /* Don't let it under 8, that's invalid */
391 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
393 /* Force it to User CS */
394 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
398 /* Handle SS Specially for validation */
399 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
401 /* Write ESP back; take into account Edited Trap Frames */
402 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
404 /* Handle our V86 Bias if we went through a switch */
405 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
408 /* Process the Integer Registers */
409 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
411 /* Copy them manually */
412 TrapFrame
->Eax
= Context
->Eax
;
413 TrapFrame
->Ebx
= Context
->Ebx
;
414 TrapFrame
->Ecx
= Context
->Ecx
;
415 TrapFrame
->Edx
= Context
->Edx
;
416 TrapFrame
->Esi
= Context
->Esi
;
417 TrapFrame
->Edi
= Context
->Edi
;
420 /* Process the Context Segments */
421 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
423 /* Check if we were in V86 Mode */
424 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
426 /* Copy the V86 Segments directly */
427 TrapFrame
->V86Ds
= Context
->SegDs
;
428 TrapFrame
->V86Es
= Context
->SegEs
;
429 TrapFrame
->V86Fs
= Context
->SegFs
;
430 TrapFrame
->V86Gs
= Context
->SegGs
;
432 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
434 /* For kernel mode, write the standard values */
435 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
436 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
437 TrapFrame
->SegFs
= Ke386SanitizeSeg(Context
->SegFs
, PreviousMode
);
438 TrapFrame
->SegGs
= 0;
442 /* For user mode, return the values directly */
443 TrapFrame
->SegDs
= Context
->SegDs
;
444 TrapFrame
->SegEs
= Context
->SegEs
;
445 TrapFrame
->SegFs
= Context
->SegFs
;
447 /* Handle GS specially */
448 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
450 /* Don't use it, if user */
451 TrapFrame
->SegGs
= 0;
455 /* Copy it if kernel */
456 TrapFrame
->SegGs
= Context
->SegGs
;
461 /* Handle the extended registers */
462 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
463 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
465 /* Get the FX Area */
466 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
468 /* Check if NPX is present */
469 if (KeI386NpxPresent
)
471 /* Flush the NPX State */
472 KiFlushNPXState(NULL
);
474 /* Copy the FX State */
475 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
476 &Context
->ExtendedRegisters
[0],
477 MAXIMUM_SUPPORTED_EXTENSION
);
479 /* Remove reserved bits from MXCSR */
480 FxSaveArea
->U
.FxArea
.MXCsr
&= KiMXCsrMask
;
482 /* Mask out any invalid flags */
483 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
485 /* Check if this is a VDM app */
486 if (PsGetCurrentProcess()->VdmObjects
)
488 /* Allow the EM flag */
489 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
495 /* Handle the floating point state */
496 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
497 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
499 /* Get the FX Area */
500 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
502 /* Check if NPX is present */
503 if (KeI386NpxPresent
)
505 /* Flush the NPX State */
506 KiFlushNPXState(NULL
);
508 /* Check if we have Fxsr support */
509 if (KeI386FxsrPresent
)
511 /* Convert the Fn Floating Point state to Fx */
512 FxSaveArea
->U
.FxArea
.ControlWord
=
513 (USHORT
)Context
->FloatSave
.ControlWord
;
514 FxSaveArea
->U
.FxArea
.StatusWord
=
515 (USHORT
)Context
->FloatSave
.StatusWord
;
516 FxSaveArea
->U
.FxArea
.TagWord
=
517 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
518 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
519 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
520 FxSaveArea
->U
.FxArea
.ErrorOffset
=
521 Context
->FloatSave
.ErrorOffset
;
522 FxSaveArea
->U
.FxArea
.ErrorSelector
=
523 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
524 FxSaveArea
->U
.FxArea
.DataOffset
=
525 Context
->FloatSave
.DataOffset
;
526 FxSaveArea
->U
.FxArea
.DataSelector
=
527 Context
->FloatSave
.DataSelector
;
529 /* Clear out the Register Area */
530 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
531 SIZE_OF_FX_REGISTERS
);
533 /* Loop the 8 floating point registers */
534 for (i
= 0; i
< 8; i
++)
536 /* Copy from Fn to Fx */
537 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
538 Context
->FloatSave
.RegisterArea
+ (i
* 10),
544 /* Copy the structure */
545 FxSaveArea
->U
.FnArea
.ControlWord
= Context
->FloatSave
.
547 FxSaveArea
->U
.FnArea
.StatusWord
= Context
->FloatSave
.
549 FxSaveArea
->U
.FnArea
.TagWord
= Context
->FloatSave
.TagWord
;
550 FxSaveArea
->U
.FnArea
.ErrorOffset
= Context
->FloatSave
.
552 FxSaveArea
->U
.FnArea
.ErrorSelector
= Context
->FloatSave
.
554 FxSaveArea
->U
.FnArea
.DataOffset
= Context
->FloatSave
.
556 FxSaveArea
->U
.FnArea
.DataSelector
= Context
->FloatSave
.
560 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
563 FxSaveArea
->U
.FnArea
.RegisterArea
[i
] =
564 Context
->FloatSave
.RegisterArea
[i
];
568 /* Mask out any invalid flags */
569 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
571 /* Check if this is a VDM app */
572 if (PsGetCurrentProcess()->VdmObjects
)
574 /* Allow the EM flag */
575 FxSaveArea
->Cr0NpxState
|= Context
->FloatSave
.Cr0NpxState
&
581 /* FIXME: Handle FPU Emulation */
586 /* Handle the Debug Registers */
587 if (0 && (ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
589 /* Loop DR registers */
590 for (i
= 0; i
< 4; i
++)
592 /* Sanitize the context DR Address */
593 SafeDr
= Ke386SanitizeDr(KiDrFromContext(i
, Context
), PreviousMode
);
595 /* Save it in the trap frame */
596 *KiDrFromTrapFrame(i
, TrapFrame
) = SafeDr
;
598 /* Check if this DR address is active and add it in the DR mask */
599 if (SafeDr
) DrMask
|= DR_MASK(i
);
602 /* Now save and sanitize DR6 */
603 TrapFrame
->Dr6
= Context
->Dr6
& DR6_LEGAL
;
604 if (TrapFrame
->Dr6
) DrMask
|= DR_MASK(6);
606 /* Save and sanitize DR7 */
607 TrapFrame
->Dr7
= Context
->Dr7
& DR7_LEGAL
;
608 KiRecordDr7(&TrapFrame
->Dr7
, &DrMask
);
610 /* If we're in user-mode */
611 if (PreviousMode
!= KernelMode
)
614 KeGetCurrentThread()->DispatcherHeader
.DebugActive
= DrMask
;
618 /* Check if thread has IOPL and force it enabled if so */
619 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= EFLAGS_IOPL
;
622 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
627 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
628 IN PKEXCEPTION_FRAME ExceptionFrame
,
629 IN OUT PCONTEXT Context
)
631 PFX_SAVE_AREA FxSaveArea
;
635 FLOATING_SAVE_AREA UnalignedArea
;
637 FLOATING_SAVE_AREA
*FloatSaveArea
;
641 /* Do this at APC_LEVEL */
642 OldIrql
= KeGetCurrentIrql();
643 if (OldIrql
< APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
645 /* Start with the Control flags */
646 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
648 /* EBP, EIP and EFLAGS */
649 Context
->Ebp
= TrapFrame
->Ebp
;
650 Context
->Eip
= TrapFrame
->Eip
;
651 Context
->EFlags
= TrapFrame
->EFlags
;
653 /* Return the correct CS */
654 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
655 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
657 /* Get it from the Temp location */
658 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
662 /* Return it directly */
663 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
666 /* Get the Ss and ESP */
667 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
668 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
671 /* Handle the Segments */
672 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
674 /* Do V86 Mode first */
675 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
677 /* Return from the V86 location */
678 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
679 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
680 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
681 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
685 /* Check if this was a Kernel Trap */
686 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
688 /* Set valid selectors */
689 TrapFrame
->SegGs
= 0;
690 TrapFrame
->SegFs
= KGDT_R0_PCR
;
691 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
692 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
695 /* Return the segments */
696 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
697 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
698 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
699 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
703 /* Handle the simple registers */
704 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
706 /* Return them directly */
707 Context
->Eax
= TrapFrame
->Eax
;
708 Context
->Ebx
= TrapFrame
->Ebx
;
709 Context
->Ecx
= TrapFrame
->Ecx
;
710 Context
->Edx
= TrapFrame
->Edx
;
711 Context
->Esi
= TrapFrame
->Esi
;
712 Context
->Edi
= TrapFrame
->Edi
;
715 /* Handle extended registers */
716 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
717 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
719 /* Get the FX Save Area */
720 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
722 /* Make sure NPX is present */
723 if (KeI386NpxPresent
)
725 /* Flush the NPX State */
726 KiFlushNPXState(NULL
);
728 /* Copy the registers */
729 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
730 &FxSaveArea
->U
.FxArea
,
731 MAXIMUM_SUPPORTED_EXTENSION
);
735 /* Handle Floating Point */
736 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
737 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
739 /* Get the FX Save Area */
740 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
742 /* Make sure we have an NPX */
743 if (KeI386NpxPresent
)
745 /* Check if we have Fxsr support */
746 if (KeI386FxsrPresent
)
748 /* Align the floating area to 16-bytes */
749 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
750 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
753 KiFlushNPXState(FloatSaveArea
);
757 /* We don't, use the FN area and flush the NPX State */
758 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
759 KiFlushNPXState(NULL
);
763 Context
->FloatSave
.ControlWord
= FloatSaveArea
->ControlWord
;
764 Context
->FloatSave
.StatusWord
= FloatSaveArea
->StatusWord
;
765 Context
->FloatSave
.TagWord
= FloatSaveArea
->TagWord
;
766 Context
->FloatSave
.ErrorOffset
= FloatSaveArea
->ErrorOffset
;
767 Context
->FloatSave
.ErrorSelector
= FloatSaveArea
->ErrorSelector
;
768 Context
->FloatSave
.DataOffset
= FloatSaveArea
->DataOffset
;
769 Context
->FloatSave
.DataSelector
= FloatSaveArea
->DataSelector
;
770 Context
->FloatSave
.Cr0NpxState
= FxSaveArea
->Cr0NpxState
;
773 for (i
= 0; i
< SIZE_OF_80387_REGISTERS
; i
++)
776 Context
->FloatSave
.RegisterArea
[i
] =
777 FloatSaveArea
->RegisterArea
[i
];
782 /* FIXME: Handle Emulation */
787 /* Handle debug registers */
788 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
789 CONTEXT_DEBUG_REGISTERS
)
791 /* Make sure DR7 is valid */
792 if (TrapFrame
->Dr7
& ~DR7_RESERVED_MASK
)
794 /* Copy the debug registers */
795 Context
->Dr0
= TrapFrame
->Dr0
;
796 Context
->Dr1
= TrapFrame
->Dr1
;
797 Context
->Dr2
= TrapFrame
->Dr2
;
798 Context
->Dr3
= TrapFrame
->Dr3
;
799 Context
->Dr6
= TrapFrame
->Dr6
;
802 Context
->Dr7
= KiUpdateDr7(TrapFrame
->Dr7
);
806 /* Otherwise clear DR registers */
817 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
822 KeInvalidAccessAllowed(IN PVOID TrapInformation OPTIONAL
)
825 PKTRAP_FRAME TrapFrame
= TrapInformation
;
826 VOID NTAPI
ExpInterlockedPopEntrySListFault(VOID
);
828 /* Don't do anything if we didn't get a trap frame */
829 if (!TrapInformation
) return FALSE
;
831 /* Check where we came from */
832 switch (TrapFrame
->SegCs
)
837 /* Allow S-LIST Routine to fail */
838 Eip
= (ULONG
)&ExpInterlockedPopEntrySListFault
;
842 case KGDT_R3_CODE
| RPL_MASK
:
844 /* Allow S-LIST Routine to fail */
845 //Eip = (ULONG)KeUserPopEntrySListFault;
851 /* Anything else gets a bugcheck */
855 /* Return TRUE if we want to keep the system up */
856 return (TrapFrame
->Eip
== Eip
) ? TRUE
: FALSE
;
861 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
862 IN PKEXCEPTION_FRAME ExceptionFrame
,
863 IN PKTRAP_FRAME TrapFrame
,
864 IN KPROCESSOR_MODE PreviousMode
,
865 IN BOOLEAN FirstChance
)
868 EXCEPTION_RECORD LocalExceptRecord
;
870 /* Increase number of Exception Dispatches */
871 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
873 /* Set the context flags */
874 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
876 /* Check if User Mode or if the kernel debugger is enabled */
877 if ((PreviousMode
== UserMode
) || (KeGetPcr()->KdVersionBlock
))
879 /* Add the FPU Flag */
880 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
882 /* Check for NPX Support */
883 if (KeI386FxsrPresent
)
886 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
891 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
893 /* Look at our exception code */
894 switch (ExceptionRecord
->ExceptionCode
)
897 case STATUS_BREAKPOINT
:
899 /* Decrement EIP by one */
903 /* Internal exception */
904 case KI_EXCEPTION_ACCESS_VIOLATION
:
906 /* Set correct code */
907 ExceptionRecord
->ExceptionCode
= STATUS_ACCESS_VIOLATION
;
908 if (PreviousMode
== UserMode
)
910 /* FIXME: Handle no execute */
916 ASSERT(!((PreviousMode
== KernelMode
) &&
917 (Context
.EFlags
& EFLAGS_V86_MASK
)));
919 /* Handle kernel-mode first, it's simpler */
920 if (PreviousMode
== KernelMode
)
922 /* Check if this is a first-chance exception */
923 if (FirstChance
== TRUE
)
925 /* Break into the debugger for the first time */
926 if (KiDebugRoutine(TrapFrame
,
933 /* Exception was handled */
937 /* If the Debugger couldn't handle it, dispatch the exception */
938 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
941 /* This is a second-chance exception, only for the debugger */
942 if (KiDebugRoutine(TrapFrame
,
949 /* Exception was handled */
953 /* Third strike; you're out */
954 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
955 ExceptionRecord
->ExceptionCode
,
956 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
957 (ULONG_PTR
)TrapFrame
,
962 /* User mode exception, was it first-chance? */
966 * Break into the kernel debugger unless a user mode debugger
967 * is present or user mode exceptions are ignored, except if this
968 * is a debug service which we must always pass to KD
970 if ((!(PsGetCurrentProcess()->DebugPort
) &&
971 !(KdIgnoreUmExceptions
)) ||
972 (KdIsThisAKdTrap(ExceptionRecord
,
976 /* Call the kernel debugger */
977 if (KiDebugRoutine(TrapFrame
,
984 /* Exception was handled */
989 /* Forward exception to user mode debugger */
990 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) return;
992 /* Set up the user-stack */
997 ULONG_PTR Stack
, NewStack
;
999 /* Make sure we have a valid SS and that this isn't V86 mode */
1000 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
1001 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
1003 /* Raise an exception instead */
1004 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
1005 LocalExceptRecord
.ExceptionFlags
= 0;
1006 LocalExceptRecord
.NumberParameters
= 0;
1007 RtlRaiseException(&LocalExceptRecord
);
1010 /* Align context size and get stack pointer */
1011 Size
= (sizeof(CONTEXT
) + 3) & ~3;
1012 Stack
= (Context
.Esp
& ~3) - Size
;
1014 /* Probe stack and copy Context */
1015 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
1016 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
1018 /* Align exception record size and get stack pointer */
1019 Size
= (sizeof(EXCEPTION_RECORD
) -
1020 (EXCEPTION_MAXIMUM_PARAMETERS
-
1021 ExceptionRecord
->NumberParameters
) *
1022 sizeof(ULONG
) + 3) & ~3;
1023 NewStack
= Stack
- Size
;
1025 /* Probe stack and copy exception record */
1026 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1027 Size
+ 2 * sizeof(ULONG_PTR
),
1029 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1031 /* Now write the two params for the user-mode dispatcher */
1032 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1033 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1035 /* Set new Stack Pointer */
1036 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
1037 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
1039 /* Force correct segments */
1040 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, PreviousMode
);
1041 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1042 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, PreviousMode
);
1043 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, PreviousMode
);
1044 TrapFrame
->SegGs
= 0;
1046 /* Set EIP to the User-mode Dispatcher */
1047 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1049 /* Dispatch exception to user-mode */
1050 _SEH2_YIELD(return);
1052 _SEH2_EXCEPT((RtlCopyMemory(&LocalExceptRecord
, _SEH2_GetExceptionInformation()->ExceptionRecord
, sizeof(EXCEPTION_RECORD
)), EXCEPTION_EXECUTE_HANDLER
))
1054 /* Check if we got a stack overflow and raise that instead */
1055 if ((NTSTATUS
)LocalExceptRecord
.ExceptionCode
==
1056 STATUS_STACK_OVERFLOW
)
1058 /* Copy the exception address and record */
1059 LocalExceptRecord
.ExceptionAddress
=
1060 ExceptionRecord
->ExceptionAddress
;
1061 RtlCopyMemory(ExceptionRecord
,
1062 (PVOID
)&LocalExceptRecord
,
1063 sizeof(EXCEPTION_RECORD
));
1065 /* Do the exception again */
1066 _SEH2_YIELD(goto DispatchToUser
);
1072 /* Try second chance */
1073 if (DbgkForwardException(ExceptionRecord
, TRUE
, TRUE
))
1075 /* Handled, get out */
1078 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
1080 /* Handled, get out */
1084 /* 3rd strike, kill the process */
1085 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx, BaseAddress: %lx\n",
1086 PsGetCurrentProcess()->ImageFileName
,
1087 ExceptionRecord
->ExceptionCode
,
1088 ExceptionRecord
->ExceptionAddress
,
1089 PsGetCurrentProcess()->SectionBaseAddress
);
1091 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
1092 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
1093 ExceptionRecord
->ExceptionCode
,
1094 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1095 (ULONG_PTR
)TrapFrame
,
1100 /* Convert the context back into Trap/Exception Frames */
1101 KeContextToTrapFrame(&Context
,
1104 Context
.ContextFlags
,
1112 KiDispatchExceptionFromTrapFrame(IN NTSTATUS Code
,
1113 IN ULONG_PTR Address
,
1114 IN ULONG ParameterCount
,
1115 IN ULONG_PTR Parameter1
,
1116 IN ULONG_PTR Parameter2
,
1117 IN ULONG_PTR Parameter3
,
1118 IN PKTRAP_FRAME TrapFrame
)
1120 EXCEPTION_RECORD ExceptionRecord
;
1122 /* Build the exception record */
1123 ExceptionRecord
.ExceptionCode
= Code
;
1124 ExceptionRecord
.ExceptionFlags
= 0;
1125 ExceptionRecord
.ExceptionRecord
= NULL
;
1126 ExceptionRecord
.ExceptionAddress
= (PVOID
)Address
;
1127 ExceptionRecord
.NumberParameters
= ParameterCount
;
1130 /* Copy extra parameters */
1131 ExceptionRecord
.ExceptionInformation
[0] = Parameter1
;
1132 ExceptionRecord
.ExceptionInformation
[1] = Parameter2
;
1133 ExceptionRecord
.ExceptionInformation
[2] = Parameter3
;
1136 /* Now go dispatch the exception */
1137 KiDispatchException(&ExceptionRecord
,
1140 TrapFrame
->EFlags
& EFLAGS_V86_MASK
?
1141 -1 : KiUserTrap(TrapFrame
),
1144 /* Return from this trap */
1145 KiEoiHelper(TrapFrame
);
1151 KiSystemFatalException(IN ULONG ExceptionCode
,
1152 IN PKTRAP_FRAME TrapFrame
)
1154 /* Bugcheck the system */
1155 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP
,
1163 /* PUBLIC FUNCTIONS ***********************************************************/
1170 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1173 PTEB Teb
= KeGetCurrentThread()->Teb
;
1174 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
1176 /* Make sure we can access the TEB */
1179 /* Set the exception code */
1180 Teb
->ExceptionCode
= ExceptionCode
;
1182 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1184 /* Return the exception code */
1185 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1189 /* Get the old EIP */
1190 OldEip
= TrapFrame
->Eip
;
1192 /* Change it to the user-mode dispatcher */
1193 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1195 /* Return the old EIP */
1196 return (NTSTATUS
)OldEip
;