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 *****************************************************************/
22 KeInitExceptions(VOID
)
25 USHORT FlippedSelector
;
26 extern KIDTENTRY KiIdt
[];
29 for (i
= 0; i
<= MAXIMUM_IDTVECTOR
; i
++)
31 /* Save the current Selector */
32 FlippedSelector
= KiIdt
[i
].Selector
;
34 /* Flip Selector and Extended Offset */
35 KiIdt
[i
].Selector
= KiIdt
[i
].ExtendedOffset
;
36 KiIdt
[i
].ExtendedOffset
= FlippedSelector
;
42 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
44 /* Check if this is user-mode or V86 */
45 if ((TrapFrame
->SegCs
& MODE_MASK
) ||
46 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
48 /* Return it directly */
49 return TrapFrame
->HardwareEsp
;
54 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
56 /* Return edited value */
57 return TrapFrame
->TempEsp
;
61 /* Virgin frame, calculate */
62 return (ULONG
)&TrapFrame
->HardwareEsp
;
69 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
72 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
74 /* Check if this is user-mode or V86 */
75 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
77 /* Write it directly */
78 TrapFrame
->HardwareEsp
= Esp
;
82 /* Don't allow ESP to be lowered, this is illegal */
83 if (Esp
< Previous
) KeBugCheck(SET_OF_INVALID_CONTEXT
);
85 /* Create an edit frame, check if it was alrady */
86 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
88 /* Update the value */
89 TrapFrame
->TempEsp
= Esp
;
93 /* Check if ESP changed */
97 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
98 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
101 TrapFrame
->TempEsp
= Esp
;
109 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
111 /* If this was V86 Mode */
112 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
115 return TrapFrame
->HardwareSegSs
;
117 else if (TrapFrame
->SegCs
& MODE_MASK
)
119 /* Usermode, return the User SS */
120 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
131 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
134 /* Remove the high-bits */
137 /* If this was V86 Mode */
138 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
141 TrapFrame
->HardwareSegSs
= Ss
;
143 else if (TrapFrame
->SegCs
& MODE_MASK
)
145 /* Usermode, save the User SS */
146 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
152 KiTagWordFnsaveToFxsave(USHORT TagWord
)
154 INT FxTagWord
= ~TagWord
;
157 * Empty is now 00, any 2 bits containing 1 mean valid
158 * Now convert the rest (11->0 and the rest to 1)
160 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
161 FxTagWord
= (FxTagWord
| (FxTagWord
>> 1)) & 0x3333; /* 00VV00VV00VV00VV */
162 FxTagWord
= (FxTagWord
| (FxTagWord
>> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
163 FxTagWord
= (FxTagWord
| (FxTagWord
>> 4)) & 0x00ff; /* 00000000VVVVVVVV */
169 KeContextToTrapFrame(IN PCONTEXT Context
,
170 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
171 IN OUT PKTRAP_FRAME TrapFrame
,
172 IN ULONG ContextFlags
,
173 IN KPROCESSOR_MODE PreviousMode
)
175 PFX_SAVE_AREA FxSaveArea
;
177 BOOLEAN V86Switch
= FALSE
;
178 KIRQL OldIrql
= APC_LEVEL
;
180 /* Do this at APC_LEVEL */
181 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
183 /* Start with the basic Registers */
184 if ((ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
186 /* Check if we went through a V86 switch */
187 if ((Context
->EFlags
& EFLAGS_V86_MASK
) !=
188 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
190 /* We did, remember this for later */
194 /* Copy EFLAGS. FIXME: Needs to be sanitized */
195 TrapFrame
->EFlags
= Context
->EFlags
;
197 /* Copy EBP and EIP */
198 TrapFrame
->Ebp
= Context
->Ebp
;
199 TrapFrame
->Eip
= Context
->Eip
;
201 /* Check if we were in V86 Mode */
202 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
204 /* Simply copy the CS value */
205 TrapFrame
->SegCs
= Context
->SegCs
;
209 /* We weren't in V86, so sanitize the CS (FIXME!) */
210 TrapFrame
->SegCs
= Context
->SegCs
;
212 /* Don't let it under 8, that's invalid */
213 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
215 /* Force it to User CS */
216 TrapFrame
->SegCs
= (KGDT_R3_CODE
| RPL_MASK
);
220 /* Handle SS Specially for validation */
221 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
223 /* Write ESP back; take into account Edited Trap Frames */
224 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
226 /* Handle our V86 Bias if we went through a switch */
227 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
230 /* Process the Integer Registers */
231 if ((ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
233 /* Copy them manually */
234 TrapFrame
->Eax
= Context
->Eax
;
235 TrapFrame
->Ebx
= Context
->Ebx
;
236 TrapFrame
->Ecx
= Context
->Ecx
;
237 TrapFrame
->Edx
= Context
->Edx
;
238 TrapFrame
->Esi
= Context
->Esi
;
239 TrapFrame
->Edi
= Context
->Edi
;
242 /* Process the Context Segments */
243 if ((ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
245 /* Check if we were in V86 Mode */
246 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
248 /* Copy the V86 Segments directlry */
249 TrapFrame
->V86Ds
= Context
->SegDs
;
250 TrapFrame
->V86Es
= Context
->SegEs
;
251 TrapFrame
->V86Fs
= Context
->SegFs
;
252 TrapFrame
->V86Gs
= Context
->SegGs
;
254 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
256 /* For kernel mode, write the standard values */
257 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
258 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
259 TrapFrame
->SegFs
= Context
->SegFs
;
260 TrapFrame
->SegGs
= 0;
264 /* For user mode, return the values directlry */
265 TrapFrame
->SegDs
= Context
->SegDs
;
266 TrapFrame
->SegEs
= Context
->SegEs
;
267 TrapFrame
->SegFs
= Context
->SegFs
;
269 /* Handle GS specially */
270 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
272 /* Don't use it, if user */
273 TrapFrame
->SegGs
= 0;
277 /* Copy it if kernel */
278 TrapFrame
->SegGs
= Context
->SegGs
;
283 /* Handle the extended registers */
284 if (((ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
285 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
287 /* Get the FX Area */
288 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
290 /* Check if NPX is present */
291 if (KeI386NpxPresent
)
293 /* Flush the NPX State */
294 KiFlushNPXState(NULL
);
296 /* Copy the FX State */
297 RtlCopyMemory(&FxSaveArea
->U
.FxArea
,
298 &Context
->ExtendedRegisters
[0],
299 MAXIMUM_SUPPORTED_EXTENSION
);
301 /* Remove reserved bits from MXCSR */
302 FxSaveArea
->U
.FxArea
.MXCsr
&= ~0xFFBF;
304 /* Mask out any invalid flags */
305 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
307 /* FIXME: Check if this is a VDM app */
311 /* Handle the floating point state */
312 if (((ContextFlags
& CONTEXT_FLOATING_POINT
) ==
313 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
315 /* Get the FX Area */
316 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
318 /* Check if NPX is present */
319 if (KeI386NpxPresent
)
321 /* Flush the NPX State */
322 KiFlushNPXState(NULL
);
324 /* Check if we have Fxsr support */
325 if (KeI386FxsrPresent
)
327 /* Convert the Fn Floating Point state to Fx */
328 FxSaveArea
->U
.FxArea
.ControlWord
=
329 (USHORT
)Context
->FloatSave
.ControlWord
;
330 FxSaveArea
->U
.FxArea
.StatusWord
=
331 (USHORT
)Context
->FloatSave
.StatusWord
;
332 FxSaveArea
->U
.FxArea
.TagWord
=
333 KiTagWordFnsaveToFxsave((USHORT
)Context
->FloatSave
.TagWord
);
334 FxSaveArea
->U
.FxArea
.ErrorOpcode
=
335 (USHORT
)((Context
->FloatSave
.ErrorSelector
>> 16) & 0xFFFF);
336 FxSaveArea
->U
.FxArea
.ErrorOffset
=
337 Context
->FloatSave
.ErrorOffset
;
338 FxSaveArea
->U
.FxArea
.ErrorSelector
=
339 Context
->FloatSave
.ErrorSelector
& 0xFFFF;
340 FxSaveArea
->U
.FxArea
.DataOffset
=
341 Context
->FloatSave
.DataOffset
;
342 FxSaveArea
->U
.FxArea
.DataSelector
=
343 Context
->FloatSave
.DataSelector
;
345 /* Clear out the Register Area */
346 RtlZeroMemory(&FxSaveArea
->U
.FxArea
.RegisterArea
[0],
347 SIZE_OF_FX_REGISTERS
);
349 /* Loop the 8 floating point registers */
350 for (i
= 0; i
< 8; i
++)
352 /* Copy from Fn to Fx */
353 RtlCopyMemory(FxSaveArea
->U
.FxArea
.RegisterArea
+ (i
* 16),
354 Context
->FloatSave
.RegisterArea
+ (i
* 10),
360 /* Just dump the Fn state in */
361 RtlCopyMemory(&FxSaveArea
->U
.FnArea
,
363 sizeof(FNSAVE_FORMAT
));
366 /* Mask out any invalid flags */
367 FxSaveArea
->Cr0NpxState
&= ~(CR0_EM
| CR0_MP
| CR0_TS
);
369 /* FIXME: Check if this is a VDM app */
373 /* FIXME: Handle FPU Emulation */
378 /* Handle the Debug Registers */
379 if ((ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
381 /* FIXME: All these should be sanitized */
382 TrapFrame
->Dr0
= Context
->Dr0
;
383 TrapFrame
->Dr1
= Context
->Dr1
;
384 TrapFrame
->Dr2
= Context
->Dr2
;
385 TrapFrame
->Dr3
= Context
->Dr3
;
386 TrapFrame
->Dr6
= Context
->Dr6
;
387 TrapFrame
->Dr7
= Context
->Dr7
;
389 /* Check if usermode */
390 if (PreviousMode
!= KernelMode
)
392 /* Set the Debug Flag */
393 KeGetCurrentThread()->DispatcherHeader
.DebugActive
=
394 (Context
->Dr7
& DR7_ACTIVE
);
399 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
404 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
405 IN PKEXCEPTION_FRAME ExceptionFrame
,
406 IN OUT PCONTEXT Context
)
408 PFX_SAVE_AREA FxSaveArea
;
412 FLOATING_SAVE_AREA UnalignedArea
;
414 FLOATING_SAVE_AREA
*FloatSaveArea
;
415 KIRQL OldIrql
= APC_LEVEL
;
417 /* Do this at APC_LEVEL */
418 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
420 /* Start with the Control flags */
421 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
423 /* EBP, EIP and EFLAGS */
424 Context
->Ebp
= TrapFrame
->Ebp
;
425 Context
->Eip
= TrapFrame
->Eip
;
426 Context
->EFlags
= TrapFrame
->EFlags
;
428 /* Return the correct CS */
429 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
430 !(TrapFrame
->EFlags
& EFLAGS_V86_MASK
))
432 /* Get it from the Temp location */
433 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
437 /* Return it directly */
438 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
441 /* Get the Ss and ESP */
442 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
443 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
446 /* Handle the Segments */
447 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
449 /* Do V86 Mode first */
450 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)
452 /* Return from the V86 location */
453 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
454 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
455 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
456 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
460 /* Check if this was a Kernel Trap */
461 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
463 /* Set valid selectors */
464 TrapFrame
->SegGs
= 0;
465 TrapFrame
->SegFs
= KGDT_R0_PCR
;
466 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
467 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
470 /* Return the segments */
471 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
472 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
473 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
474 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
478 /* Handle the simple registers */
479 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
481 /* Return them directly */
482 Context
->Eax
= TrapFrame
->Eax
;
483 Context
->Ebx
= TrapFrame
->Ebx
;
484 Context
->Ecx
= TrapFrame
->Ecx
;
485 Context
->Edx
= TrapFrame
->Edx
;
486 Context
->Esi
= TrapFrame
->Esi
;
487 Context
->Edi
= TrapFrame
->Edi
;
490 /* Handle extended registers */
491 if (((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) ==
492 CONTEXT_EXTENDED_REGISTERS
) && (TrapFrame
->SegCs
& MODE_MASK
))
494 /* Get the FX Save Area */
495 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
497 /* Make sure NPX is present */
498 if (KeI386NpxPresent
)
500 /* Flush the NPX State */
501 KiFlushNPXState(NULL
);
503 /* Copy the registers */
504 RtlCopyMemory(&Context
->ExtendedRegisters
[0],
505 &FxSaveArea
->U
.FxArea
,
506 MAXIMUM_SUPPORTED_EXTENSION
);
510 /* Handle Floating Point */
511 if (((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) ==
512 CONTEXT_FLOATING_POINT
) && (TrapFrame
->SegCs
& MODE_MASK
))
514 /* Get the FX Save Area */
515 FxSaveArea
= (PFX_SAVE_AREA
)(TrapFrame
+ 1);
517 /* Make sure we have an NPX */
518 if (KeI386NpxPresent
)
520 /* Check if we have Fxsr support */
521 if (KeI386FxsrPresent
)
523 /* Align the floating area to 16-bytes */
524 FloatSaveArea
= (FLOATING_SAVE_AREA
*)
525 ((ULONG_PTR
)&FloatSaveBuffer
.UnalignedArea
&~ 0xF);
528 KiFlushNPXState(FloatSaveArea
);
532 /* We don't, use the FN area and flush the NPX State */
533 FloatSaveArea
= (FLOATING_SAVE_AREA
*)&FxSaveArea
->U
.FnArea
;
534 KiFlushNPXState(NULL
);
537 /* Copy into the Context */
538 RtlCopyMemory(&Context
->FloatSave
,
540 sizeof(FNSAVE_FORMAT
));
544 /* FIXME: Handle Emulation */
549 /* Handle debug registers */
550 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) ==
551 CONTEXT_DEBUG_REGISTERS
)
553 /* Copy the debug registers */
554 Context
->Dr0
= TrapFrame
->Dr0
;
555 Context
->Dr1
= TrapFrame
->Dr1
;
556 Context
->Dr2
= TrapFrame
->Dr2
;
557 Context
->Dr3
= TrapFrame
->Dr3
;
558 Context
->Dr6
= TrapFrame
->Dr6
;
560 /* For user-mode, only set DR7 if a debugger is active */
561 if (((TrapFrame
->SegCs
& MODE_MASK
) ||
562 (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) &&
563 (KeGetCurrentThread()->DispatcherHeader
.DebugActive
))
566 Context
->Dr7
= TrapFrame
->Dr7
;
576 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
581 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord
,
582 PKEXCEPTION_FRAME ExceptionFrame
,
583 PKTRAP_FRAME TrapFrame
,
584 KPROCESSOR_MODE PreviousMode
,
588 KD_CONTINUE_TYPE Action
;
589 ULONG_PTR Stack
, NewStack
;
591 BOOLEAN UserDispatch
= FALSE
;
593 /* Increase number of Exception Dispatches */
594 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
596 /* Set the context flags */
597 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
599 /* Check if User Mode */
600 if (PreviousMode
== UserMode
)
602 /* Add the FPU Flag */
603 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
604 if (KeI386FxsrPresent
) Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
608 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
610 /* Handle kernel-mode first, it's simpler */
611 if (PreviousMode
== KernelMode
)
613 /* Check if this is a first-chance exception */
614 if (FirstChance
== TRUE
)
616 /* Break into the debugger for the first time */
617 Action
= KdpEnterDebuggerException(ExceptionRecord
,
624 /* If the debugger said continue, then continue */
625 if (Action
== kdContinue
) goto Handled
;
627 /* If the Debugger couldn't handle it, dispatch the exception */
628 if (RtlDispatchException(ExceptionRecord
, &Context
))
630 /* It was handled by an exception handler, continue */
635 /* This is a second-chance exception, only for the debugger */
636 Action
= KdpEnterDebuggerException(ExceptionRecord
,
643 /* If the debugger said continue, then continue */
644 if (Action
== kdContinue
) goto Handled
;
646 /* Third strike; you're out */
647 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
648 ExceptionRecord
->ExceptionCode
,
649 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
650 ExceptionRecord
->ExceptionInformation
[0],
651 ExceptionRecord
->ExceptionInformation
[1],
656 /* User mode exception, was it first-chance? */
659 /* Enter Debugger if available */
660 Action
= KdpEnterDebuggerException(ExceptionRecord
,
667 /* Exit if we're continuing */
668 if (Action
== kdContinue
) goto Handled
;
670 /* FIXME: Forward exception to user mode debugger */
672 /* Set up the user-stack */
675 /* Align context size and get stack pointer */
676 Size
= (sizeof(CONTEXT
) + 3) & ~3;
677 Stack
= (Context
.Esp
& ~3) - Size
;
678 DPRINT("Stack: %lx\n", Stack
);
680 /* Probe stack and copy Context */
681 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
682 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
684 /* Align exception record size and get stack pointer */
685 Size
= (sizeof(EXCEPTION_RECORD
) -
686 (EXCEPTION_MAXIMUM_PARAMETERS
- ExceptionRecord
->NumberParameters
) *
687 sizeof(ULONG
) + 3) & ~3;
688 NewStack
= Stack
- Size
;
689 DPRINT("NewStack: %lx\n", NewStack
);
691 /* Probe stack and copy exception record. Don't forget to add the two params */
692 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
693 Size
+ 2 * sizeof(ULONG_PTR
),
695 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
697 /* Now write the two params for the user-mode dispatcher */
698 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
699 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
701 /* Set new Stack Pointer */
702 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
704 /* Set EIP to the User-mode Dispathcer */
705 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
711 /* Do second-chance */
716 /* If we dispatch to user, return now */
717 if (UserDispatch
) return;
719 /* FIXME: Forward the exception to the debugger for 2nd chance */
721 /* 3rd strike, kill the thread */
722 DPRINT1("Unhandled UserMode exception, terminating thread\n");
723 ZwTerminateThread(NtCurrentThread(), ExceptionRecord
->ExceptionCode
);
724 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
725 ExceptionRecord
->ExceptionCode
,
726 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
727 ExceptionRecord
->ExceptionInformation
[0],
728 ExceptionRecord
->ExceptionInformation
[1],
733 /* Convert the context back into Trap/Exception Frames */
734 KeContextToTrapFrame(&Context
,
737 Context
.ContextFlags
,
747 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
750 PKTHREAD Thread
= KeGetCurrentThread();
752 /* Make sure we can access the TEB */
755 Thread
->Teb
->ExceptionCode
= ExceptionCode
;
759 return(ExceptionCode
);
763 /* Get the old EIP */
764 OldEip
= Thread
->TrapFrame
->Eip
;
766 /* Change it to the user-mode dispatcher */
767 Thread
->TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
769 /* Return the old EIP */
770 return((NTSTATUS
)OldEip
);