- Detect NPX/FPU in simple assembly and XMMI/SSE2 by using CPU Feature flags, replaci...
[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 if (PsGetCurrentThread() != NULL &&
503 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
504 {
505 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
506 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit, Tf->Eip);
507 ExceptionNr = 12;
508 }
509
510 if (ExceptionNr == 15)
511 {
512 /*
513 * FIXME:
514 * This exception should never occur. The P6 has a bug, which does sometimes deliver
515 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
516 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
517 * sources. Linux does ignore this exception.
518 *
519 */
520 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
521 return(0);
522 }
523
524 /*
525 * Check for a breakpoint that was only for the attention of the debugger.
526 */
527 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
528 {
529 /*
530 EIP is already adjusted by the processor to point to the instruction
531 after the breakpoint.
532 */
533 return(0);
534 }
535
536 /*
537 * Handle user exceptions differently
538 */
539 if ((Tf->SegCs & 0xFFFF) == (KGDT_R3_CODE | RPL_MASK))
540 {
541 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
542 }
543 else
544 {
545 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
546 }
547 }
548
549 ULONG
550 NTAPI
551 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
552 {
553 /* Check if this is user-mode or V86 */
554 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & X86_EFLAGS_VM))
555 {
556 /* Return it directly */
557 return TrapFrame->HardwareEsp;
558 }
559 else
560 {
561 /* Edited frame */
562 if (!(TrapFrame->SegCs & FRAME_EDITED))
563 {
564 /* Return edited value */
565 return TrapFrame->TempEsp;
566 }
567 else
568 {
569 /* Virgin frame, calculate */
570 return (ULONG)&TrapFrame->HardwareEsp;
571 }
572 }
573 }
574
575 VOID
576 NTAPI
577 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame,
578 IN ULONG Esp)
579 {
580 ULONG Previous = KiEspFromTrapFrame(TrapFrame);
581
582 /* Check if this is user-mode or V86 */
583 if ((TrapFrame->SegCs & MODE_MASK) || (TrapFrame->EFlags & X86_EFLAGS_VM))
584 {
585 /* Write it directly */
586 TrapFrame->HardwareEsp = Esp;
587 }
588 else
589 {
590 /* Don't allow ESP to be lowered, this is illegal */
591 if (Esp < Previous)
592 {
593 KeBugCheck(SET_OF_INVALID_CONTEXT);
594 }
595
596 /* Create an edit frame, check if it was alrady */
597 if (!(TrapFrame->SegCs & FRAME_EDITED))
598 {
599 /* Update the value */
600 TrapFrame->TempEsp = Esp;
601 }
602 else
603 {
604 /* Check if ESP changed */
605 if (Previous != Esp)
606 {
607 /* Save CS */
608 TrapFrame->TempSegCs = TrapFrame->SegCs;
609 TrapFrame->SegCs &= ~FRAME_EDITED;
610
611 /* Save ESP */
612 TrapFrame->TempEsp = Esp;
613 }
614 }
615 }
616 }
617
618 ULONG
619 NTAPI
620 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame)
621 {
622 /* If this was V86 Mode */
623 if (TrapFrame->EFlags & X86_EFLAGS_VM)
624 {
625 /* Just return it */
626 return TrapFrame->HardwareSegSs;
627 }
628 else if (TrapFrame->SegCs & MODE_MASK)
629 {
630 /* Usermode, return the User SS */
631 return TrapFrame->HardwareSegSs | RPL_MASK;
632 }
633 else
634 {
635 /* Kernel mode */
636 return KGDT_R0_DATA;
637 }
638 }
639
640 VOID
641 NTAPI
642 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame,
643 IN ULONG Ss)
644 {
645 /* Remove the high-bits */
646 Ss &= 0xFFFF;
647
648 /* If this was V86 Mode */
649 if (TrapFrame->EFlags & X86_EFLAGS_VM)
650 {
651 /* Just write it */
652 TrapFrame->HardwareSegSs = Ss;
653 }
654 else if (TrapFrame->SegCs & MODE_MASK)
655 {
656 /* Usermode, save the User SS */
657 TrapFrame->HardwareSegSs = Ss | RPL_MASK;
658 }
659 }
660
661 USHORT
662 NTAPI
663 KiTagWordFnsaveToFxsave(USHORT TagWord)
664 {
665 INT FxTagWord = ~TagWord;
666
667 /*
668 * Empty is now 00, any 2 bits containing 1 mean valid
669 * Now convert the rest (11->0 and the rest to 1)
670 */
671 FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */
672 FxTagWord = (FxTagWord | (FxTagWord >> 1)) & 0x3333; /* 00VV00VV00VV00VV */
673 FxTagWord = (FxTagWord | (FxTagWord >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */
674 FxTagWord = (FxTagWord | (FxTagWord >> 4)) & 0x00ff; /* 00000000VVVVVVVV */
675 return FxTagWord;
676 }
677
678 VOID
679 NTAPI
680 KeContextToTrapFrame(IN PCONTEXT Context,
681 IN OUT PKEXCEPTION_FRAME ExceptionFrame,
682 IN OUT PKTRAP_FRAME TrapFrame,
683 IN ULONG ContextFlags,
684 IN KPROCESSOR_MODE PreviousMode)
685 {
686 PFX_SAVE_AREA FxSaveArea;
687 ULONG i;
688 BOOLEAN V86Switch = FALSE;
689
690 /* Start with the basic Registers */
691 if ((ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
692 {
693 /* Check if we went through a V86 switch */
694 if ((Context->EFlags & X86_EFLAGS_VM) !=
695 (TrapFrame->EFlags & X86_EFLAGS_VM))
696 {
697 /* We did, remember this for later */
698 V86Switch = TRUE;
699 }
700
701 /* Copy EFLAGS. FIXME: Needs to be sanitized */
702 TrapFrame->EFlags = Context->EFlags;
703
704 /* Copy EBP and EIP */
705 TrapFrame->Ebp = Context->Ebp;
706 TrapFrame->Eip = Context->Eip;
707
708 /* Check if we were in V86 Mode */
709 if (TrapFrame->EFlags & X86_EFLAGS_VM)
710 {
711 /* Simply copy the CS value */
712 TrapFrame->SegCs = Context->SegCs;
713 }
714 else
715 {
716 /* We weren't in V86, so sanitize the CS (FIXME!) */
717 TrapFrame->SegCs = Context->SegCs;
718
719 /* Don't let it under 8, that's invalid */
720 if ((PreviousMode != KernelMode) && (TrapFrame->SegCs < 8))
721 {
722 /* Force it to User CS */
723 TrapFrame->SegCs = (KGDT_R3_CODE | RPL_MASK);
724 }
725 }
726
727 /* Handle SS Specially for validation */
728 KiSsToTrapFrame(TrapFrame, Context->SegSs);
729
730 /* Write ESP back; take into account Edited Trap Frames */
731 KiEspToTrapFrame(TrapFrame, Context->Esp);
732
733 /* Handle our V86 Bias if we went through a switch */
734 if (V86Switch) Ki386AdjustEsp0(TrapFrame);
735 }
736
737 /* Process the Integer Registers */
738 if ((ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
739 {
740 TrapFrame->Eax = Context->Eax;
741 TrapFrame->Ebx = Context->Ebx;
742 TrapFrame->Ecx = Context->Ecx;
743 TrapFrame->Edx = Context->Edx;
744 TrapFrame->Esi = Context->Esi;
745 TrapFrame->Edi = Context->Edi;
746 }
747
748 /* Process the Context Segments */
749 if ((ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
750 {
751 /* Check if we were in V86 Mode */
752 if (TrapFrame->EFlags & X86_EFLAGS_VM)
753 {
754 /* Copy the V86 Segments directlry */
755 TrapFrame->V86Ds = Context->SegDs;
756 TrapFrame->V86Es = Context->SegEs;
757 TrapFrame->V86Fs = Context->SegFs;
758 TrapFrame->V86Gs = Context->SegGs;
759 }
760 else if (!(TrapFrame->SegCs & MODE_MASK))
761 {
762 /* For kernel mode, write the standard values */
763 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
764 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
765 TrapFrame->SegFs = Context->SegFs;
766 TrapFrame->SegGs = 0;
767 }
768 else
769 {
770 /* For user mode, return the values directlry */
771 TrapFrame->SegDs = Context->SegDs;
772 TrapFrame->SegEs = Context->SegEs;
773 TrapFrame->SegFs = Context->SegFs;
774
775 /* Handle GS specially */
776 if (TrapFrame->SegCs == (KGDT_R3_CODE | RPL_MASK))
777 {
778 /* Don't use it, if user */
779 TrapFrame->SegGs = 0;
780 }
781 else
782 {
783 /* Copy it if kernel */
784 TrapFrame->SegGs = Context->SegGs;
785 }
786 }
787 }
788
789 /* Handle the extended registers */
790 if (((ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
791 CONTEXT_EXTENDED_REGISTERS) &&
792 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
793 {
794 /* Get the FX Area */
795 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
796
797 /* Check if NPX is present */
798 if (KeI386NpxPresent)
799 {
800 /* Flush the NPX State */
801 KiFlushNPXState(NULL);
802
803 /* Copy the FX State */
804 RtlCopyMemory(&FxSaveArea->U.FxArea,
805 &Context->ExtendedRegisters[0],
806 MAXIMUM_SUPPORTED_EXTENSION);
807
808 /* Remove reserved bits from MXCSR */
809 FxSaveArea->U.FxArea.MXCsr &= ~0xFFBF;
810
811 /* Mask out any invalid flags */
812 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
813
814 /* FIXME: Check if this is a VDM app */
815 }
816 }
817
818 /* Handle the floating point state */
819 if (((ContextFlags & CONTEXT_FLOATING_POINT) ==
820 CONTEXT_FLOATING_POINT) &&
821 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
822 {
823 /* Get the FX Area */
824 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
825
826 /* Check if NPX is present */
827 if (KeI386NpxPresent)
828 {
829 /* Flush the NPX State */
830 KiFlushNPXState(NULL);
831
832 /* Check if we have Fxsr support */
833 if (KeI386FxsrPresent)
834 {
835 /* Convert the Fn Floating Point state to Fx */
836 FxSaveArea->U.FxArea.ControlWord =
837 (USHORT)Context->FloatSave.ControlWord;
838 FxSaveArea->U.FxArea.StatusWord =
839 (USHORT)Context->FloatSave.StatusWord;
840 FxSaveArea->U.FxArea.TagWord =
841 KiTagWordFnsaveToFxsave((USHORT)Context->FloatSave.TagWord);
842 FxSaveArea->U.FxArea.ErrorOpcode =
843 (USHORT)(Context->FloatSave.ErrorSelector >> 16);
844 FxSaveArea->U.FxArea.ErrorOffset =
845 Context->FloatSave.ErrorOffset;
846 FxSaveArea->U.FxArea.ErrorSelector =
847 Context->FloatSave.ErrorSelector & 0xFFFF;
848 FxSaveArea->U.FxArea.DataOffset =
849 Context->FloatSave.DataOffset;
850 FxSaveArea->U.FxArea.DataSelector =
851 Context->FloatSave.DataSelector & 0xFFFF;
852
853 /* Clear out the Register Area */
854 RtlZeroMemory(&FxSaveArea->U.FxArea.RegisterArea[0], SIZE_OF_FX_REGISTERS);
855
856 /* Loop the 8 floating point registers */
857 for (i = 0; i < 8; i++)
858 {
859 /* Copy from Fn to Fx */
860 RtlCopyMemory(FxSaveArea->U.FxArea.RegisterArea + (i * 16),
861 Context->FloatSave.RegisterArea + (i * 10),
862 10);
863 }
864 }
865 else
866 {
867 /* Just dump the Fn state in */
868 RtlCopyMemory(&FxSaveArea->U.FnArea,
869 &Context->FloatSave,
870 sizeof(FNSAVE_FORMAT));
871 }
872
873 /* Mask out any invalid flags */
874 FxSaveArea->Cr0NpxState &= ~(CR0_EM | CR0_MP | CR0_TS);
875
876 /* FIXME: Check if this is a VDM app */
877 }
878 else
879 {
880 /* FIXME: Handle FPU Emulation */
881 }
882 }
883
884 /* Handle the Debug Registers */
885 if ((ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
886 {
887 /* FIXME: All these should be sanitized */
888 TrapFrame->Dr0 = Context->Dr0;
889 TrapFrame->Dr1 = Context->Dr1;
890 TrapFrame->Dr2 = Context->Dr2;
891 TrapFrame->Dr3 = Context->Dr3;
892 TrapFrame->Dr6 = Context->Dr6;
893 TrapFrame->Dr7 = Context->Dr7;
894
895 /* Check if usermode */
896 if (PreviousMode != KernelMode)
897 {
898 /* Set the Debug Flag */
899 KeGetCurrentThread()->DispatcherHeader.DebugActive =
900 (Context->Dr7 & DR7_ACTIVE);
901 }
902 }
903 }
904
905 VOID
906 NTAPI
907 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame,
908 IN PKEXCEPTION_FRAME ExceptionFrame,
909 IN OUT PCONTEXT Context)
910 {
911 PFX_SAVE_AREA FxSaveArea;
912 struct _AlignHack
913 {
914 UCHAR Hack[15];
915 FLOATING_SAVE_AREA UnalignedArea;
916 } FloatSaveBuffer;
917 FLOATING_SAVE_AREA *FloatSaveArea;
918
919 /* Start with the Control flags */
920 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
921 {
922 /* EBP, EIP and EFLAGS */
923 Context->Ebp = TrapFrame->Ebp;
924 Context->Eip = TrapFrame->Eip;
925 Context->EFlags = TrapFrame->EFlags;
926
927 /* Return the correct CS */
928 if (!(TrapFrame->SegCs & FRAME_EDITED) &&
929 !(TrapFrame->EFlags & X86_EFLAGS_VM))
930 {
931 /* Get it from the Temp location */
932 Context->SegCs = TrapFrame->TempSegCs & 0xFFFF;
933 }
934 else
935 {
936 /* Return it directly */
937 Context->SegCs = TrapFrame->SegCs & 0xFFFF;
938 }
939
940 /* Get the Ss and ESP */
941 Context->SegSs = KiSsFromTrapFrame(TrapFrame);
942 Context->Esp = KiEspFromTrapFrame(TrapFrame);
943 }
944
945 /* Handle the Segments */
946 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
947 {
948 /* Do V86 Mode first */
949 if (TrapFrame->EFlags & X86_EFLAGS_VM)
950 {
951 /* Return from the V86 location */
952 Context->SegGs = TrapFrame->V86Gs & 0xFFFF;
953 Context->SegFs = TrapFrame->V86Fs & 0xFFFF;
954 Context->SegEs = TrapFrame->V86Es & 0xFFFF;
955 Context->SegDs = TrapFrame->V86Ds & 0xFFFF;
956 }
957 else
958 {
959 /* Check if this was a Kernel Trap */
960 if (TrapFrame->SegCs == KGDT_R0_CODE)
961 {
962 /* Set valid selectors */
963 TrapFrame->SegGs = 0;
964 TrapFrame->SegFs = KGDT_R0_PCR;
965 TrapFrame->SegEs = KGDT_R3_DATA | RPL_MASK;
966 TrapFrame->SegDs = KGDT_R3_DATA | RPL_MASK;
967 }
968
969 /* Return the segments */
970 Context->SegGs = TrapFrame->SegGs & 0xFFFF;
971 Context->SegFs = TrapFrame->SegFs & 0xFFFF;
972 Context->SegEs = TrapFrame->SegEs & 0xFFFF;
973 Context->SegDs = TrapFrame->SegDs & 0xFFFF;
974 }
975 }
976
977 /* Handle the simple registers */
978 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
979 {
980 /* Return them directly */
981 Context->Eax = TrapFrame->Eax;
982 Context->Ebx = TrapFrame->Ebx;
983 Context->Ecx = TrapFrame->Ecx;
984 Context->Edx = TrapFrame->Edx;
985 Context->Esi = TrapFrame->Esi;
986 Context->Edi = TrapFrame->Edi;
987 }
988
989 /* Handle extended registers */
990 if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
991 CONTEXT_EXTENDED_REGISTERS) &&
992 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
993 {
994 /* Get the FX Save Area */
995 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
996
997 /* Make sure NPX is present */
998 if (KeI386NpxPresent)
999 {
1000 /* Flush the NPX State */
1001 KiFlushNPXState(NULL);
1002
1003 /* Copy the registers */
1004 RtlCopyMemory(&Context->ExtendedRegisters[0],
1005 &FxSaveArea->U.FxArea,
1006 MAXIMUM_SUPPORTED_EXTENSION);
1007 }
1008 }
1009
1010 /* Handle Floating Point */
1011 if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
1012 CONTEXT_FLOATING_POINT) &&
1013 ((TrapFrame->SegCs & MODE_MASK) == UserMode))
1014 {
1015 /* Get the FX Save Area */
1016 FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);
1017
1018 /* Make sure we have an NPX */
1019 if (KeI386NpxPresent)
1020 {
1021 /* Check if we have Fxsr support */
1022 if (KeI386FxsrPresent)
1023 {
1024 /* Align the floating area to 16-bytes */
1025 FloatSaveArea = (FLOATING_SAVE_AREA*)
1026 ((ULONG_PTR)&FloatSaveBuffer.UnalignedArea &~ 0xF);
1027
1028 /* Get the State */
1029 KiFlushNPXState(FloatSaveArea);
1030 }
1031 else
1032 {
1033 /* We don't, use the FN area and flush the NPX State */
1034 FloatSaveArea = (FLOATING_SAVE_AREA*)&FxSaveArea->U.FnArea;
1035 KiFlushNPXState(NULL);
1036 }
1037
1038 /* Copy into the Context */
1039 RtlCopyMemory(&Context->FloatSave,
1040 &FxSaveArea->U.FnArea,
1041 sizeof(FNSAVE_FORMAT));
1042 }
1043 else
1044 {
1045 /* FIXME: Handle Emulation */
1046 Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
1047 }
1048 }
1049
1050 /* Handle debug registers */
1051 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
1052 CONTEXT_DEBUG_REGISTERS)
1053 {
1054 /* Copy the debug registers */
1055 Context->Dr0 = TrapFrame->Dr0;
1056 Context->Dr1 = TrapFrame->Dr1;
1057 Context->Dr2 = TrapFrame->Dr2;
1058 Context->Dr3 = TrapFrame->Dr3;
1059 Context->Dr6 = TrapFrame->Dr6;
1060
1061 /* For user-mode, only set DR7 if a debugger is active */
1062 if (((TrapFrame->SegCs & MODE_MASK) ||
1063 (TrapFrame->EFlags & EFLAGS_V86_MASK)) &&
1064 (KeGetCurrentThread()->DispatcherHeader.DebugActive))
1065 {
1066 /* Copy it over */
1067 Context->Dr7 = TrapFrame->Dr7;
1068 }
1069 else
1070 {
1071 /* Clear it */
1072 Context->Dr7 = 0;
1073 }
1074 }
1075 }
1076
1077 VOID
1078 NTAPI
1079 KeDumpStackFrames(PULONG Frame)
1080 {
1081 PULONG StackBase, StackEnd;
1082 MEMORY_BASIC_INFORMATION mbi;
1083 ULONG ResultLength = sizeof(mbi);
1084 NTSTATUS Status;
1085
1086 DbgPrint("Frames:\n");
1087 _SEH_TRY
1088 {
1089 Status = MiQueryVirtualMemory (
1090 (HANDLE)-1,
1091 Frame,
1092 MemoryBasicInformation,
1093 &mbi,
1094 sizeof(mbi),
1095 &ResultLength );
1096 if ( !NT_SUCCESS(Status) )
1097 {
1098 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1099 return;
1100 }
1101
1102 StackBase = Frame;
1103 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1104
1105 while ( Frame >= StackBase && Frame < StackEnd )
1106 {
1107 ULONG Addr = Frame[1];
1108 if (!KeRosPrintAddress((PVOID)Addr))
1109 DbgPrint("<%X>", Addr);
1110 if ( Addr == 0 || Addr == 0xDEADBEEF )
1111 break;
1112 StackBase = Frame;
1113 Frame = (PULONG)Frame[0];
1114 DbgPrint("\n");
1115 }
1116 }
1117 _SEH_HANDLE
1118 {
1119 }
1120 _SEH_END;
1121 DbgPrint("\n");
1122 }
1123
1124 VOID STDCALL
1125 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
1126 {
1127 ULONG i=0;
1128 PULONG StackBase, StackEnd;
1129 MEMORY_BASIC_INFORMATION mbi;
1130 ULONG ResultLength = sizeof(mbi);
1131 NTSTATUS Status;
1132
1133 DbgPrint("Frames: ");
1134 _SEH_TRY
1135 {
1136 if ( !Frame )
1137 {
1138 #if defined __GNUC__
1139 __asm__("mov %%ebp, %0" : "=r" (Frame) : );
1140 #elif defined(_MSC_VER)
1141 __asm mov [Frame], ebp
1142 #endif
1143 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
1144 }
1145
1146 Status = MiQueryVirtualMemory (
1147 (HANDLE)-1,
1148 Frame,
1149 MemoryBasicInformation,
1150 &mbi,
1151 sizeof(mbi),
1152 &ResultLength );
1153 if ( !NT_SUCCESS(Status) )
1154 {
1155 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1156 return;
1157 }
1158
1159 StackBase = Frame;
1160 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1161
1162 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
1163 {
1164 ULONG Addr = Frame[1];
1165 if (!KeRosPrintAddress((PVOID)Addr))
1166 DbgPrint("<%X>", Addr);
1167 if ( Addr == 0 || Addr == 0xDEADBEEF )
1168 break;
1169 StackBase = Frame;
1170 Frame = (PULONG)Frame[0];
1171 DbgPrint(" ");
1172 }
1173 }
1174 _SEH_HANDLE
1175 {
1176 }
1177 _SEH_END;
1178 DbgPrint("\n");
1179 }
1180
1181 ULONG STDCALL
1182 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
1183 {
1184 ULONG Count = 0;
1185 PULONG StackBase, StackEnd, Frame;
1186 MEMORY_BASIC_INFORMATION mbi;
1187 ULONG ResultLength = sizeof(mbi);
1188 NTSTATUS Status;
1189
1190 _SEH_TRY
1191 {
1192 #if defined __GNUC__
1193 __asm__("mov %%ebp, %0" : "=r" (Frame) : );
1194 #elif defined(_MSC_VER)
1195 __asm mov [Frame], ebp
1196 #endif
1197
1198 Status = MiQueryVirtualMemory (
1199 (HANDLE)-1,
1200 Frame,
1201 MemoryBasicInformation,
1202 &mbi,
1203 sizeof(mbi),
1204 &ResultLength );
1205 if ( !NT_SUCCESS(Status) )
1206 {
1207 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
1208 return 0;
1209 }
1210
1211 StackBase = Frame;
1212 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
1213
1214 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
1215 {
1216 Frames[Count++] = Frame[1];
1217 StackBase = Frame;
1218 Frame = (PULONG)Frame[0];
1219 }
1220 }
1221 _SEH_HANDLE
1222 {
1223 }
1224 _SEH_END;
1225 return Count;
1226 }
1227
1228 VOID
1229 INIT_FUNCTION
1230 NTAPI
1231 KeInitExceptions(VOID)
1232 {
1233 ULONG i;
1234 USHORT FlippedSelector;
1235
1236 /* Loop the IDT */
1237 for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
1238 {
1239 /* Save the current Selector */
1240 FlippedSelector = KiIdt[i].Selector;
1241
1242 /* Flip Selector and Extended Offset */
1243 KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
1244 KiIdt[i].ExtendedOffset = FlippedSelector;
1245 }
1246 }
1247
1248 VOID
1249 NTAPI
1250 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
1251 PKEXCEPTION_FRAME ExceptionFrame,
1252 PKTRAP_FRAME TrapFrame,
1253 KPROCESSOR_MODE PreviousMode,
1254 BOOLEAN FirstChance)
1255 {
1256 CONTEXT Context;
1257 KD_CONTINUE_TYPE Action;
1258 ULONG_PTR Stack, NewStack;
1259 ULONG Size;
1260 BOOLEAN UserDispatch = FALSE;
1261 DPRINT("KiDispatchException() called\n");
1262
1263 /* Increase number of Exception Dispatches */
1264 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
1265
1266 /* Set the context flags */
1267 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
1268
1269 /* Check if User Mode */
1270 if (PreviousMode == UserMode)
1271 {
1272 /* Add the FPU Flag */
1273 Context.ContextFlags |= CONTEXT_FLOATING_POINT;
1274 if (KeI386FxsrPresent) Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
1275 }
1276
1277 /* Get a Context */
1278 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
1279
1280 /* Handle kernel-mode first, it's simpler */
1281 if (PreviousMode == KernelMode)
1282 {
1283 /* Check if this is a first-chance exception */
1284 if (FirstChance == TRUE)
1285 {
1286 /* Break into the debugger for the first time */
1287 Action = KdpEnterDebuggerException(ExceptionRecord,
1288 PreviousMode,
1289 &Context,
1290 TrapFrame,
1291 TRUE,
1292 TRUE);
1293
1294 /* If the debugger said continue, then continue */
1295 if (Action == kdContinue) goto Handled;
1296
1297 /* If the Debugger couldn't handle it, dispatch the exception */
1298 if (RtlDispatchException(ExceptionRecord, &Context))
1299 {
1300 /* It was handled by an exception handler, continue */
1301 goto Handled;
1302 }
1303 }
1304
1305 /* This is a second-chance exception, only for the debugger */
1306 Action = KdpEnterDebuggerException(ExceptionRecord,
1307 PreviousMode,
1308 &Context,
1309 TrapFrame,
1310 FALSE,
1311 FALSE);
1312
1313 /* If the debugger said continue, then continue */
1314 if (Action == kdContinue) goto Handled;
1315
1316 /* Third strike; you're out */
1317 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
1318 ExceptionRecord->ExceptionCode,
1319 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1320 ExceptionRecord->ExceptionInformation[0],
1321 ExceptionRecord->ExceptionInformation[1],
1322 TrapFrame);
1323 }
1324 else
1325 {
1326 /* User mode exception, was it first-chance? */
1327 if (FirstChance)
1328 {
1329 /* Enter Debugger if available */
1330 Action = KdpEnterDebuggerException(ExceptionRecord,
1331 PreviousMode,
1332 &Context,
1333 TrapFrame,
1334 TRUE,
1335 TRUE);
1336
1337 /* Exit if we're continuing */
1338 if (Action == kdContinue) goto Handled;
1339
1340 /* FIXME: Forward exception to user mode debugger */
1341
1342 /* Set up the user-stack */
1343 _SEH_TRY
1344 {
1345 /* Align context size and get stack pointer */
1346 Size = (sizeof(CONTEXT) + 3) & ~3;
1347 Stack = (Context.Esp & ~3) - Size;
1348 DPRINT("Stack: %lx\n", Stack);
1349
1350 /* Probe stack and copy Context */
1351 ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
1352 RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));
1353
1354 /* Align exception record size and get stack pointer */
1355 Size = (sizeof(EXCEPTION_RECORD) -
1356 (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) *
1357 sizeof(ULONG) + 3) & ~3;
1358 NewStack = Stack - Size;
1359 DPRINT("NewStack: %lx\n", NewStack);
1360
1361 /* Probe stack and copy exception record. Don't forget to add the two params */
1362 ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
1363 Size + 2 * sizeof(ULONG_PTR),
1364 sizeof(ULONG));
1365 RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);
1366
1367 /* Now write the two params for the user-mode dispatcher */
1368 *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
1369 *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;
1370
1371 /* Set new Stack Pointer */
1372 KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));
1373
1374 /* Set EIP to the User-mode Dispathcer */
1375 TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
1376 UserDispatch = TRUE;
1377 _SEH_LEAVE;
1378 }
1379 _SEH_HANDLE
1380 {
1381 /* Do second-chance */
1382 }
1383 _SEH_END;
1384 }
1385
1386 /* If we dispatch to user, return now */
1387 if (UserDispatch) return;
1388
1389 /* FIXME: Forward the exception to the debugger for 2nd chance */
1390
1391 /* 3rd strike, kill the thread */
1392 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1393 ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
1394 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
1395 ExceptionRecord->ExceptionCode,
1396 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
1397 ExceptionRecord->ExceptionInformation[0],
1398 ExceptionRecord->ExceptionInformation[1],
1399 TrapFrame);
1400 }
1401
1402 Handled:
1403 /* Convert the context back into Trap/Exception Frames */
1404 KeContextToTrapFrame(&Context,
1405 NULL,
1406 TrapFrame,
1407 Context.ContextFlags,
1408 PreviousMode);
1409 return;
1410 }
1411
1412 /*
1413 * @implemented
1414 */
1415 NTSTATUS
1416 NTAPI
1417 KeRaiseUserException(IN NTSTATUS ExceptionCode)
1418 {
1419 ULONG OldEip;
1420 PKTHREAD Thread = KeGetCurrentThread();
1421
1422 /* Make sure we can access the TEB */
1423 _SEH_TRY
1424 {
1425 Thread->Teb->ExceptionCode = ExceptionCode;
1426 }
1427 _SEH_HANDLE
1428 {
1429 return(ExceptionCode);
1430 }
1431 _SEH_END;
1432
1433 /* Get the old EIP */
1434 OldEip = Thread->TrapFrame->Eip;
1435
1436 /* Change it to the user-mode dispatcher */
1437 Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;
1438
1439 /* Return the old EIP */
1440 return((NTSTATUS)OldEip);
1441 }
1442