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