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 /* FUNCTIONS *****************************************************************/
19 _SEH_DEFINE_LOCALS(KiCopyInfo
)
21 volatile EXCEPTION_RECORD SehExceptRecord
;
24 _SEH_FILTER(KiCopyInformation
)
26 _SEH_ACCESS_LOCALS(KiCopyInfo
);
28 /* Copy the exception records and return to the handler */
29 RtlMoveMemory((PVOID
)&_SEH_VAR(SehExceptRecord
),
30 _SEH_GetExceptionPointers()->ExceptionRecord
,
31 sizeof(EXCEPTION_RECORD
));
32 return EXCEPTION_EXECUTE_HANDLER
;
38 KeInitExceptions(VOID
)
41 USHORT FlippedSelector
;
42 extern KIDTENTRY KiIdt
[];
45 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
47 /* Save the current Selector */
48 FlippedSelector
= KiIdt
[i
].Selector
;
50 /* Flip Selector and Extended Offset */
51 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
52 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
58 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
60 /* Check if this is user-mode or V86 */
61 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
62 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
64 /* Return it directly */
65 return TrapFrame
->HardwareEsp
;
70 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
72 /* Return edited value */
73 return TrapFrame
->TempEsp
;
77 /* Virgin frame, calculate */
78 return (ULONG
)&TrapFrame
->HardwareEsp
;
85 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
88 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
90 /* Check if this is user-mode or V86 */
91 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
93 /* Write it directly */
94 TrapFrame
->HardwareEsp
= Esp
;
98 /* Don't allow ESP to be lowered, this is illegal */
99 if (Esp
< Previous
) KeBugCheck(SET_OF_INVALID_CONTEXT
);
101 /* Create an edit frame, check if it was alrady */
102 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
104 /* Update the value */
105 TrapFrame
->TempEsp
= Esp
;
109 /* Check if ESP changed */
113 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
114 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
117 TrapFrame
->TempEsp
= Esp
;
125 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
127 /* If this was V86 Mode */
128 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
131 return TrapFrame
->HardwareSegSs
;
133 else if (TrapFrame
->SegCs
& MODE_MASK
)
135 /* Usermode, return the User SS */
136 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
147 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
150 /* Remove the high-bits */
153 /* If this was V86 Mode */
154 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
157 TrapFrame
->HardwareSegSs
= Ss
;
159 else if (TrapFrame
->SegCs
& MODE_MASK
)
161 /* Usermode, save the User SS */
162 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
168 KiTagWordFnsaveToFxsave(USHORT TagWord
)
170 INT FxTagWord
= ~TagWord
;
173 * Empty is now 00, any 2 bits containing 1 mean valid
174 * Now convert the rest (11->0 and the rest to 1)
176 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
177 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
178 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
179 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
185 KeContextToTrapFrame(IN PCONTEXT Context
,
186 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
187 IN OUT PKTRAP_FRAME TrapFrame
,
188 IN ULONG ContextFlags
,
189 IN KPROCESSOR_MODE PreviousMode
)
191 PFX_SAVE_AREA FxSaveArea
;
193 BOOLEAN V86Switch
= FALSE
;
194 KIRQL OldIrql
= APC_LEVEL
;
196 /* Do this at APC_LEVEL */
197 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
199 /* Start with the basic Registers */
200 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
202 /* Check if we went through a V86 switch */
203 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
204 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
206 /* We did, remember this for later */
210 /* Copy EFLAGS. FIXME: Needs to be sanitized */
211 TrapFrame
->EFlags
= Context
->EFlags
;
213 /* Copy EBP and EIP */
214 TrapFrame
->Ebp
= Context
->Ebp
;
215 TrapFrame
->Eip
= Context
->Eip
;
217 /* Check if we were in V86 Mode */
218 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
220 /* Simply copy the CS value */
221 TrapFrame
->SegCs
= Context
->SegCs
;
225 /* We weren't in V86, so sanitize the CS (FIXME!) */
226 TrapFrame
->SegCs
= Context
->SegCs
;
228 /* Don't let it under 8, that's invalid */
229 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
231 /* Force it to User CS */
232 TrapFrame
->SegCs
= (KGDT_R3_CODE
| RPL_MASK
);
236 /* Handle SS Specially for validation */
237 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
239 /* Write ESP back; take into account Edited Trap Frames */
240 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
242 /* Handle our V86 Bias if we went through a switch */
243 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
246 /* Process the Integer Registers */
247 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
249 /* Copy them manually */
250 TrapFrame
->Eax
= Context
->Eax
;
251 TrapFrame
->Ebx
= Context
->Ebx
;
252 TrapFrame
->Ecx
= Context
->Ecx
;
253 TrapFrame
->Edx
= Context
->Edx
;
254 TrapFrame
->Esi
= Context
->Esi
;
255 TrapFrame
->Edi
= Context
->Edi
;
258 /* Process the Context Segments */
259 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
261 /* Check if we were in V86 Mode */
262 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
264 /* Copy the V86 Segments directlry */
265 TrapFrame
->V86Ds
= Context
->SegDs
;
266 TrapFrame
->V86Es
= Context
->SegEs
;
267 TrapFrame
->V86Fs
= Context
->SegFs
;
268 TrapFrame
->V86Gs
= Context
->SegGs
;
270 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
272 /* For kernel mode, write the standard values */
273 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
274 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
275 TrapFrame
->SegFs
= Context
->SegFs
;
276 TrapFrame
->SegGs
= 0;
280 /* For user mode, return the values directlry */
281 TrapFrame
->SegDs
= Context
->SegDs
;
282 TrapFrame
->SegEs
= Context
->SegEs
;
283 TrapFrame
->SegFs
= Context
->SegFs
;
285 /* Handle GS specially */
286 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
288 /* Don't use it, if user */
289 TrapFrame
->SegGs
= 0;
293 /* Copy it if kernel */
294 TrapFrame
->SegGs
= Context
->SegGs
;
299 /* Handle the extended registers */
300 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
301 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
303 /* Get the FX Area */
304 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
306 /* Check if NPX is present */
307 if (KeI386NpxPresent
)
309 /* Flush the NPX State */
310 KiFlushNPXState(NULL
);
312 /* Copy the FX State */
313 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
314 &Context
->ExtendedRegisters
[0],
315 MAXIMUM_SUPPORTED_EXTENSION
);
317 /* Remove reserved bits from MXCSR */
318 FxSaveArea
->U
.FxArea
.MXCsr
&= ~0xFFBF;
320 /* Mask out any invalid flags */
321 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
323 /* FIXME: Check if this is a VDM app */
327 /* Handle the floating point state */
328 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
329 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
331 /* Get the FX Area */
332 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
334 /* Check if NPX is present */
335 if (KeI386NpxPresent
)
337 /* Flush the NPX State */
338 KiFlushNPXState(NULL
);
340 /* Check if we have Fxsr support */
341 if (KeI386FxsrPresent
)
343 /* Convert the Fn Floating Point state to Fx */
344 FxSaveArea
->U
.FxArea
.ControlWord
=
345 (USHORT
)Context
->FloatSave
.ControlWord
;
346 FxSaveArea
->U
.FxArea
.StatusWord
=
347 (USHORT
)Context
->FloatSave
.StatusWord
;
348 FxSaveArea
->U
.FxArea
.TagWord
=
349 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
350 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
351 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
352 FxSaveArea
->U
.FxArea
.ErrorOffset
=
353 Context
->FloatSave
.ErrorOffset
;
354 FxSaveArea
->U
.FxArea
.ErrorSelector
=
355 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
356 FxSaveArea
->U
.FxArea
.DataOffset
=
357 Context
->FloatSave
.DataOffset
;
358 FxSaveArea
->U
.FxArea
.DataSelector
=
359 Context
->FloatSave
.DataSelector
;
361 /* Clear out the Register Area */
362 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
363 SIZE_OF_FX_REGISTERS
);
365 /* Loop the 8 floating point registers */
366 for (i
= 0; i
< 8; i
++)
368 /* Copy from Fn to Fx */
369 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
370 Context
->FloatSave
.RegisterArea
+ (i
* 10),
376 /* Just dump the Fn state in */
377 RtlCopyMemory(&FxSaveArea
->U
.FnArea
,
379 sizeof(FNSAVE_FORMAT
));
382 /* Mask out any invalid flags */
383 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
385 /* FIXME: Check if this is a VDM app */
389 /* FIXME: Handle FPU Emulation */
394 /* Handle the Debug Registers */
395 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
397 /* FIXME: All these should be sanitized */
398 TrapFrame
->Dr0
= Context
->Dr0
;
399 TrapFrame
->Dr1
= Context
->Dr1
;
400 TrapFrame
->Dr2
= Context
->Dr2
;
401 TrapFrame
->Dr3
= Context
->Dr3
;
402 TrapFrame
->Dr6
= Context
->Dr6
;
403 TrapFrame
->Dr7
= Context
->Dr7
;
405 /* Check if usermode */
406 if (PreviousMode
!= KernelMode
)
408 /* Set the Debug Flag */
409 KeGetCurrentThread()->DispatcherHeader
.DebugActive
=
410 (Context
->Dr7
& DR7_ACTIVE
);
415 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
420 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
421 IN PKEXCEPTION_FRAME ExceptionFrame
,
422 IN OUT PCONTEXT Context
)
424 PFX_SAVE_AREA FxSaveArea
;
428 FLOATING_SAVE_AREA UnalignedArea
;
430 FLOATING_SAVE_AREA
*FloatSaveArea
;
431 KIRQL OldIrql
= APC_LEVEL
;
433 /* Do this at APC_LEVEL */
434 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
436 /* Start with the Control flags */
437 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
439 /* EBP, EIP and EFLAGS */
440 Context
->Ebp
= TrapFrame
->Ebp
;
441 Context
->Eip
= TrapFrame
->Eip
;
442 Context
->EFlags
= TrapFrame
->EFlags
;
444 /* Return the correct CS */
445 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
446 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
448 /* Get it from the Temp location */
449 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
453 /* Return it directly */
454 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
457 /* Get the Ss and ESP */
458 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
459 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
462 /* Handle the Segments */
463 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
465 /* Do V86 Mode first */
466 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
468 /* Return from the V86 location */
469 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
470 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
471 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
472 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
476 /* Check if this was a Kernel Trap */
477 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
479 /* Set valid selectors */
480 TrapFrame
->SegGs
= 0;
481 TrapFrame
->SegFs
= KGDT_R0_PCR
;
482 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
483 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
486 /* Return the segments */
487 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
488 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
489 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
490 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
494 /* Handle the simple registers */
495 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
497 /* Return them directly */
498 Context
->Eax
= TrapFrame
->Eax
;
499 Context
->Ebx
= TrapFrame
->Ebx
;
500 Context
->Ecx
= TrapFrame
->Ecx
;
501 Context
->Edx
= TrapFrame
->Edx
;
502 Context
->Esi
= TrapFrame
->Esi
;
503 Context
->Edi
= TrapFrame
->Edi
;
506 /* Handle extended registers */
507 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
508 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
510 /* Get the FX Save Area */
511 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
513 /* Make sure NPX is present */
514 if (KeI386NpxPresent
)
516 /* Flush the NPX State */
517 KiFlushNPXState(NULL
);
519 /* Copy the registers */
520 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
521 &FxSaveArea
->U
.FxArea
,
522 MAXIMUM_SUPPORTED_EXTENSION
);
526 /* Handle Floating Point */
527 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
528 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
530 /* Get the FX Save Area */
531 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
533 /* Make sure we have an NPX */
534 if (KeI386NpxPresent
)
536 /* Check if we have Fxsr support */
537 if (KeI386FxsrPresent
)
539 /* Align the floating area to 16-bytes */
540 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
541 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
544 KiFlushNPXState(FloatSaveArea
);
548 /* We don't, use the FN area and flush the NPX State */
549 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
550 KiFlushNPXState(NULL
);
553 /* Copy into the Context */
554 RtlCopyMemory(&Context
->FloatSave
,
556 sizeof(FNSAVE_FORMAT
));
560 /* FIXME: Handle Emulation */
565 /* Handle debug registers */
566 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
567 CONTEXT_DEBUG_REGISTERS
)
569 /* Copy the debug registers */
570 Context
->Dr0
= TrapFrame
->Dr0
;
571 Context
->Dr1
= TrapFrame
->Dr1
;
572 Context
->Dr2
= TrapFrame
->Dr2
;
573 Context
->Dr3
= TrapFrame
->Dr3
;
574 Context
->Dr6
= TrapFrame
->Dr6
;
576 /* For user-mode, only set DR7 if a debugger is active */
577 if (((TrapFrame
->SegCs
& MODE_MASK
) ||
578 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) &&
579 (KeGetCurrentThread()->DispatcherHeader
.DebugActive
))
582 Context
->Dr7
= TrapFrame
->Dr7
;
592 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
597 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord
,
598 PKEXCEPTION_FRAME ExceptionFrame
,
599 PKTRAP_FRAME TrapFrame
,
600 KPROCESSOR_MODE PreviousMode
,
604 KD_CONTINUE_TYPE Action
;
605 ULONG_PTR Stack
, NewStack
;
607 EXCEPTION_RECORD LocalExceptRecord
;
608 _SEH_DECLARE_LOCALS(KiCopyInfo
);
610 /* Increase number of Exception Dispatches */
611 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
613 /* Set the context flags */
614 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
616 /* Check if User Mode or if the debugger isenabled */
617 if ((PreviousMode
== UserMode
) || (KdDebuggerEnabled
))
619 /* Add the FPU Flag */
620 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
622 /* Check for NPX Support */
623 if (KeI386FxsrPresent
)
626 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
631 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
634 if (ExceptionRecord
->ExceptionCode
== STATUS_BREAKPOINT
)
636 /* Decrement EIP by one */
640 ASSERT(!((PreviousMode
== KernelMode
) &&
641 (Context
.EFlags
& EFLAGS_V86_MASK
)));
643 /* Handle kernel-mode first, it's simpler */
644 if (PreviousMode
== KernelMode
)
646 /* Check if this is a first-chance exception */
647 if (FirstChance
== TRUE
)
649 /* Break into the debugger for the first time */
650 Action
= KdpEnterDebuggerException(ExceptionRecord
,
657 /* If the debugger said continue, then continue */
658 if (Action
== kdContinue
) goto Handled
;
660 /* If the Debugger couldn't handle it, dispatch the exception */
661 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
664 /* This is a second-chance exception, only for the debugger */
665 Action
= KdpEnterDebuggerException(ExceptionRecord
,
672 /* If the debugger said continue, then continue */
673 if (Action
== kdContinue
) goto Handled
;
675 /* Third strike; you're out */
676 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
677 ExceptionRecord
->ExceptionCode
,
678 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
679 ExceptionRecord
->ExceptionInformation
[0],
680 ExceptionRecord
->ExceptionInformation
[1]);
684 /* User mode exception, was it first-chance? */
687 /* Enter Debugger if available */
688 Action
= KdpEnterDebuggerException(ExceptionRecord
,
695 /* Exit if we're continuing */
696 if (Action
== kdContinue
) goto Handled
;
698 /* FIXME: Forward exception to user mode debugger */
699 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
)) goto Exit
;
701 /* Set up the user-stack */
705 /* Make sure we have a valid SS and that this isn't V86 mode */
706 if ((TrapFrame
->HardwareSegSs
!= (KGDT_R3_DATA
| RPL_MASK
)) ||
707 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
709 /* Raise an exception instead */
710 LocalExceptRecord
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
711 LocalExceptRecord
.ExceptionFlags
= 0;
712 LocalExceptRecord
.NumberParameters
= 0;
713 RtlRaiseException(&LocalExceptRecord
);
716 /* Align context size and get stack pointer */
717 Size
= (sizeof(CONTEXT
) + 3) & ~3;
718 Stack
= (Context
.Esp
& ~3) - Size
;
720 /* Probe stack and copy Context */
721 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
722 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
724 /* Align exception record size and get stack pointer */
725 Size
= (sizeof(EXCEPTION_RECORD
) -
726 (EXCEPTION_MAXIMUM_PARAMETERS
-
727 ExceptionRecord
->NumberParameters
) *
728 sizeof(ULONG
) + 3) & ~3;
729 NewStack
= Stack
- Size
;
731 /* Probe stack and copy exception record */
732 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
733 Size
+ 2 * sizeof(ULONG_PTR
),
735 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
737 /* Now write the two params for the user-mode dispatcher */
738 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
739 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
741 /* Set new Stack Pointer */
742 KiSsToTrapFrame(TrapFrame
, KGDT_R3_DATA
);
743 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
745 /* Force correct segments */
746 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
747 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
748 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
749 TrapFrame
->SegFs
= KGDT_R3_TEB
| RPL_MASK
;
750 TrapFrame
->SegGs
= 0;
752 /* Set EIP to the User-mode Dispathcer */
753 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
756 _SEH_EXCEPT(KiCopyInformation
)
758 /* Check if we got a stack overflow and raise that instead */
759 if (_SEH_VAR(SehExceptRecord
).ExceptionCode
==
760 STATUS_STACK_OVERFLOW
)
762 /* Copy the exception address and record */
763 _SEH_VAR(SehExceptRecord
).ExceptionAddress
=
764 ExceptionRecord
->ExceptionAddress
;
765 RtlMoveMemory(ExceptionRecord
,
766 (PVOID
)&_SEH_VAR(SehExceptRecord
),
767 sizeof(EXCEPTION_RECORD
));
769 /* Do the exception again */
776 /* Try second chance */
777 if (DbgkForwardException(ExceptionRecord
, TRUE
, FALSE
))
779 /* Handled, get out */
782 else if (DbgkForwardException(ExceptionRecord
, FALSE
, TRUE
))
784 /* Handled, get out */
788 /* 3rd strike, kill the process */
789 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord
->ExceptionCode
);
790 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
791 ExceptionRecord
->ExceptionCode
,
792 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
793 ExceptionRecord
->ExceptionInformation
[0],
794 ExceptionRecord
->ExceptionInformation
[1]);
798 /* Convert the context back into Trap/Exception Frames */
799 KeContextToTrapFrame(&Context
,
802 Context
.ContextFlags
,
813 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
815 NTSTATUS Status
= STATUS_SUCCESS
;
817 PTEB Teb
= KeGetCurrentThread()->Teb
;
818 PKTRAP_FRAME TrapFrame
= KeGetCurrentThread()->TrapFrame
;
820 /* Make sure we can access the TEB */
823 /* Set the exception code */
824 Teb
->ExceptionCode
= ExceptionCode
;
828 /* Save exception code */
829 Status
= ExceptionCode
;
832 if (!NT_SUCCESS(Status
)) return Status
;
834 /* Get the old EIP */
835 OldEip
= TrapFrame
->Eip
;
837 /* Change it to the user-mode dispatcher */
838 TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
840 /* Return the old EIP */
841 return (NTSTATUS
)OldEip
;