- Implement generic exception dispatcher for traps (kind-of analogous to KiKernelTrap...
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ke/i386/exp.c
5 * PURPOSE: Exception Support Code
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Gregor Anich
8 * David Welch (welch@cwcom.net)
9 * Skywing (skywing@valhallalegends.com)
10 */
11
12 /*
13 * FIXMES:
14 * - Clean up file (remove all stack functions and use RtlWalkFrameChain/RtlCaptureStackBacktrace)
15 * - Sanitize some context fields.
16 * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
17 * - Forward exceptions to user-mode debugger.
18 */
19
20 /* INCLUDES *****************************************************************/
21
22 #include <ntoskrnl.h>
23
24 #define NDEBUG
25 #include <internal/debug.h>
26
27 #if defined (ALLOC_PRAGMA)
28 #pragma alloc_text(INIT, KeInitExceptions)
29 #endif
30
31 #define SIZE_OF_FX_REGISTERS 32
32
33 VOID
34 NTAPI
35 Ki386AdjustEsp0(
36 IN PKTRAP_FRAME TrapFrame
37 );
38
39 VOID
40 NTAPI
41 KiFlushNPXState(
42 IN FLOATING_SAVE_AREA *SaveArea
43 );
44
45 extern KIDTENTRY KiIdt[];
46
47 /* GLOBALS *****************************************************************/
48
49 #define FLAG_IF (1<<9)
50
51 #define _STR(x) #x
52 #define STR(x) _STR(x)
53
54 #ifndef ARRAY_SIZE
55 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
56 #endif
57
58 extern ULONG init_stack;
59 extern ULONG init_stack_top;
60
61 extern BOOLEAN Ke386NoExecute;
62
63 static char *ExceptionTypeStrings[] =
64 {
65 "Divide Error",
66 "Debug Trap",
67 "NMI",
68 "Breakpoint",
69 "Overflow",
70 "BOUND range exceeded",
71 "Invalid Opcode",
72 "No Math Coprocessor",
73 "Double Fault",
74 "Unknown(9)",
75 "Invalid TSS",
76 "Segment Not Present",
77 "Stack Segment Fault",
78 "General Protection",
79 "Page Fault",
80 "Reserved(15)",
81 "Math Fault",
82 "Alignment Check",
83 "Machine Check",
84 "SIMD Fault"
85 };
86
87 NTSTATUS ExceptionToNtStatus[] =
88 {
89 STATUS_INTEGER_DIVIDE_BY_ZERO,
90 STATUS_SINGLE_STEP,
91 STATUS_ACCESS_VIOLATION,
92 STATUS_BREAKPOINT,
93 STATUS_INTEGER_OVERFLOW,
94 STATUS_ARRAY_BOUNDS_EXCEEDED,
95 STATUS_ILLEGAL_INSTRUCTION,
96 STATUS_FLOAT_INVALID_OPERATION,
97 STATUS_ACCESS_VIOLATION,
98 STATUS_ACCESS_VIOLATION,
99 STATUS_ACCESS_VIOLATION,
100 STATUS_ACCESS_VIOLATION,
101 STATUS_STACK_OVERFLOW,
102 STATUS_ACCESS_VIOLATION,
103 STATUS_ACCESS_VIOLATION,
104 STATUS_ACCESS_VIOLATION, /* RESERVED */
105 STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
106 STATUS_DATATYPE_MISALIGNMENT,
107 STATUS_ACCESS_VIOLATION,
108 STATUS_FLOAT_MULTIPLE_TRAPS,
109 };
110
111 /* FUNCTIONS ****************************************************************/
112
113 BOOLEAN STDCALL
114 KiRosPrintAddress(PVOID address)
115 {
116 PLIST_ENTRY current_entry;
117 PLDR_DATA_TABLE_ENTRY current;
118 extern LIST_ENTRY ModuleListHead;
119 ULONG_PTR RelativeAddress;
120 ULONG i = 0;
121
122 do
123 {
124 current_entry = ModuleListHead.Flink;
125
126 while (current_entry != &ModuleListHead)
127 {
128 current =
129 CONTAINING_RECORD(current_entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
130
131 if (address >= (PVOID)current->DllBase &&
132 address < (PVOID)((ULONG_PTR)current->DllBase + current->SizeOfImage))
133 {
134 RelativeAddress = (ULONG_PTR) address - (ULONG_PTR) current->DllBase;
135 DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
136 return(TRUE);
137 }
138 current_entry = current_entry->Flink;
139 }
140
141 address = (PVOID)((ULONG_PTR)address & ~(ULONG_PTR)MmSystemRangeStart);
142 } while(++i <= 1);
143
144 return(FALSE);
145 }
146
147 ULONG
148 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
149 {
150 EXCEPTION_RECORD Er;
151
152 Er.ExceptionFlags = 0;
153 Er.ExceptionRecord = NULL;
154 Er.ExceptionAddress = (PVOID)Tf->Eip;
155
156 if (ExceptionNr == 14)
157 {
158 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
159 Er.NumberParameters = 2;
160 Er.ExceptionInformation[0] = Tf->ErrCode & 0x1;
161 Er.ExceptionInformation[1] = (ULONG)Cr2;
162 }
163 else
164 {
165 if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
166 {
167 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
168 }
169 else
170 {
171 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
172 }
173 Er.NumberParameters = 0;
174 }
175
176 /* FIXME: Which exceptions are noncontinuable? */
177 Er.ExceptionFlags = 0;
178
179 KiDispatchException(&Er, NULL, Tf, KernelMode, TRUE);
180
181 return(0);
182 }
183
184 VOID
185 KiDoubleFaultHandler(VOID)
186 {
187 #if 0
188 unsigned int cr2;
189 ULONG StackLimit;
190 ULONG StackBase;
191 ULONG Esp0;
192 ULONG ExceptionNr = 8;
193 KTSS* OldTss;
194 PULONG Frame;
195 ULONG OldCr3;
196 #if 0
197 ULONG i, j;
198 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
199 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
200 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
201 ULONG TraceLength;
202 BOOLEAN FoundRepeat;
203 #endif
204
205 OldTss = KeGetCurrentKPCR()->TSS;
206 Esp0 = OldTss->Esp0;
207
208 /* Get CR2 */
209 cr2 = Ke386GetCr2();
210 if (PsGetCurrentThread() != NULL &&
211 PsGetCurrentThread()->ThreadsProcess != NULL)
212 {
213 OldCr3 = (ULONG)
214 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
215 }
216 else
217 {
218 OldCr3 = 0xBEADF0AL;
219 }
220
221 /*
222 * Check for stack underflow
223 */
224 if (PsGetCurrentThread() != NULL &&
225 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
226 {
227 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
228 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
229 ExceptionNr = 12;
230 }
231
232 /*
233 * Print out the CPU registers
234 */
235 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
236 {
237 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
238 ExceptionNr, 0);
239 }
240 else
241 {
242 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
243 }
244 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
245 KeRosPrintAddress((PVOID)OldTss->Eip);
246 DbgPrint("\n");
247 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
248 DbgPrint("Proc: %x ",PsGetCurrentProcess());
249 if (PsGetCurrentProcess() != NULL)
250 {
251 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
252 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
253 }
254 if (PsGetCurrentThread() != NULL)
255 {
256 DbgPrint("Thrd: %x Tid: %x",
257 PsGetCurrentThread(),
258 PsGetCurrentThread()->Cid.UniqueThread);
259 }
260 DbgPrint("\n");
261 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
262 OldTss->Fs, OldTss->Gs);
263 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
264 OldTss->Ecx);
265 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss->Edx,
266 OldTss->Ebp, OldTss->Esi, Esp0);
267 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
268 if (OldTss->Cs == KGDT_R0_CODE)
269 {
270 DbgPrint("kESP %.8x ", Esp0);
271 if (PsGetCurrentThread() != NULL)
272 {
273 DbgPrint("kernel stack base %x\n",
274 PsGetCurrentThread()->Tcb.StackLimit);
275
276 }
277 }
278 else
279 {
280 DbgPrint("User ESP %.8x\n", OldTss->Esp);
281 }
282 if ((OldTss->Cs & 0xffff) == KGDT_R0_CODE)
283 {
284 if (PsGetCurrentThread() != NULL)
285 {
286 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
287 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
288 }
289 else
290 {
291 StackLimit = (ULONG)init_stack_top;
292 StackBase = (ULONG)init_stack;
293 }
294
295 /*
296 Change to an #if 0 to reduce the amount of information printed on
297 a recursive stack trace.
298 */
299 #if 1
300 DbgPrint("Frames: ");
301 Frame = (PULONG)OldTss->Ebp;
302 while (Frame != NULL && (ULONG)Frame >= StackBase)
303 {
304 KeRosPrintAddress((PVOID)Frame[1]);
305 Frame = (PULONG)Frame[0];
306 DbgPrint("\n");
307 }
308 #else
309 DbgPrint("Frames: ");
310 i = 0;
311 Frame = (PULONG)OldTss->Ebp;
312 while (Frame != NULL && (ULONG)Frame >= StackBase)
313 {
314 StackTrace[i] = (PVOID)Frame[1];
315 Frame = (PULONG)Frame[0];
316 i++;
317 }
318 TraceLength = i;
319
320 i = 0;
321 while (i < TraceLength)
322 {
323 StackRepeatCount[i] = 0;
324 j = i + 1;
325 FoundRepeat = FALSE;
326 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
327 {
328 if (memcmp(&StackTrace[i], &StackTrace[j],
329 (j - i) * sizeof(PVOID)) == 0)
330 {
331 StackRepeatCount[i] = 2;
332 StackRepeatLength[i] = j - i;
333 FoundRepeat = TRUE;
334 }
335 else
336 {
337 j++;
338 }
339 }
340 if (FoundRepeat == FALSE)
341 {
342 i++;
343 continue;
344 }
345 j = j + StackRepeatLength[i];
346 while ((TraceLength - j) >= StackRepeatLength[i] &&
347 FoundRepeat == TRUE)
348 {
349 if (memcmp(&StackTrace[i], &StackTrace[j],
350 StackRepeatLength[i] * sizeof(PVOID)) == 0)
351 {
352 StackRepeatCount[i]++;
353 j = j + StackRepeatLength[i];
354 }
355 else
356 {
357 FoundRepeat = FALSE;
358 }
359 }
360 i = j;
361 }
362
363 i = 0;
364 while (i < TraceLength)
365 {
366 if (StackRepeatCount[i] == 0)
367 {
368 KeRosPrintAddress(StackTrace[i]);
369 i++;
370 }
371 else
372 {
373 DbgPrint("{");
374 if (StackRepeatLength[i] == 0)
375 {
376 for(;;);
377 }
378 for (j = 0; j < StackRepeatLength[i]; j++)
379 {
380 KeRosPrintAddress(StackTrace[i + j]);
381 }
382 DbgPrint("}*%d", StackRepeatCount[i]);
383 i = i + StackRepeatLength[i] * StackRepeatCount[i];
384 }
385 }
386 #endif
387 }
388 #endif
389 DbgPrint("\n");
390 for(;;);
391 }
392
393 VOID
394 NTAPI
395 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
396 {
397 ULONG cr3_;
398 ULONG StackLimit;
399 ULONG Esp0;
400 ULONG ExceptionNr = (ULONG)Tf->DbgArgMark;
401 ULONG cr2 = (ULONG)Tf->DbgArgPointer;
402
403 Esp0 = (ULONG)Tf;
404
405 /*
406 * Print out the CPU registers
407 */
408 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
409 {
410 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
411 ExceptionNr, Tf->ErrCode&0xffff);
412 }
413 else
414 {
415 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrCode&0xffff);
416 }
417 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
418 Tf->SegCs&0xffff, Tf->Eip);
419 KeRosPrintAddress((PVOID)Tf->Eip);
420 DbgPrint("\n");
421 Ke386GetPageTableDirectory(cr3_);
422 DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
423 DbgPrint("Proc: %x ",PsGetCurrentProcess());
424 if (PsGetCurrentProcess() != NULL)
425 {
426 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
427 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
428 }
429 if (PsGetCurrentThread() != NULL)
430 {
431 DbgPrint("Thrd: %x Tid: %x",
432 PsGetCurrentThread(),
433 PsGetCurrentThread()->Cid.UniqueThread);
434 }
435 DbgPrint("\n");
436 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->SegDs&0xffff, Tf->SegEs&0xffff,
437 Tf->SegFs&0xffff, Tf->SegGs&0xfff);
438 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
439 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
440 Tf->Ebp, Tf->Esi, Esp0);
441 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->EFlags);
442 if ((Tf->SegCs&0xffff) == KGDT_R0_CODE)
443 {
444 DbgPrint("kESP %.8x ", Esp0);
445 if (PsGetCurrentThread() != NULL)
446 {
447 DbgPrint("kernel stack base %x\n",
448 PsGetCurrentThread()->Tcb.StackLimit);
449
450 }
451 }
452
453 if (PsGetCurrentThread() != NULL)
454 {
455 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
456 }
457 else
458 {
459 StackLimit = (ULONG)init_stack_top;
460 }
461
462 /*
463 * Dump the stack frames
464 */
465 KeDumpStackFrames((PULONG)Tf->Ebp);
466 }
467
468 ULONG
469 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
470 /*
471 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
472 * message and halt the computer
473 * ARGUMENTS:
474 * Complete CPU context
475 */
476 {
477 ULONG_PTR cr2;
478 ULONG Esp0;
479
480 ASSERT(ExceptionNr != 14);
481 ASSERT((ExceptionNr != 7 && ExceptionNr != 16 && ExceptionNr != 19));
482
483 /* Use the address of the trap frame as approximation to the ring0 esp */
484 Esp0 = (ULONG)&Tf->Eip;
485
486 /* Get CR2 */
487 cr2 = Ke386GetCr2();
488 Tf->DbgArgPointer = cr2;
489
490 /*
491 * If this was a V86 mode exception then handle it specially
492 */
493 if (Tf->EFlags & (1 << 17))
494 {
495 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->EFlags, Tf->Eip, ExceptionNr);
496 return(KeV86Exception(ExceptionNr, Tf, cr2));
497 }
498
499 /*
500 * Check for stack underflow, this may be obsolete
501 */
502 DPRINT1("Exception: %x\n", ExceptionNr);
503 if (PsGetCurrentThread() != NULL &&
504 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
505 {
506 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
507 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit, Tf->Eip);
508 ExceptionNr = 12;
509 }
510
511 if (ExceptionNr == 15)
512 {
513 /*
514 * FIXME:
515 * This exception should never occur. The P6 has a bug, which does sometimes deliver
516 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
517 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
518 * sources. Linux does ignore this exception.
519 *
520 */
521 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
522 return(0);
523 }
524
525 /*
526 * Check for a breakpoint that was only for the attention of the debugger.
527 */
528 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
529 {
530 /*
531 EIP is already adjusted by the processor to point to the instruction
532 after the breakpoint.
533 */
534 return(0);
535 }
536
537 /*
538 * Handle user exceptions differently
539 */
540 if ((Tf->SegCs & 0xFFFF) == (KGDT_R3_CODE | RPL_MASK))
541 {
542 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
543 }
544 else
545 {
546 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
547 }
548 }
549
550 ULONG
551 NTAPI
552 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
553 {
554 /* Check if this is user-mode or V86 */
555 if ((TrapFrame->SegCs & MODE_MASK) ||
556 (TrapFrame->EFlags & EFLAGS_V86_MASK))
557 {
558 /* Return it directly */
559 return TrapFrame->HardwareEsp;
560 }
561 else
562 {
563 /* Edited frame */
564 if (!(TrapFrame->SegCs & FRAME_EDITED))
565 {
566 /* Return edited value */
567 return TrapFrame->TempEsp;
568 }
569 else
570 {
571 /* Virgin frame, calculate */
572 return (ULONG)&TrapFrame->HardwareEsp;
573 }
574 }
575 }
576
577 VOID
578 NTAPI
579 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
580 IN ULONG Esp)
581 {
582 ULONG Previous = KiEspFromTrapFrame(TrapFrame);
583
584 /* Check if this is user-mode or V86 */
585 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
586 {
587 /* Write it directly */
588 TrapFrame->HardwareEsp = Esp;
589 }
590 else
591 {
592 /* Don't allow ESP to be lowered, this is illegal */
593 if (Esp < Previous) KeBugCheck(SET_OF_INVALID_CONTEXT);
594
595 /* Create an edit frame, check if it was alrady */
596 if (!(TrapFrame->SegCs & FRAME_EDITED))
597 {
598 /* Update the value */
599 TrapFrame->TempEsp = Esp;
600 }
601 else
602 {
603 /* Check if ESP changed */
604 if (Previous != Esp)
605 {
606 /* Save CS */
607 TrapFrame->TempSegCs = TrapFrame->SegCs;
608 TrapFrame->SegCs &= ~FRAME_EDITED;
609
610 /* Save ESP */
611 TrapFrame->TempEsp = Esp;
612 }
613 }
614 }
615 }
616
617 ULONG
618 NTAPI
619 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
620 {
621 /* If this was V86 Mode */
622 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
623 {
624 /* Just return it */
625 return TrapFrame->HardwareSegSs;
626 }
627 else if (TrapFrame->SegCs & MODE_MASK)
628 {
629 /* Usermode, return the User SS */
630 return TrapFrame->HardwareSegSs | RPL_MASK;
631 }
632 else
633 {
634 /* Kernel mode */
635 return KGDT_R0_DATA;
636 }
637 }
638
639 VOID
640 NTAPI
641 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
642 IN ULONG Ss)
643 {
644 /* Remove the high-bits */
645 Ss &= 0xFFFF;
646
647 /* If this was V86 Mode */
648 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
649 {
650 /* Just write it */
651 TrapFrame->HardwareSegSs = Ss;
652 }
653 else if (TrapFrame->SegCs & MODE_MASK)
654 {
655 /* Usermode, save the User SS */
656 TrapFrame->HardwareSegSs = Ss | RPL_MASK;
657 }
658 }
659
660 USHORT
661 NTAPI
662 KiTagWordFnsaveToFxsave(USHORT TagWord)
663 {
664 INT FxTagWord = ~TagWord;
665
666 /*
667 * Empty is now 00, any 2 bits containing 1 mean valid
668 * Now convert the rest (11->0 and the rest to 1)
669 */
670 FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
671 FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
672 FxTagWord = (FxTagWord | (FxTagWord >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
673 FxTagWord = (FxTagWord | (FxTagWord >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
674 return FxTagWord;
675 }
676
677 VOID
678 NTAPI
679 KeContextToTrapFrame(IN PCONTEXT Context,
680 IN OUT PKEXCEPTION_FRAME ExceptionFrame,
681 IN OUT PKTRAP_FRAME TrapFrame,
682 IN ULONG ContextFlags,
683 IN KPROCESSOR_MODE PreviousMode)
684 {
685 PFX_SAVE_AREA FxSaveArea;
686 ULONG i;
687 BOOLEAN V86Switch = FALSE;
688 KIRQL OldIrql = APC_LEVEL;
689
690 /* Do this at APC_LEVEL */
691 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
692
693 /* Start with the basic Registers */
694 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
695 {
696 /* Check if we went through a V86 switch */
697 if ((Context->EFlags & EFLAGS_V86_MASK) !=
698 (TrapFrame->EFlags & EFLAGS_V86_MASK))
699 {
700 /* We did, remember this for later */
701 V86Switch = TRUE;
702 }
703
704 /* Copy EFLAGS. FIXME: Needs to be sanitized */
705 TrapFrame->EFlags = Context->EFlags;
706
707 /* Copy EBP and EIP */
708 TrapFrame->Ebp = Context->Ebp;
709 TrapFrame->Eip = Context->Eip;
710
711 /* Check if we were in V86 Mode */
712 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
713 {
714 /* Simply copy the CS value */
715 TrapFrame->SegCs = Context->SegCs;
716 }
717 else
718 {
719 /* We weren't in V86, so sanitize the CS (FIXME!) */
720 TrapFrame->SegCs = Context->SegCs;
721
722 /* Don't let it under 8, that's invalid */
723 if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
724 {
725 /* Force it to User CS */
726 TrapFrame->SegCs = (KGDT_R3_CODE | RPL_MASK);
727 }
728 }
729
730 /* Handle SS Specially for validation */
731 KiSsToTrapFrame(TrapFrame, Context->SegSs);
732
733 /* Write ESP back; take into account Edited Trap Frames */
734 KiEspToTrapFrame(TrapFrame, Context->Esp);
735
736 /* Handle our V86 Bias if we went through a switch */
737 if (V86Switch) Ki386AdjustEsp0(TrapFrame);
738 }
739
740 /* Process the Integer Registers */
741 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
742 {
743 /* Copy them manually */
744 TrapFrame->Eax = Context->Eax;
745 TrapFrame->Ebx = Context->Ebx;
746 TrapFrame->Ecx = Context->Ecx;
747 TrapFrame->Edx = Context->Edx;
748 TrapFrame->Esi = Context->Esi;
749 TrapFrame->Edi = Context->Edi;
750 }
751
752 /* Process the Context Segments */
753 if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
754 {
755 /* Check if we were in V86 Mode */
756 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
757 {
758 /* Copy the V86 Segments directlry */
759 TrapFrame->V86Ds = Context->SegDs;
760 TrapFrame->V86Es = Context->SegEs;
761 TrapFrame->V86Fs = Context->SegFs;
762 TrapFrame->V86Gs = Context->SegGs;
763 }
764 else if (!(TrapFrame->SegCs & MODE_MASK))
765 {
766 /* For kernel mode, write the standard values */
767 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
768 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
769 TrapFrame->SegFs = Context->SegFs;
770 TrapFrame->SegGs = 0;
771 }
772 else
773 {
774 /* For user mode, return the values directlry */
775 TrapFrame->SegDs = Context->SegDs;
776 TrapFrame->SegEs = Context->SegEs;
777 TrapFrame->SegFs = Context->SegFs;
778
779 /* Handle GS specially */
780 if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
781 {
782 /* Don't use it, if user */
783 TrapFrame->SegGs = 0;
784 }
785 else
786 {
787 /* Copy it if kernel */
788 TrapFrame->SegGs = Context->SegGs;
789 }
790 }
791 }
792
793 /* Handle the extended registers */
794 if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
795 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
796 {
797 /* Get the FX Area */
798 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
799
800 /* Check if NPX is present */
801 if (KeI386NpxPresent)
802 {
803 /* Flush the NPX State */
804 KiFlushNPXState(NULL);
805
806 /* Copy the FX State */
807 RtlCopyMemory(&FxSaveArea->U.FxArea,
808 &Context->ExtendedRegisters[0],
809 MAXIMUM_SUPPORTED_EXTENSION);
810
811 /* Remove reserved bits from MXCSR */
812 FxSaveArea->U.FxArea.MXCsr &= ~0xFFBF;
813
814 /* Mask out any invalid flags */
815 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
816
817 /* FIXME: Check if this is a VDM app */
818 }
819 }
820
821 /* Handle the floating point state */
822 if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
823 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
824 {
825 /* Get the FX Area */
826 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
827
828 /* Check if NPX is present */
829 if (KeI386NpxPresent)
830 {
831 /* Flush the NPX State */
832 KiFlushNPXState(NULL);
833
834 /* Check if we have Fxsr support */
835 if (KeI386FxsrPresent)
836 {
837 /* Convert the Fn Floating Point state to Fx */
838 FxSaveArea->U.FxArea.ControlWord =
839 (USHORT)Context->FloatSave.ControlWord;
840 FxSaveArea->U.FxArea.StatusWord =
841 (USHORT)Context->FloatSave.StatusWord;
842 FxSaveArea->U.FxArea.TagWord =
843 KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord);
844 FxSaveArea->U.FxArea.ErrorOpcode =
845 (USHORT)((Context->FloatSave.ErrorSelector >> 16) & 0xFFFF);
846 FxSaveArea->U.FxArea.ErrorOffset =
847 Context->FloatSave.ErrorOffset;
848 FxSaveArea->U.FxArea.ErrorSelector =
849 Context->FloatSave.ErrorSelector & 0xFFFF;
850 FxSaveArea->U.FxArea.DataOffset =
851 Context->FloatSave.DataOffset;
852 FxSaveArea->U.FxArea.DataSelector =
853 Context->FloatSave.DataSelector;
854
855 /* Clear out the Register Area */
856 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0],
857 SIZE_OF_FX_REGISTERS);
858
859 /* Loop the 8 floating point registers */
860 for (i = 0; i < 8; i++)
861 {
862 /* Copy from Fn to Fx */
863 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
864 Context->FloatSave.RegisterArea + (i * 10),
865 10);
866 }
867 }
868 else
869 {
870 /* Just dump the Fn state in */
871 RtlCopyMemory(&FxSaveArea->U.FnArea,
872 &Context->FloatSave,
873 sizeof(FNSAVE_FORMAT));
874 }
875
876 /* Mask out any invalid flags */
877 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
878
879 /* FIXME: Check if this is a VDM app */
880 }
881 else
882 {
883 /* FIXME: Handle FPU Emulation */
884 ASSERT(FALSE);
885 }
886 }
887
888 /* Handle the Debug Registers */
889 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
890 {
891 /* FIXME: All these should be sanitized */
892 TrapFrame->Dr0 = Context->Dr0;
893 TrapFrame->Dr1 = Context->Dr1;
894 TrapFrame->Dr2 = Context->Dr2;
895 TrapFrame->Dr3 = Context->Dr3;
896 TrapFrame->Dr6 = Context->Dr6;
897 TrapFrame->Dr7 = Context->Dr7;
898
899 /* Check if usermode */
900 if (PreviousMode != KernelMode)
901 {
902 /* Set the Debug Flag */
903 KeGetCurrentThread()->DispatcherHeader.DebugActive =
904 (Context->Dr7 & DR7_ACTIVE);
905 }
906 }
907
908 /* Restore IRQL */
909 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
910 }
911
912 VOID
913 NTAPI
914 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
915 IN PKEXCEPTION_FRAME ExceptionFrame,
916 IN OUT PCONTEXT Context)
917 {
918 PFX_SAVE_AREA FxSaveArea;
919 struct _AlignHack
920 {
921 UCHAR Hack[15];
922 FLOATING_SAVE_AREA UnalignedArea;
923 } FloatSaveBuffer;
924 FLOATING_SAVE_AREA *FloatSaveArea;
925 KIRQL OldIrql = APC_LEVEL;
926
927 /* Do this at APC_LEVEL */
928 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
929
930 /* Start with the Control flags */
931 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
932 {
933 /* EBP, EIP and EFLAGS */
934 Context->Ebp = TrapFrame->Ebp;
935 Context->Eip = TrapFrame->Eip;
936 Context->EFlags = TrapFrame->EFlags;
937
938 /* Return the correct CS */
939 if (!(TrapFrame->SegCs & FRAME_EDITED) &&
940 !(TrapFrame->EFlags & EFLAGS_V86_MASK))
941 {
942 /* Get it from the Temp location */
943 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
944 }
945 else
946 {
947 /* Return it directly */
948 Context->SegCs = TrapFrame->SegCs & 0xFFFF;
949 }
950
951 /* Get the Ss and ESP */
952 Context->SegSs = KiSsFromTrapFrame(TrapFrame);
953 Context->Esp = KiEspFromTrapFrame(TrapFrame);
954 }
955
956 /* Handle the Segments */
957 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
958 {
959 /* Do V86 Mode first */
960 if (TrapFrame->EFlags & EFLAGS_V86_MASK)
961 {
962 /* Return from the V86 location */
963 Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
964 Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
965 Context->SegEs = TrapFrame->V86Es & 0xFFFF;
966 Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
967 }
968 else
969 {
970 /* Check if this was a Kernel Trap */
971 if (TrapFrame->SegCs == KGDT_R0_CODE)
972 {
973 /* Set valid selectors */
974 TrapFrame->SegGs = 0;
975 TrapFrame->SegFs = KGDT_R0_PCR;
976 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
977 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
978 }
979
980 /* Return the segments */
981 Context->SegGs = TrapFrame->SegGs & 0xFFFF;
982 Context->SegFs = TrapFrame->SegFs & 0xFFFF;
983 Context->SegEs = TrapFrame->SegEs & 0xFFFF;
984 Context->SegDs = TrapFrame->SegDs & 0xFFFF;
985 }
986 }
987
988 /* Handle the simple registers */
989 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
990 {
991 /* Return them directly */
992 Context->Eax = TrapFrame->Eax;
993 Context->Ebx = TrapFrame->Ebx;
994 Context->Ecx = TrapFrame->Ecx;
995 Context->Edx = TrapFrame->Edx;
996 Context->Esi = TrapFrame->Esi;
997 Context->Edi = TrapFrame->Edi;
998 }
999
1000 /* Handle extended registers */
1001 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
1002 CONTEXT_EXTENDED_REGISTERS) && (TrapFrame->SegCs & MODE_MASK))
1003 {
1004 /* Get the FX Save Area */
1005 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
1006
1007 /* Make sure NPX is present */
1008 if (KeI386NpxPresent)
1009 {
1010 /* Flush the NPX State */
1011 KiFlushNPXState(NULL);
1012
1013 /* Copy the registers */
1014 RtlCopyMemory(&Context->ExtendedRegisters[0],
1015 &FxSaveArea->U.FxArea,
1016 MAXIMUM_SUPPORTED_EXTENSION);
1017 }
1018 }
1019
1020 /* Handle Floating Point */
1021 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
1022 CONTEXT_FLOATING_POINT) && (TrapFrame->SegCs & MODE_MASK))
1023 {
1024 /* Get the FX Save Area */
1025 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
1026
1027 /* Make sure we have an NPX */
1028 if (KeI386NpxPresent)
1029 {
1030 /* Check if we have Fxsr support */
1031 if (KeI386FxsrPresent)
1032 {
1033 /* Align the floating area to 16-bytes */
1034 FloatSaveArea = (FLOATING_SAVE_AREA*)
1035 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
1036
1037 /* Get the State */
1038 KiFlushNPXState(FloatSaveArea);
1039 }
1040 else
1041 {
1042 /* We don't, use the FN area and flush the NPX State */
1043 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
1044 KiFlushNPXState(NULL);
1045 }
1046
1047 /* Copy into the Context */
1048 RtlCopyMemory(&Context->FloatSave,
1049 FloatSaveArea,
1050 sizeof(FNSAVE_FORMAT));
1051 }
1052 else
1053 {
1054 /* FIXME: Handle Emulation */
1055 ASSERT(FALSE);
1056 }
1057 }
1058
1059 /* Handle debug registers */
1060 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
1061 CONTEXT_DEBUG_REGISTERS)
1062 {
1063 /* Copy the debug registers */
1064 Context->Dr0 = TrapFrame->Dr0;
1065 Context->Dr1 = TrapFrame->Dr1;
1066 Context->Dr2 = TrapFrame->Dr2;
1067 Context->Dr3 = TrapFrame->Dr3;
1068 Context->Dr6 = TrapFrame->Dr6;
1069
1070 /* For user-mode, only set DR7 if a debugger is active */
1071 if (((TrapFrame->SegCs & MODE_MASK) ||
1072 (TrapFrame->EFlags & EFLAGS_V86_MASK)) &&
1073 (KeGetCurrentThread()->DispatcherHeader.DebugActive))
1074 {
1075 /* Copy it over */
1076 Context->Dr7 = TrapFrame->Dr7;
1077 }
1078 else
1079 {
1080 /* Clear it */
1081 Context->Dr7 = 0;
1082 }
1083 }
1084
1085 /* Restore IRQL */
1086 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
1087 }
1088
1089 VOID
1090 NTAPI
1091 KeDumpStackFrames(PULONG Frame)
1092 {
1093 PULONG StackBase, StackEnd;
1094 MEMORY_BASIC_INFORMATION mbi;
1095 ULONG ResultLength = sizeof(mbi);
1096 NTSTATUS Status;
1097
1098 DbgPrint("Frames:\n");
1099 _SEH_TRY
1100 {
1101 Status = MiQueryVirtualMemory (
1102 (HANDLE)-1,
1103 Frame,
1104 MemoryBasicInformation,
1105 &mbi,
1106 sizeof(mbi),
1107 &ResultLength );
1108 if ( !NT_SUCCESS(Status) )
1109 {
1110 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1111 return;
1112 }
1113
1114 StackBase = Frame;
1115 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1116
1117 while ( Frame >= StackBase && Frame < StackEnd )
1118 {
1119 ULONG Addr = Frame[1];
1120 if (!KeRosPrintAddress((PVOID)Addr))
1121 DbgPrint("<%X>", Addr);
1122 if ( Addr == 0 || Addr == 0xDEADBEEF )
1123 break;
1124 StackBase = Frame;
1125 Frame = (PULONG)Frame[0];
1126 DbgPrint("\n");
1127 }
1128 }
1129 _SEH_HANDLE
1130 {
1131 }
1132 _SEH_END;
1133 DbgPrint("\n");
1134 }
1135
1136 VOID STDCALL
1137 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
1138 {
1139 ULONG i=0;
1140 PULONG StackBase, StackEnd;
1141 MEMORY_BASIC_INFORMATION mbi;
1142 ULONG ResultLength = sizeof(mbi);
1143 NTSTATUS Status;
1144
1145 DbgPrint("Frames: ");
1146 _SEH_TRY
1147 {
1148 if ( !Frame )
1149 {
1150 #if defined __GNUC__
1151 __asm__("mov %%ebp, %0" : "=r" (Frame) : );
1152 #elif defined(_MSC_VER)
1153 __asm mov [Frame], ebp
1154 #endif
1155 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
1156 }
1157
1158 Status = MiQueryVirtualMemory (
1159 (HANDLE)-1,
1160 Frame,
1161 MemoryBasicInformation,
1162 &mbi,
1163 sizeof(mbi),
1164 &ResultLength );
1165 if ( !NT_SUCCESS(Status) )
1166 {
1167 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1168 return;
1169 }
1170
1171 StackBase = Frame;
1172 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1173
1174 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
1175 {
1176 ULONG Addr = Frame[1];
1177 if (!KeRosPrintAddress((PVOID)Addr))
1178 DbgPrint("<%X>", Addr);
1179 if ( Addr == 0 || Addr == 0xDEADBEEF )
1180 break;
1181 StackBase = Frame;
1182 Frame = (PULONG)Frame[0];
1183 DbgPrint(" ");
1184 }
1185 }
1186 _SEH_HANDLE
1187 {
1188 }
1189 _SEH_END;
1190 DbgPrint("\n");
1191 }
1192
1193 ULONG STDCALL
1194 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
1195 {
1196 ULONG Count = 0;
1197 PULONG StackBase, StackEnd, Frame;
1198 MEMORY_BASIC_INFORMATION mbi;
1199 ULONG ResultLength = sizeof(mbi);
1200 NTSTATUS Status;
1201
1202 _SEH_TRY
1203 {
1204 #if defined __GNUC__
1205 __asm__("mov %%ebp, %0" : "=r" (Frame) : );
1206 #elif defined(_MSC_VER)
1207 __asm mov [Frame], ebp
1208 #endif
1209
1210 Status = MiQueryVirtualMemory (
1211 (HANDLE)-1,
1212 Frame,
1213 MemoryBasicInformation,
1214 &mbi,
1215 sizeof(mbi),
1216 &ResultLength );
1217 if ( !NT_SUCCESS(Status) )
1218 {
1219 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1220 return 0;
1221 }
1222
1223 StackBase = Frame;
1224 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1225
1226 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
1227 {
1228 Frames[Count++] = Frame[1];
1229 StackBase = Frame;
1230 Frame = (PULONG)Frame[0];
1231 }
1232 }
1233 _SEH_HANDLE
1234 {
1235 }
1236 _SEH_END;
1237 return Count;
1238 }
1239
1240 VOID
1241 INIT_FUNCTION
1242 NTAPI
1243 KeInitExceptions(VOID)
1244 {
1245 ULONG i;
1246 USHORT FlippedSelector;
1247
1248 /* Loop the IDT */
1249 for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
1250 {
1251 /* Save the current Selector */
1252 FlippedSelector = KiIdt[i].Selector;
1253
1254 /* Flip Selector and Extended Offset */
1255 KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
1256 KiIdt[i].ExtendedOffset = FlippedSelector;
1257 }
1258 }
1259
1260 VOID
1261 NTAPI
1262 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
1263 PKEXCEPTION_FRAME ExceptionFrame,
1264 PKTRAP_FRAME TrapFrame,
1265 KPROCESSOR_MODE PreviousMode,
1266 BOOLEAN FirstChance)
1267 {
1268 CONTEXT Context;
1269 KD_CONTINUE_TYPE Action;
1270 ULONG_PTR Stack, NewStack;
1271 ULONG Size;
1272 BOOLEAN UserDispatch = FALSE;
1273 DPRINT("KiDispatchException() called\n");
1274
1275 /* Increase number of Exception Dispatches */
1276 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
1277
1278 /* Set the context flags */
1279 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
1280
1281 /* Check if User Mode */
1282 if (PreviousMode == UserMode)
1283 {
1284 /* Add the FPU Flag */
1285 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
1286 if (KeI386FxsrPresent) Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
1287 }
1288
1289 /* Get a Context */
1290 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
1291
1292 /* Handle kernel-mode first, it's simpler */
1293 if (PreviousMode == KernelMode)
1294 {
1295 /* Check if this is a first-chance exception */
1296 if (FirstChance == TRUE)
1297 {
1298 /* Break into the debugger for the first time */
1299 Action = KdpEnterDebuggerException(ExceptionRecord,
1300 PreviousMode,
1301 &Context,
1302 TrapFrame,
1303 TRUE,
1304 TRUE);
1305
1306 /* If the debugger said continue, then continue */
1307 if (Action == kdContinue) goto Handled;
1308
1309 /* If the Debugger couldn't handle it, dispatch the exception */
1310 if (RtlDispatchException(ExceptionRecord, &Context))
1311 {
1312 /* It was handled by an exception handler, continue */
1313 goto Handled;
1314 }
1315 }
1316
1317 /* This is a second-chance exception, only for the debugger */
1318 Action = KdpEnterDebuggerException(ExceptionRecord,
1319 PreviousMode,
1320 &Context,
1321 TrapFrame,
1322 FALSE,
1323 FALSE);
1324
1325 /* If the debugger said continue, then continue */
1326 if (Action == kdContinue) goto Handled;
1327
1328 /* Third strike; you're out */
1329 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
1330 ExceptionRecord->ExceptionCode,
1331 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1332 ExceptionRecord->ExceptionInformation[0],
1333 ExceptionRecord->ExceptionInformation[1],
1334 TrapFrame);
1335 }
1336 else
1337 {
1338 /* User mode exception, was it first-chance? */
1339 if (FirstChance)
1340 {
1341 /* Enter Debugger if available */
1342 Action = KdpEnterDebuggerException(ExceptionRecord,
1343 PreviousMode,
1344 &Context,
1345 TrapFrame,
1346 TRUE,
1347 TRUE);
1348
1349 /* Exit if we're continuing */
1350 if (Action == kdContinue) goto Handled;
1351
1352 /* FIXME: Forward exception to user mode debugger */
1353
1354 /* Set up the user-stack */
1355 _SEH_TRY
1356 {
1357 /* Align context size and get stack pointer */
1358 Size = (sizeof(CONTEXT) + 3) & ~3;
1359 Stack = (Context.Esp & ~3) - Size;
1360 DPRINT("Stack: %lx\n", Stack);
1361
1362 /* Probe stack and copy Context */
1363 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
1364 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
1365
1366 /* Align exception record size and get stack pointer */
1367 Size = (sizeof(EXCEPTION_RECORD) -
1368 (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) *
1369 sizeof(ULONG) + 3) & ~3;
1370 NewStack = Stack - Size;
1371 DPRINT("NewStack: %lx\n", NewStack);
1372
1373 /* Probe stack and copy exception record. Don't forget to add the two params */
1374 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
1375 Size + 2 * sizeof(ULONG_PTR),
1376 sizeof(ULONG));
1377 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
1378
1379 /* Now write the two params for the user-mode dispatcher */
1380 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
1381 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
1382
1383 /* Set new Stack Pointer */
1384 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
1385
1386 /* Set EIP to the User-mode Dispathcer */
1387 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
1388 UserDispatch = TRUE;
1389 _SEH_LEAVE;
1390 }
1391 _SEH_HANDLE
1392 {
1393 /* Do second-chance */
1394 }
1395 _SEH_END;
1396 }
1397
1398 /* If we dispatch to user, return now */
1399 if (UserDispatch) return;
1400
1401 /* FIXME: Forward the exception to the debugger for 2nd chance */
1402
1403 /* 3rd strike, kill the thread */
1404 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1405 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
1406 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
1407 ExceptionRecord->ExceptionCode,
1408 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1409 ExceptionRecord->ExceptionInformation[0],
1410 ExceptionRecord->ExceptionInformation[1],
1411 TrapFrame);
1412 }
1413
1414 Handled:
1415 /* Convert the context back into Trap/Exception Frames */
1416 KeContextToTrapFrame(&Context,
1417 NULL,
1418 TrapFrame,
1419 Context.ContextFlags,
1420 PreviousMode);
1421 return;
1422 }
1423
1424 /*
1425 * @implemented
1426 */
1427 NTSTATUS
1428 NTAPI
1429 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1430 {
1431 ULONG OldEip;
1432 PKTHREAD Thread = KeGetCurrentThread();
1433
1434 /* Make sure we can access the TEB */
1435 _SEH_TRY
1436 {
1437 Thread->Teb->ExceptionCode = ExceptionCode;
1438 }
1439 _SEH_HANDLE
1440 {
1441 return(ExceptionCode);
1442 }
1443 _SEH_END;
1444
1445 /* Get the old EIP */
1446 OldEip = Thread->TrapFrame->Eip;
1447
1448 /* Change it to the user-mode dispatcher */
1449 Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1450
1451 /* Return the old EIP */
1452 return((NTSTATUS)OldEip);
1453 }
1454