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