- Fix KeRaiseUserException (can't use "return" from SEH_HANDLE).
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
1 /*
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)
7 * Gregor Anich
8 * Skywing (skywing@valhallalegends.com)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 _SEH_DEFINE_LOCALS(KiCopyInfo)
20 {
21 volatile EXCEPTION_RECORD SehExceptRecord;
22 };
23
24 _SEH_FILTER(KiCopyInformation)
25 {
26 _SEH_ACCESS_LOCALS(KiCopyInfo);
27
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;
33 }
34
35 VOID
36 INIT_FUNCTION
37 NTAPI
38 KeInitExceptions(VOID)
39 {
40 ULONG i;
41 USHORT FlippedSelector;
42 extern KIDTENTRY KiIdt[];
43
44 /* Loop the IDT */
45 for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
46 {
47 /* Save the current Selector */
48 FlippedSelector = KiIdt[i].Selector;
49
50 /* Flip Selector and Extended Offset */
51 KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
52 KiIdt[i].ExtendedOffset = FlippedSelector;
53 }
54 }
55
56 ULONG
57 NTAPI
58 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
59 {
60 /* Check if this is user-mode or V86 */
61 if ((TrapFrame->SegCs & MODE_MASK) ||
62 (TrapFrame->EFlags & EFLAGS_V86_MASK))
63 {
64 /* Return it directly */
65 return TrapFrame->HardwareEsp;
66 }
67 else
68 {
69 /* Edited frame */
70 if (!(TrapFrame->SegCs & FRAME_EDITED))
71 {
72 /* Return edited value */
73 return TrapFrame->TempEsp;
74 }
75 else
76 {
77 /* Virgin frame, calculate */
78 return (ULONG)&TrapFrame->HardwareEsp;
79 }
80 }
81 }
82
83 VOID
84 NTAPI
85 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
86 IN ULONG Esp)
87 {
88 ULONG Previous = KiEspFromTrapFrame(TrapFrame);
89
90 /* Check if this is user-mode or V86 */
91 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
92 {
93 /* Write it directly */
94 TrapFrame->HardwareEsp = Esp;
95 }
96 else
97 {
98 /* Don't allow ESP to be lowered, this is illegal */
99 if (Esp < Previous) KeBugCheck(SET_OF_INVALID_CONTEXT);
100
101 /* Create an edit frame, check if it was alrady */
102 if (!(TrapFrame->SegCs & FRAME_EDITED))
103 {
104 /* Update the value */
105 TrapFrame->TempEsp = Esp;
106 }
107 else
108 {
109 /* Check if ESP changed */
110 if (Previous != Esp)
111 {
112 /* Save CS */
113 TrapFrame->TempSegCs = TrapFrame->SegCs;
114 TrapFrame->SegCs &= ~FRAME_EDITED;
115
116 /* Save ESP */
117 TrapFrame->TempEsp = Esp;
118 }
119 }
120 }
121 }
122
123 ULONG
124 NTAPI
125 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
126 {
127 /* If this was V86 Mode */
128 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
129 {
130 /* Just return it */
131 return TrapFrame->HardwareSegSs;
132 }
133 else if (TrapFrame->SegCs & MODE_MASK)
134 {
135 /* Usermode, return the User SS */
136 return TrapFrame->HardwareSegSs | RPL_MASK;
137 }
138 else
139 {
140 /* Kernel mode */
141 return KGDT_R0_DATA;
142 }
143 }
144
145 VOID
146 NTAPI
147 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
148 IN ULONG Ss)
149 {
150 /* Remove the high-bits */
151 Ss &= 0xFFFF;
152
153 /* If this was V86 Mode */
154 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
155 {
156 /* Just write it */
157 TrapFrame->HardwareSegSs = Ss;
158 }
159 else if (TrapFrame->SegCs & MODE_MASK)
160 {
161 /* Usermode, save the User SS */
162 TrapFrame->HardwareSegSs = Ss | RPL_MASK;
163 }
164 }
165
166 USHORT
167 NTAPI
168 KiTagWordFnsaveToFxsave(USHORT TagWord)
169 {
170 INT FxTagWord = ~TagWord;
171
172 /*
173 * Empty is now 00, any 2 bits containing 1 mean valid
174 * Now convert the rest (11->0 and the rest to 1)
175 */
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 */
180 return FxTagWord;
181 }
182
183 VOID
184 NTAPI
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)
190 {
191 PFX_SAVE_AREA FxSaveArea;
192 ULONG i;
193 BOOLEAN V86Switch = FALSE;
194 KIRQL OldIrql = APC_LEVEL;
195
196 /* Do this at APC_LEVEL */
197 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
198
199 /* Start with the basic Registers */
200 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
201 {
202 /* Check if we went through a V86 switch */
203 if ((Context->EFlags & EFLAGS_V86_MASK) !=
204 (TrapFrame->EFlags & EFLAGS_V86_MASK))
205 {
206 /* We did, remember this for later */
207 V86Switch = TRUE;
208 }
209
210 /* Copy EFLAGS. FIXME: Needs to be sanitized */
211 TrapFrame->EFlags = Context->EFlags;
212
213 /* Copy EBP and EIP */
214 TrapFrame->Ebp = Context->Ebp;
215 TrapFrame->Eip = Context->Eip;
216
217 /* Check if we were in V86 Mode */
218 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
219 {
220 /* Simply copy the CS value */
221 TrapFrame->SegCs = Context->SegCs;
222 }
223 else
224 {
225 /* We weren't in V86, so sanitize the CS (FIXME!) */
226 TrapFrame->SegCs = Context->SegCs;
227
228 /* Don't let it under 8, that's invalid */
229 if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
230 {
231 /* Force it to User CS */
232 TrapFrame->SegCs = (KGDT_R3_CODE | RPL_MASK);
233 }
234 }
235
236 /* Handle SS Specially for validation */
237 KiSsToTrapFrame(TrapFrame, Context->SegSs);
238
239 /* Write ESP back; take into account Edited Trap Frames */
240 KiEspToTrapFrame(TrapFrame, Context->Esp);
241
242 /* Handle our V86 Bias if we went through a switch */
243 if (V86Switch) Ki386AdjustEsp0(TrapFrame);
244 }
245
246 /* Process the Integer Registers */
247 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
248 {
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;
256 }
257
258 /* Process the Context Segments */
259 if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
260 {
261 /* Check if we were in V86 Mode */
262 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
263 {
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;
269 }
270 else if (!(TrapFrame->SegCs & MODE_MASK))
271 {
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;
277 }
278 else
279 {
280 /* For user mode, return the values directlry */
281 TrapFrame->SegDs = Context->SegDs;
282 TrapFrame->SegEs = Context->SegEs;
283 TrapFrame->SegFs = Context->SegFs;
284
285 /* Handle GS specially */
286 if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
287 {
288 /* Don't use it, if user */
289 TrapFrame->SegGs = 0;
290 }
291 else
292 {
293 /* Copy it if kernel */
294 TrapFrame->SegGs = Context->SegGs;
295 }
296 }
297 }
298
299 /* Handle the extended registers */
300 if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
301 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
302 {
303 /* Get the FX Area */
304 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
305
306 /* Check if NPX is present */
307 if (KeI386NpxPresent)
308 {
309 /* Flush the NPX State */
310 KiFlushNPXState(NULL);
311
312 /* Copy the FX State */
313 RtlCopyMemory(&FxSaveArea->U.FxArea,
314 &Context->ExtendedRegisters[0],
315 MAXIMUM_SUPPORTED_EXTENSION);
316
317 /* Remove reserved bits from MXCSR */
318 FxSaveArea->U.FxArea.MXCsr &= ~0xFFBF;
319
320 /* Mask out any invalid flags */
321 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
322
323 /* FIXME: Check if this is a VDM app */
324 }
325 }
326
327 /* Handle the floating point state */
328 if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
329 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
330 {
331 /* Get the FX Area */
332 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
333
334 /* Check if NPX is present */
335 if (KeI386NpxPresent)
336 {
337 /* Flush the NPX State */
338 KiFlushNPXState(NULL);
339
340 /* Check if we have Fxsr support */
341 if (KeI386FxsrPresent)
342 {
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;
360
361 /* Clear out the Register Area */
362 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0],
363 SIZE_OF_FX_REGISTERS);
364
365 /* Loop the 8 floating point registers */
366 for (i = 0; i < 8; i++)
367 {
368 /* Copy from Fn to Fx */
369 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
370 Context->FloatSave.RegisterArea + (i * 10),
371 10);
372 }
373 }
374 else
375 {
376 /* Just dump the Fn state in */
377 RtlCopyMemory(&FxSaveArea->U.FnArea,
378 &Context->FloatSave,
379 sizeof(FNSAVE_FORMAT));
380 }
381
382 /* Mask out any invalid flags */
383 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
384
385 /* FIXME: Check if this is a VDM app */
386 }
387 else
388 {
389 /* FIXME: Handle FPU Emulation */
390 ASSERT(FALSE);
391 }
392 }
393
394 /* Handle the Debug Registers */
395 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
396 {
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;
404
405 /* Check if usermode */
406 if (PreviousMode != KernelMode)
407 {
408 /* Set the Debug Flag */
409 KeGetCurrentThread()->DispatcherHeader.DebugActive =
410 (Context->Dr7 & DR7_ACTIVE);
411 }
412 }
413
414 /* Restore IRQL */
415 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
416 }
417
418 VOID
419 NTAPI
420 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
421 IN PKEXCEPTION_FRAME ExceptionFrame,
422 IN OUT PCONTEXT Context)
423 {
424 PFX_SAVE_AREA FxSaveArea;
425 struct _AlignHack
426 {
427 UCHAR Hack[15];
428 FLOATING_SAVE_AREA UnalignedArea;
429 } FloatSaveBuffer;
430 FLOATING_SAVE_AREA *FloatSaveArea;
431 KIRQL OldIrql = APC_LEVEL;
432
433 /* Do this at APC_LEVEL */
434 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
435
436 /* Start with the Control flags */
437 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
438 {
439 /* EBP, EIP and EFLAGS */
440 Context->Ebp = TrapFrame->Ebp;
441 Context->Eip = TrapFrame->Eip;
442 Context->EFlags = TrapFrame->EFlags;
443
444 /* Return the correct CS */
445 if (!(TrapFrame->SegCs & FRAME_EDITED) &&
446 !(TrapFrame->EFlags & EFLAGS_V86_MASK))
447 {
448 /* Get it from the Temp location */
449 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
450 }
451 else
452 {
453 /* Return it directly */
454 Context->SegCs = TrapFrame->SegCs & 0xFFFF;
455 }
456
457 /* Get the Ss and ESP */
458 Context->SegSs = KiSsFromTrapFrame(TrapFrame);
459 Context->Esp = KiEspFromTrapFrame(TrapFrame);
460 }
461
462 /* Handle the Segments */
463 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
464 {
465 /* Do V86 Mode first */
466 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
467 {
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;
473 }
474 else
475 {
476 /* Check if this was a Kernel Trap */
477 if (TrapFrame->SegCs == KGDT_R0_CODE)
478 {
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;
484 }
485
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;
491 }
492 }
493
494 /* Handle the simple registers */
495 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
496 {
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;
504 }
505
506 /* Handle extended registers */
507 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
508 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
509 {
510 /* Get the FX Save Area */
511 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
512
513 /* Make sure NPX is present */
514 if (KeI386NpxPresent)
515 {
516 /* Flush the NPX State */
517 KiFlushNPXState(NULL);
518
519 /* Copy the registers */
520 RtlCopyMemory(&Context->ExtendedRegisters[0],
521 &FxSaveArea->U.FxArea,
522 MAXIMUM_SUPPORTED_EXTENSION);
523 }
524 }
525
526 /* Handle Floating Point */
527 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
528 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
529 {
530 /* Get the FX Save Area */
531 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
532
533 /* Make sure we have an NPX */
534 if (KeI386NpxPresent)
535 {
536 /* Check if we have Fxsr support */
537 if (KeI386FxsrPresent)
538 {
539 /* Align the floating area to 16-bytes */
540 FloatSaveArea = (FLOATING_SAVE_AREA*)
541 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
542
543 /* Get the State */
544 KiFlushNPXState(FloatSaveArea);
545 }
546 else
547 {
548 /* We don't, use the FN area and flush the NPX State */
549 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
550 KiFlushNPXState(NULL);
551 }
552
553 /* Copy into the Context */
554 RtlCopyMemory(&Context->FloatSave,
555 FloatSaveArea,
556 sizeof(FNSAVE_FORMAT));
557 }
558 else
559 {
560 /* FIXME: Handle Emulation */
561 ASSERT(FALSE);
562 }
563 }
564
565 /* Handle debug registers */
566 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
567 CONTEXT_DEBUG_REGISTERS)
568 {
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;
575
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))
580 {
581 /* Copy it over */
582 Context->Dr7 = TrapFrame->Dr7;
583 }
584 else
585 {
586 /* Clear it */
587 Context->Dr7 = 0;
588 }
589 }
590
591 /* Restore IRQL */
592 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
593 }
594
595 VOID
596 NTAPI
597 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
598 PKEXCEPTION_FRAME ExceptionFrame,
599 PKTRAP_FRAME TrapFrame,
600 KPROCESSOR_MODE PreviousMode,
601 BOOLEAN FirstChance)
602 {
603 CONTEXT Context;
604 KD_CONTINUE_TYPE Action;
605 ULONG_PTR Stack, NewStack;
606 ULONG Size;
607 EXCEPTION_RECORD LocalExceptRecord;
608 _SEH_DECLARE_LOCALS(KiCopyInfo);
609
610 /* Increase number of Exception Dispatches */
611 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
612
613 /* Set the context flags */
614 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
615
616 /* Check if User Mode or if the debugger isenabled */
617 if ((PreviousMode == UserMode) || (KdDebuggerEnabled))
618 {
619 /* Add the FPU Flag */
620 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
621
622 /* Check for NPX Support */
623 if (KeI386FxsrPresent)
624 {
625 /* Save those too */
626 Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
627 }
628 }
629
630 /* Get a Context */
631 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
632
633 /* Fix up EIP */
634 if (ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
635 {
636 /* Decrement EIP by one */
637 Context.Eip--;
638 }
639
640 ASSERT(!((PreviousMode == KernelMode) &&
641 (Context.EFlags & EFLAGS_V86_MASK)));
642
643 /* Handle kernel-mode first, it's simpler */
644 if (PreviousMode == KernelMode)
645 {
646 /* Check if this is a first-chance exception */
647 if (FirstChance == TRUE)
648 {
649 /* Break into the debugger for the first time */
650 Action = KdpEnterDebuggerException(ExceptionRecord,
651 PreviousMode,
652 &Context,
653 TrapFrame,
654 TRUE,
655 TRUE);
656
657 /* If the debugger said continue, then continue */
658 if (Action == kdContinue) goto Handled;
659
660 /* If the Debugger couldn't handle it, dispatch the exception */
661 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
662 }
663
664 /* This is a second-chance exception, only for the debugger */
665 Action = KdpEnterDebuggerException(ExceptionRecord,
666 PreviousMode,
667 &Context,
668 TrapFrame,
669 FALSE,
670 FALSE);
671
672 /* If the debugger said continue, then continue */
673 if (Action == kdContinue) goto Handled;
674
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]);
681 }
682 else
683 {
684 /* User mode exception, was it first-chance? */
685 if (FirstChance)
686 {
687 /* Enter Debugger if available */
688 Action = KdpEnterDebuggerException(ExceptionRecord,
689 PreviousMode,
690 &Context,
691 TrapFrame,
692 TRUE,
693 TRUE);
694
695 /* Exit if we're continuing */
696 if (Action == kdContinue) goto Handled;
697
698 /* FIXME: Forward exception to user mode debugger */
699 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) goto Exit;
700
701 /* Set up the user-stack */
702 DispatchToUser:
703 _SEH_TRY
704 {
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))
708 {
709 /* Raise an exception instead */
710 LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION;
711 LocalExceptRecord.ExceptionFlags = 0;
712 LocalExceptRecord.NumberParameters = 0;
713 RtlRaiseException(&LocalExceptRecord);
714 }
715
716 /* Align context size and get stack pointer */
717 Size = (sizeof(CONTEXT) + 3) & ~3;
718 Stack = (Context.Esp & ~3) - Size;
719
720 /* Probe stack and copy Context */
721 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
722 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
723
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;
730
731 /* Probe stack and copy exception record */
732 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
733 Size + 2 * sizeof(ULONG_PTR),
734 sizeof(ULONG));
735 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
736
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;
740
741 /* Set new Stack Pointer */
742 KiSsToTrapFrame(TrapFrame, KGDT_R3_DATA);
743 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
744
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;
751
752 /* Set EIP to the User-mode Dispathcer */
753 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
754 _SEH_LEAVE;
755 }
756 _SEH_EXCEPT(KiCopyInformation)
757 {
758 /* Check if we got a stack overflow and raise that instead */
759 if (_SEH_VAR(SehExceptRecord).ExceptionCode ==
760 STATUS_STACK_OVERFLOW)
761 {
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));
768
769 /* Do the exception again */
770 goto DispatchToUser;
771 }
772 }
773 _SEH_END;
774 }
775
776 /* Try second chance */
777 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE))
778 {
779 /* Handled, get out */
780 goto Exit;
781 }
782 else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE))
783 {
784 /* Handled, get out */
785 goto Exit;
786 }
787
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]);
795 }
796
797 Handled:
798 /* Convert the context back into Trap/Exception Frames */
799 KeContextToTrapFrame(&Context,
800 NULL,
801 TrapFrame,
802 Context.ContextFlags,
803 PreviousMode);
804 Exit:
805 return;
806 }
807
808 /*
809 * @implemented
810 */
811 NTSTATUS
812 NTAPI
813 KeRaiseUserException(IN NTSTATUS ExceptionCode)
814 {
815 NTSTATUS Status = STATUS_SUCCESS;
816 ULONG OldEip;
817 PTEB Teb = KeGetCurrentThread()->Teb;
818 PKTRAP_FRAME TrapFrame = KeGetCurrentThread()->TrapFrame;
819
820 /* Make sure we can access the TEB */
821 _SEH_TRY
822 {
823 /* Set the exception code */
824 Teb->ExceptionCode = ExceptionCode;
825 }
826 _SEH_HANDLE
827 {
828 /* Save exception code */
829 Status = ExceptionCode;
830 }
831 _SEH_END;
832 if (!NT_SUCCESS(Status)) return Status;
833
834 /* Get the old EIP */
835 OldEip = TrapFrame->Eip;
836
837 /* Change it to the user-mode dispatcher */
838 TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
839
840 /* Return the old EIP */
841 return (NTSTATUS)OldEip;
842 }
843