- Add about two dozen new bugcheck codes and strings.
[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 VOID
20 INIT_FUNCTION
21 NTAPI
22 KeInitExceptions(VOID)
23 {
24 ULONG i;
25 USHORT FlippedSelector;
26 extern KIDTENTRY KiIdt[];
27
28 /* Loop the IDT */
29 for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
30 {
31 /* Save the current Selector */
32 FlippedSelector = KiIdt[i].Selector;
33
34 /* Flip Selector and Extended Offset */
35 KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
36 KiIdt[i].ExtendedOffset = FlippedSelector;
37 }
38 }
39
40 ULONG
41 NTAPI
42 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
43 {
44 /* Check if this is user-mode or V86 */
45 if ((TrapFrame->SegCs & MODE_MASK) ||
46 (TrapFrame->EFlags & EFLAGS_V86_MASK))
47 {
48 /* Return it directly */
49 return TrapFrame->HardwareEsp;
50 }
51 else
52 {
53 /* Edited frame */
54 if (!(TrapFrame->SegCs & FRAME_EDITED))
55 {
56 /* Return edited value */
57 return TrapFrame->TempEsp;
58 }
59 else
60 {
61 /* Virgin frame, calculate */
62 return (ULONG)&TrapFrame->HardwareEsp;
63 }
64 }
65 }
66
67 VOID
68 NTAPI
69 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
70 IN ULONG Esp)
71 {
72 ULONG Previous = KiEspFromTrapFrame(TrapFrame);
73
74 /* Check if this is user-mode or V86 */
75 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
76 {
77 /* Write it directly */
78 TrapFrame->HardwareEsp = Esp;
79 }
80 else
81 {
82 /* Don't allow ESP to be lowered, this is illegal */
83 if (Esp < Previous) KeBugCheck(SET_OF_INVALID_CONTEXT);
84
85 /* Create an edit frame, check if it was alrady */
86 if (!(TrapFrame->SegCs & FRAME_EDITED))
87 {
88 /* Update the value */
89 TrapFrame->TempEsp = Esp;
90 }
91 else
92 {
93 /* Check if ESP changed */
94 if (Previous != Esp)
95 {
96 /* Save CS */
97 TrapFrame->TempSegCs = TrapFrame->SegCs;
98 TrapFrame->SegCs &= ~FRAME_EDITED;
99
100 /* Save ESP */
101 TrapFrame->TempEsp = Esp;
102 }
103 }
104 }
105 }
106
107 ULONG
108 NTAPI
109 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
110 {
111 /* If this was V86 Mode */
112 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
113 {
114 /* Just return it */
115 return TrapFrame->HardwareSegSs;
116 }
117 else if (TrapFrame->SegCs & MODE_MASK)
118 {
119 /* Usermode, return the User SS */
120 return TrapFrame->HardwareSegSs | RPL_MASK;
121 }
122 else
123 {
124 /* Kernel mode */
125 return KGDT_R0_DATA;
126 }
127 }
128
129 VOID
130 NTAPI
131 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
132 IN ULONG Ss)
133 {
134 /* Remove the high-bits */
135 Ss &= 0xFFFF;
136
137 /* If this was V86 Mode */
138 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
139 {
140 /* Just write it */
141 TrapFrame->HardwareSegSs = Ss;
142 }
143 else if (TrapFrame->SegCs & MODE_MASK)
144 {
145 /* Usermode, save the User SS */
146 TrapFrame->HardwareSegSs = Ss | RPL_MASK;
147 }
148 }
149
150 USHORT
151 NTAPI
152 KiTagWordFnsaveToFxsave(USHORT TagWord)
153 {
154 INT FxTagWord = ~TagWord;
155
156 /*
157 * Empty is now 00, any 2 bits containing 1 mean valid
158 * Now convert the rest (11->0 and the rest to 1)
159 */
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 */
164 return FxTagWord;
165 }
166
167 VOID
168 NTAPI
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)
174 {
175 PFX_SAVE_AREA FxSaveArea;
176 ULONG i;
177 BOOLEAN V86Switch = FALSE;
178 KIRQL OldIrql = APC_LEVEL;
179
180 /* Do this at APC_LEVEL */
181 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
182
183 /* Start with the basic Registers */
184 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
185 {
186 /* Check if we went through a V86 switch */
187 if ((Context->EFlags & EFLAGS_V86_MASK) !=
188 (TrapFrame->EFlags & EFLAGS_V86_MASK))
189 {
190 /* We did, remember this for later */
191 V86Switch = TRUE;
192 }
193
194 /* Copy EFLAGS. FIXME: Needs to be sanitized */
195 TrapFrame->EFlags = Context->EFlags;
196
197 /* Copy EBP and EIP */
198 TrapFrame->Ebp = Context->Ebp;
199 TrapFrame->Eip = Context->Eip;
200
201 /* Check if we were in V86 Mode */
202 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
203 {
204 /* Simply copy the CS value */
205 TrapFrame->SegCs = Context->SegCs;
206 }
207 else
208 {
209 /* We weren't in V86, so sanitize the CS (FIXME!) */
210 TrapFrame->SegCs = Context->SegCs;
211
212 /* Don't let it under 8, that's invalid */
213 if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
214 {
215 /* Force it to User CS */
216 TrapFrame->SegCs = (KGDT_R3_CODE | RPL_MASK);
217 }
218 }
219
220 /* Handle SS Specially for validation */
221 KiSsToTrapFrame(TrapFrame, Context->SegSs);
222
223 /* Write ESP back; take into account Edited Trap Frames */
224 KiEspToTrapFrame(TrapFrame, Context->Esp);
225
226 /* Handle our V86 Bias if we went through a switch */
227 if (V86Switch) Ki386AdjustEsp0(TrapFrame);
228 }
229
230 /* Process the Integer Registers */
231 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
232 {
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;
240 }
241
242 /* Process the Context Segments */
243 if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
244 {
245 /* Check if we were in V86 Mode */
246 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
247 {
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;
253 }
254 else if (!(TrapFrame->SegCs & MODE_MASK))
255 {
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;
261 }
262 else
263 {
264 /* For user mode, return the values directlry */
265 TrapFrame->SegDs = Context->SegDs;
266 TrapFrame->SegEs = Context->SegEs;
267 TrapFrame->SegFs = Context->SegFs;
268
269 /* Handle GS specially */
270 if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
271 {
272 /* Don't use it, if user */
273 TrapFrame->SegGs = 0;
274 }
275 else
276 {
277 /* Copy it if kernel */
278 TrapFrame->SegGs = Context->SegGs;
279 }
280 }
281 }
282
283 /* Handle the extended registers */
284 if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
285 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
286 {
287 /* Get the FX Area */
288 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
289
290 /* Check if NPX is present */
291 if (KeI386NpxPresent)
292 {
293 /* Flush the NPX State */
294 KiFlushNPXState(NULL);
295
296 /* Copy the FX State */
297 RtlCopyMemory(&FxSaveArea->U.FxArea,
298 &Context->ExtendedRegisters[0],
299 MAXIMUM_SUPPORTED_EXTENSION);
300
301 /* Remove reserved bits from MXCSR */
302 FxSaveArea->U.FxArea.MXCsr &= ~0xFFBF;
303
304 /* Mask out any invalid flags */
305 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
306
307 /* FIXME: Check if this is a VDM app */
308 }
309 }
310
311 /* Handle the floating point state */
312 if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
313 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
314 {
315 /* Get the FX Area */
316 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
317
318 /* Check if NPX is present */
319 if (KeI386NpxPresent)
320 {
321 /* Flush the NPX State */
322 KiFlushNPXState(NULL);
323
324 /* Check if we have Fxsr support */
325 if (KeI386FxsrPresent)
326 {
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;
344
345 /* Clear out the Register Area */
346 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0],
347 SIZE_OF_FX_REGISTERS);
348
349 /* Loop the 8 floating point registers */
350 for (i = 0; i < 8; i++)
351 {
352 /* Copy from Fn to Fx */
353 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
354 Context->FloatSave.RegisterArea + (i * 10),
355 10);
356 }
357 }
358 else
359 {
360 /* Just dump the Fn state in */
361 RtlCopyMemory(&FxSaveArea->U.FnArea,
362 &Context->FloatSave,
363 sizeof(FNSAVE_FORMAT));
364 }
365
366 /* Mask out any invalid flags */
367 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
368
369 /* FIXME: Check if this is a VDM app */
370 }
371 else
372 {
373 /* FIXME: Handle FPU Emulation */
374 ASSERT(FALSE);
375 }
376 }
377
378 /* Handle the Debug Registers */
379 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
380 {
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;
388
389 /* Check if usermode */
390 if (PreviousMode != KernelMode)
391 {
392 /* Set the Debug Flag */
393 KeGetCurrentThread()->DispatcherHeader.DebugActive =
394 (Context->Dr7 & DR7_ACTIVE);
395 }
396 }
397
398 /* Restore IRQL */
399 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
400 }
401
402 VOID
403 NTAPI
404 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
405 IN PKEXCEPTION_FRAME ExceptionFrame,
406 IN OUT PCONTEXT Context)
407 {
408 PFX_SAVE_AREA FxSaveArea;
409 struct _AlignHack
410 {
411 UCHAR Hack[15];
412 FLOATING_SAVE_AREA UnalignedArea;
413 } FloatSaveBuffer;
414 FLOATING_SAVE_AREA *FloatSaveArea;
415 KIRQL OldIrql = APC_LEVEL;
416
417 /* Do this at APC_LEVEL */
418 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
419
420 /* Start with the Control flags */
421 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
422 {
423 /* EBP, EIP and EFLAGS */
424 Context->Ebp = TrapFrame->Ebp;
425 Context->Eip = TrapFrame->Eip;
426 Context->EFlags = TrapFrame->EFlags;
427
428 /* Return the correct CS */
429 if (!(TrapFrame->SegCs & FRAME_EDITED) &&
430 !(TrapFrame->EFlags & EFLAGS_V86_MASK))
431 {
432 /* Get it from the Temp location */
433 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
434 }
435 else
436 {
437 /* Return it directly */
438 Context->SegCs = TrapFrame->SegCs & 0xFFFF;
439 }
440
441 /* Get the Ss and ESP */
442 Context->SegSs = KiSsFromTrapFrame(TrapFrame);
443 Context->Esp = KiEspFromTrapFrame(TrapFrame);
444 }
445
446 /* Handle the Segments */
447 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
448 {
449 /* Do V86 Mode first */
450 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
451 {
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;
457 }
458 else
459 {
460 /* Check if this was a Kernel Trap */
461 if (TrapFrame->SegCs == KGDT_R0_CODE)
462 {
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;
468 }
469
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;
475 }
476 }
477
478 /* Handle the simple registers */
479 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
480 {
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;
488 }
489
490 /* Handle extended registers */
491 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
492 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
493 {
494 /* Get the FX Save Area */
495 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
496
497 /* Make sure NPX is present */
498 if (KeI386NpxPresent)
499 {
500 /* Flush the NPX State */
501 KiFlushNPXState(NULL);
502
503 /* Copy the registers */
504 RtlCopyMemory(&Context->ExtendedRegisters[0],
505 &FxSaveArea->U.FxArea,
506 MAXIMUM_SUPPORTED_EXTENSION);
507 }
508 }
509
510 /* Handle Floating Point */
511 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
512 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
513 {
514 /* Get the FX Save Area */
515 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
516
517 /* Make sure we have an NPX */
518 if (KeI386NpxPresent)
519 {
520 /* Check if we have Fxsr support */
521 if (KeI386FxsrPresent)
522 {
523 /* Align the floating area to 16-bytes */
524 FloatSaveArea = (FLOATING_SAVE_AREA*)
525 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
526
527 /* Get the State */
528 KiFlushNPXState(FloatSaveArea);
529 }
530 else
531 {
532 /* We don't, use the FN area and flush the NPX State */
533 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
534 KiFlushNPXState(NULL);
535 }
536
537 /* Copy into the Context */
538 RtlCopyMemory(&Context->FloatSave,
539 FloatSaveArea,
540 sizeof(FNSAVE_FORMAT));
541 }
542 else
543 {
544 /* FIXME: Handle Emulation */
545 ASSERT(FALSE);
546 }
547 }
548
549 /* Handle debug registers */
550 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
551 CONTEXT_DEBUG_REGISTERS)
552 {
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;
559
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))
564 {
565 /* Copy it over */
566 Context->Dr7 = TrapFrame->Dr7;
567 }
568 else
569 {
570 /* Clear it */
571 Context->Dr7 = 0;
572 }
573 }
574
575 /* Restore IRQL */
576 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
577 }
578
579 VOID
580 NTAPI
581 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
582 PKEXCEPTION_FRAME ExceptionFrame,
583 PKTRAP_FRAME TrapFrame,
584 KPROCESSOR_MODE PreviousMode,
585 BOOLEAN FirstChance)
586 {
587 CONTEXT Context;
588 KD_CONTINUE_TYPE Action;
589 ULONG_PTR Stack, NewStack;
590 ULONG Size;
591 BOOLEAN UserDispatch = FALSE;
592
593 /* Increase number of Exception Dispatches */
594 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
595
596 /* Set the context flags */
597 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
598
599 /* Check if User Mode */
600 if (PreviousMode == UserMode)
601 {
602 /* Add the FPU Flag */
603 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
604 if (KeI386FxsrPresent) Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
605 }
606
607 /* Get a Context */
608 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
609
610 /* Handle kernel-mode first, it's simpler */
611 if (PreviousMode == KernelMode)
612 {
613 /* Check if this is a first-chance exception */
614 if (FirstChance == TRUE)
615 {
616 /* Break into the debugger for the first time */
617 Action = KdpEnterDebuggerException(ExceptionRecord,
618 PreviousMode,
619 &Context,
620 TrapFrame,
621 TRUE,
622 TRUE);
623
624 /* If the debugger said continue, then continue */
625 if (Action == kdContinue) goto Handled;
626
627 /* If the Debugger couldn't handle it, dispatch the exception */
628 if (RtlDispatchException(ExceptionRecord, &Context))
629 {
630 /* It was handled by an exception handler, continue */
631 goto Handled;
632 }
633 }
634
635 /* This is a second-chance exception, only for the debugger */
636 Action = KdpEnterDebuggerException(ExceptionRecord,
637 PreviousMode,
638 &Context,
639 TrapFrame,
640 FALSE,
641 FALSE);
642
643 /* If the debugger said continue, then continue */
644 if (Action == kdContinue) goto Handled;
645
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],
652 TrapFrame);
653 }
654 else
655 {
656 /* User mode exception, was it first-chance? */
657 if (FirstChance)
658 {
659 /* Enter Debugger if available */
660 Action = KdpEnterDebuggerException(ExceptionRecord,
661 PreviousMode,
662 &Context,
663 TrapFrame,
664 TRUE,
665 TRUE);
666
667 /* Exit if we're continuing */
668 if (Action == kdContinue) goto Handled;
669
670 /* FIXME: Forward exception to user mode debugger */
671
672 /* Set up the user-stack */
673 _SEH_TRY
674 {
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);
679
680 /* Probe stack and copy Context */
681 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
682 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
683
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);
690
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),
694 sizeof(ULONG));
695 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
696
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;
700
701 /* Set new Stack Pointer */
702 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
703
704 /* Set EIP to the User-mode Dispathcer */
705 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
706 UserDispatch = TRUE;
707 _SEH_LEAVE;
708 }
709 _SEH_HANDLE
710 {
711 /* Do second-chance */
712 }
713 _SEH_END;
714 }
715
716 /* If we dispatch to user, return now */
717 if (UserDispatch) return;
718
719 /* FIXME: Forward the exception to the debugger for 2nd chance */
720
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],
729 TrapFrame);
730 }
731
732 Handled:
733 /* Convert the context back into Trap/Exception Frames */
734 KeContextToTrapFrame(&Context,
735 NULL,
736 TrapFrame,
737 Context.ContextFlags,
738 PreviousMode);
739 return;
740 }
741
742 /*
743 * @implemented
744 */
745 NTSTATUS
746 NTAPI
747 KeRaiseUserException(IN NTSTATUS ExceptionCode)
748 {
749 ULONG OldEip;
750 PKTHREAD Thread = KeGetCurrentThread();
751
752 /* Make sure we can access the TEB */
753 _SEH_TRY
754 {
755 Thread->Teb->ExceptionCode = ExceptionCode;
756 }
757 _SEH_HANDLE
758 {
759 return(ExceptionCode);
760 }
761 _SEH_END;
762
763 /* Get the old EIP */
764 OldEip = Thread->TrapFrame->Eip;
765
766 /* Change it to the user-mode dispatcher */
767 Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
768
769 /* Return the old EIP */
770 return((NTSTATUS)OldEip);
771 }
772