Thread/Process Termination/Repeaing Rewrite + Fixes
[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 /* GLOBALS *****************************************************************/
19
20 #define FLAG_IF (1<<9)
21
22 #define _STR(x) #x
23 #define STR(x) _STR(x)
24
25 #ifndef ARRAY_SIZE
26 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
27 #endif
28
29 extern void KiSystemService(void);
30 extern void interrupt_handler2d(void);
31
32 extern VOID KiTrap0(VOID);
33 extern VOID KiTrap1(VOID);
34 extern VOID KiTrap2(VOID);
35 extern VOID KiTrap3(VOID);
36 extern VOID KiTrap4(VOID);
37 extern VOID KiTrap5(VOID);
38 extern VOID KiTrap6(VOID);
39 extern VOID KiTrap7(VOID);
40 extern VOID KiTrap8(VOID);
41 extern VOID KiTrap9(VOID);
42 extern VOID KiTrap10(VOID);
43 extern VOID KiTrap11(VOID);
44 extern VOID KiTrap12(VOID);
45 extern VOID KiTrap13(VOID);
46 extern VOID KiTrap14(VOID);
47 extern VOID KiTrap15(VOID);
48 extern VOID KiTrap16(VOID);
49 extern VOID KiTrap17(VOID);
50 extern VOID KiTrap18(VOID);
51 extern VOID KiTrap19(VOID);
52 extern VOID KiTrapUnknown(VOID);
53
54 extern ULONG init_stack;
55 extern ULONG init_stack_top;
56
57 extern BOOLEAN Ke386NoExecute;
58
59 static char *ExceptionTypeStrings[] =
60 {
61 "Divide Error",
62 "Debug Trap",
63 "NMI",
64 "Breakpoint",
65 "Overflow",
66 "BOUND range exceeded",
67 "Invalid Opcode",
68 "No Math Coprocessor",
69 "Double Fault",
70 "Unknown(9)",
71 "Invalid TSS",
72 "Segment Not Present",
73 "Stack Segment Fault",
74 "General Protection",
75 "Page Fault",
76 "Reserved(15)",
77 "Math Fault",
78 "Alignment Check",
79 "Machine Check",
80 "SIMD Fault"
81 };
82
83 NTSTATUS ExceptionToNtStatus[] =
84 {
85 STATUS_INTEGER_DIVIDE_BY_ZERO,
86 STATUS_SINGLE_STEP,
87 STATUS_ACCESS_VIOLATION,
88 STATUS_BREAKPOINT,
89 STATUS_INTEGER_OVERFLOW,
90 STATUS_ARRAY_BOUNDS_EXCEEDED,
91 STATUS_ILLEGAL_INSTRUCTION,
92 STATUS_FLOAT_INVALID_OPERATION,
93 STATUS_ACCESS_VIOLATION,
94 STATUS_ACCESS_VIOLATION,
95 STATUS_ACCESS_VIOLATION,
96 STATUS_ACCESS_VIOLATION,
97 STATUS_STACK_OVERFLOW,
98 STATUS_ACCESS_VIOLATION,
99 STATUS_ACCESS_VIOLATION,
100 STATUS_ACCESS_VIOLATION, /* RESERVED */
101 STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
102 STATUS_DATATYPE_MISALIGNMENT,
103 STATUS_ACCESS_VIOLATION,
104 STATUS_FLOAT_MULTIPLE_TRAPS,
105 };
106
107 /* FUNCTIONS ****************************************************************/
108
109 #if defined(DBG) || defined(KDBG)
110 BOOLEAN STDCALL
111 KeRosPrintAddress(PVOID address)
112 {
113 return KdbSymPrintAddress(address);
114 }
115 #else /* KDBG */
116 BOOLEAN STDCALL
117 KeRosPrintAddress(PVOID address)
118 {
119 PLIST_ENTRY current_entry;
120 MODULE_TEXT_SECTION* current;
121 extern LIST_ENTRY ModuleTextListHead;
122 ULONG_PTR RelativeAddress;
123
124 current_entry = ModuleTextListHead.Flink;
125
126 while (current_entry != &ModuleTextListHead &&
127 current_entry != NULL)
128 {
129 current =
130 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
131
132 if (address >= (PVOID)current->Base &&
133 address < (PVOID)(current->Base + current->Length))
134 {
135 RelativeAddress = (ULONG_PTR) address - current->Base;
136 DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
137 return(TRUE);
138 }
139 current_entry = current_entry->Flink;
140 }
141 return(FALSE);
142 }
143 #endif /* KDBG */
144
145 ULONG
146 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
147 {
148 EXCEPTION_RECORD Er;
149
150 Er.ExceptionFlags = 0;
151 Er.ExceptionRecord = NULL;
152 Er.ExceptionAddress = (PVOID)Tf->Eip;
153
154 if (ExceptionNr == 14)
155 {
156 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
157 Er.NumberParameters = 2;
158 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
159 Er.ExceptionInformation[1] = (ULONG)Cr2;
160 }
161 else
162 {
163 if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
164 {
165 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
166 }
167 else
168 {
169 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
170 }
171 Er.NumberParameters = 0;
172 }
173
174 /* FIXME: Which exceptions are noncontinuable? */
175 Er.ExceptionFlags = 0;
176
177 KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
178
179 return(0);
180 }
181
182 ULONG
183 KiDoubleFaultHandler(VOID)
184 {
185 unsigned int cr2;
186 ULONG StackLimit;
187 ULONG StackBase;
188 ULONG Esp0;
189 ULONG ExceptionNr = 8;
190 KTSS* OldTss;
191 PULONG Frame;
192 ULONG OldCr3;
193 #if 0
194 ULONG i, j;
195 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
196 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
197 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
198 ULONG TraceLength;
199 BOOLEAN FoundRepeat;
200 #endif
201
202 OldTss = KeGetCurrentKPCR()->TSS;
203 Esp0 = OldTss->Esp;
204
205 /* Get CR2 */
206 cr2 = Ke386GetCr2();
207 if (PsGetCurrentThread() != NULL &&
208 PsGetCurrentThread()->ThreadsProcess != NULL)
209 {
210 OldCr3 = (ULONG)
211 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
212 }
213 else
214 {
215 OldCr3 = 0xBEADF0AL;
216 }
217
218 /*
219 * Check for stack underflow
220 */
221 if (PsGetCurrentThread() != NULL &&
222 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
223 {
224 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
225 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
226 ExceptionNr = 12;
227 }
228
229 /*
230 * Print out the CPU registers
231 */
232 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
233 {
234 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
235 ExceptionNr, 0);
236 }
237 else
238 {
239 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
240 }
241 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
242 KeRosPrintAddress((PVOID)OldTss->Eip);
243 DbgPrint("\n");
244 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
245 DbgPrint("Proc: %x ",PsGetCurrentProcess());
246 if (PsGetCurrentProcess() != NULL)
247 {
248 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
249 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
250 }
251 if (PsGetCurrentThread() != NULL)
252 {
253 DbgPrint("Thrd: %x Tid: %x",
254 PsGetCurrentThread(),
255 PsGetCurrentThread()->Cid.UniqueThread);
256 }
257 DbgPrint("\n");
258 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
259 OldTss->Fs, OldTss->Gs);
260 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
261 OldTss->Ecx);
262 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n ESP: %.8x", OldTss->Edx,
263 OldTss->Ebp, OldTss->Esi, Esp0);
264 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
265 if (OldTss->Cs == KERNEL_CS)
266 {
267 DbgPrint("kESP %.8x ", Esp0);
268 if (PsGetCurrentThread() != NULL)
269 {
270 DbgPrint("kernel stack base %x\n",
271 PsGetCurrentThread()->Tcb.StackLimit);
272
273 }
274 }
275 else
276 {
277 DbgPrint("User ESP %.8x\n", OldTss->Esp);
278 }
279 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
280 {
281 if (PsGetCurrentThread() != NULL)
282 {
283 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
284 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
285 }
286 else
287 {
288 StackLimit = (ULONG)init_stack_top;
289 StackBase = (ULONG)init_stack;
290 }
291
292 /*
293 Change to an #if 0 to reduce the amount of information printed on
294 a recursive stack trace.
295 */
296 #if 1
297 DbgPrint("Frames: ");
298 Frame = (PULONG)OldTss->Ebp;
299 while (Frame != NULL && (ULONG)Frame >= StackBase)
300 {
301 KeRosPrintAddress((PVOID)Frame[1]);
302 Frame = (PULONG)Frame[0];
303 DbgPrint("\n");
304 }
305 #else
306 DbgPrint("Frames: ");
307 i = 0;
308 Frame = (PULONG)OldTss->Ebp;
309 while (Frame != NULL && (ULONG)Frame >= StackBase)
310 {
311 StackTrace[i] = (PVOID)Frame[1];
312 Frame = (PULONG)Frame[0];
313 i++;
314 }
315 TraceLength = i;
316
317 i = 0;
318 while (i < TraceLength)
319 {
320 StackRepeatCount[i] = 0;
321 j = i + 1;
322 FoundRepeat = FALSE;
323 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
324 {
325 if (memcmp(&StackTrace[i], &StackTrace[j],
326 (j - i) * sizeof(PVOID)) == 0)
327 {
328 StackRepeatCount[i] = 2;
329 StackRepeatLength[i] = j - i;
330 FoundRepeat = TRUE;
331 }
332 else
333 {
334 j++;
335 }
336 }
337 if (FoundRepeat == FALSE)
338 {
339 i++;
340 continue;
341 }
342 j = j + StackRepeatLength[i];
343 while ((TraceLength - j) >= StackRepeatLength[i] &&
344 FoundRepeat == TRUE)
345 {
346 if (memcmp(&StackTrace[i], &StackTrace[j],
347 StackRepeatLength[i] * sizeof(PVOID)) == 0)
348 {
349 StackRepeatCount[i]++;
350 j = j + StackRepeatLength[i];
351 }
352 else
353 {
354 FoundRepeat = FALSE;
355 }
356 }
357 i = j;
358 }
359
360 i = 0;
361 while (i < TraceLength)
362 {
363 if (StackRepeatCount[i] == 0)
364 {
365 KeRosPrintAddress(StackTrace[i]);
366 i++;
367 }
368 else
369 {
370 DbgPrint("{");
371 if (StackRepeatLength[i] == 0)
372 {
373 for(;;);
374 }
375 for (j = 0; j < StackRepeatLength[i]; j++)
376 {
377 KeRosPrintAddress(StackTrace[i + j]);
378 }
379 DbgPrint("}*%d", StackRepeatCount[i]);
380 i = i + StackRepeatLength[i] * StackRepeatCount[i];
381 }
382 }
383 #endif
384 }
385
386 DbgPrint("\n");
387 for(;;);
388 return 0;
389 }
390
391 VOID
392 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
393 {
394 ULONG cr3_;
395 ULONG StackLimit;
396 ULONG Esp0;
397 ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
398 ULONG cr2 = (ULONG)Tf->DebugPointer;
399
400 Esp0 = (ULONG)Tf;
401
402 /*
403 * Print out the CPU registers
404 */
405 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
406 {
407 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
408 ExceptionNr, Tf->ErrorCode&0xffff);
409 }
410 else
411 {
412 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
413 }
414 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
415 Tf->Cs&0xffff, Tf->Eip);
416 KeRosPrintAddress((PVOID)Tf->Eip);
417 DbgPrint("\n");
418 Ke386GetPageTableDirectory(cr3_);
419 DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
420 DbgPrint("Proc: %x ",PsGetCurrentProcess());
421 if (PsGetCurrentProcess() != NULL)
422 {
423 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
424 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
425 }
426 if (PsGetCurrentThread() != NULL)
427 {
428 DbgPrint("Thrd: %x Tid: %x",
429 PsGetCurrentThread(),
430 PsGetCurrentThread()->Cid.UniqueThread);
431 }
432 DbgPrint("\n");
433 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
434 Tf->Fs&0xffff, Tf->Gs&0xfff);
435 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
436 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
437 Tf->Ebp, Tf->Esi, Esp0);
438 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
439 if ((Tf->Cs&0xffff) == KERNEL_CS)
440 {
441 DbgPrint("kESP %.8x ", Esp0);
442 if (PsGetCurrentThread() != NULL)
443 {
444 DbgPrint("kernel stack base %x\n",
445 PsGetCurrentThread()->Tcb.StackLimit);
446
447 }
448 }
449
450 if (PsGetCurrentThread() != NULL)
451 {
452 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
453 }
454 else
455 {
456 StackLimit = (ULONG)init_stack_top;
457 }
458
459 /*
460 * Dump the stack frames
461 */
462 KeDumpStackFrames((PULONG)Tf->Ebp);
463 }
464
465 ULONG
466 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
467 /*
468 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
469 * message and halt the computer
470 * ARGUMENTS:
471 * Complete CPU context
472 */
473 {
474 unsigned int cr2;
475 NTSTATUS Status;
476 ULONG Esp0;
477
478 /* Store the exception number in an unused field in the trap frame. */
479 Tf->DebugArgMark = (PVOID)ExceptionNr;
480
481 /* Use the address of the trap frame as approximation to the ring0 esp */
482 Esp0 = (ULONG)&Tf->Eip;
483
484 /* Get CR2 */
485 cr2 = Ke386GetCr2();
486 Tf->DebugPointer = (PVOID)cr2;
487
488 if (ExceptionNr == 14 && Tf->Eflags & FLAG_IF)
489 {
490 Ke386EnableInterrupts();
491 }
492
493 /*
494 * If this was a V86 mode exception then handle it specially
495 */
496 if (Tf->Eflags & (1 << 17))
497 {
498 return(KeV86Exception(ExceptionNr, Tf, cr2));
499 }
500
501 /*
502 * Check for stack underflow, this may be obsolete
503 */
504 if (PsGetCurrentThread() != NULL &&
505 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
506 {
507 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
508 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
509 ExceptionNr = 12;
510 }
511
512 if (ExceptionNr == 15)
513 {
514 /*
515 * FIXME:
516 * This exception should never occur. The P6 has a bug, which does sometimes deliver
517 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
518 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
519 * sources. Linux does ignore this exception.
520 *
521 * Hartmut Birr
522 */
523 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
524 return(0);
525 }
526
527 /*
528 * Maybe handle the page fault and return
529 */
530 if (ExceptionNr == 14)
531 {
532 if (Ke386NoExecute && Tf->ErrorCode & 0x10 && cr2 >= KERNEL_BASE)
533 {
534 KEBUGCHECKWITHTF(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY, 0, 0, 0, 0, Tf);
535 }
536 Status = MmPageFault(Tf->Cs&0xffff,
537 &Tf->Eip,
538 &Tf->Eax,
539 cr2,
540 Tf->ErrorCode);
541 if (NT_SUCCESS(Status))
542 {
543 return(0);
544 }
545 }
546
547 /*
548 * Check for a breakpoint that was only for the attention of the debugger.
549 */
550 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
551 {
552 /*
553 EIP is already adjusted by the processor to point to the instruction
554 after the breakpoint.
555 */
556 return(0);
557 }
558
559 /*
560 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
561 */
562 if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
563 {
564 Status = KiHandleFpuFault(Tf, ExceptionNr);
565 if (NT_SUCCESS(Status))
566 {
567 return(0);
568 }
569 }
570
571 /*
572 * Handle user exceptions differently
573 */
574 if ((Tf->Cs & 0xFFFF) == USER_CS)
575 {
576 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
577 }
578 else
579 {
580 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
581 }
582 }
583
584 VOID
585 KeContextToTrapFrame(PCONTEXT Context,
586 PKTRAP_FRAME TrapFrame)
587 {
588 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
589 {
590 TrapFrame->Esp = Context->Esp;
591 TrapFrame->Ss = Context->SegSs;
592 TrapFrame->Cs = Context->SegCs;
593 TrapFrame->Eip = Context->Eip;
594 TrapFrame->Eflags = Context->EFlags;
595 TrapFrame->Ebp = Context->Ebp;
596 }
597 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
598 {
599 TrapFrame->Eax = Context->Eax;
600 TrapFrame->Ebx = Context->Ebx;
601 TrapFrame->Ecx = Context->Ecx;
602 TrapFrame->Edx = Context->Edx;
603 TrapFrame->Esi = Context->Esi;
604 TrapFrame->Edi = Context->Edi;
605 }
606 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
607 {
608 TrapFrame->Ds = Context->SegDs;
609 TrapFrame->Es = Context->SegEs;
610 TrapFrame->Fs = Context->SegFs;
611 TrapFrame->Gs = Context->SegGs;
612 }
613 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
614 {
615 /*
616 * Not handled
617 *
618 * This should be handled separately I think.
619 * - blight
620 */
621 }
622 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
623 {
624 /*
625 * Not handled
626 */
627 }
628 }
629
630 VOID
631 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
632 PCONTEXT Context)
633 {
634 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
635 {
636 Context->SegSs = TrapFrame->Ss;
637 Context->Esp = TrapFrame->Esp;
638 Context->SegCs = TrapFrame->Cs;
639 Context->Eip = TrapFrame->Eip;
640 Context->EFlags = TrapFrame->Eflags;
641 Context->Ebp = TrapFrame->Ebp;
642 }
643 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
644 {
645 Context->Eax = TrapFrame->Eax;
646 Context->Ebx = TrapFrame->Ebx;
647 Context->Ecx = TrapFrame->Ecx;
648 /*
649 * NOTE: In the trap frame which is built on entry to a system
650 * call TrapFrame->Edx will actually hold the address of the
651 * previous TrapFrame. I don't believe leaking this information
652 * has security implications. Also EDX holds the address of the
653 * arguments to the system call in progress so it isn't of much
654 * interest to the debugger.
655 */
656 Context->Edx = TrapFrame->Edx;
657 Context->Esi = TrapFrame->Esi;
658 Context->Edi = TrapFrame->Edi;
659 }
660 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
661 {
662 Context->SegDs = TrapFrame->Ds;
663 Context->SegEs = TrapFrame->Es;
664 Context->SegFs = TrapFrame->Fs;
665 Context->SegGs = TrapFrame->Gs;
666 }
667 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
668 {
669 /*
670 * FIXME: Implement this case
671 */
672 Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
673 }
674 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
675 {
676 /*
677 * FIXME: Implement this case
678 *
679 * I think this should only be filled for FPU exceptions, otherwise I
680 * would not know where to get it from as it can be the current state
681 * of the FPU or already saved in the thread's FPU save area.
682 * -blight
683 */
684 Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
685 }
686 #if 0
687 if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
688 {
689 /*
690 * FIXME: Investigate this
691 *
692 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
693 * This should only be filled in case of a SIMD exception I think, so
694 * this is not the right place (like for FPU the state could already be
695 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
696 * -blight
697 */
698 Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS;
699 }
700 #endif
701 }
702
703 VOID
704 KeDumpStackFrames(PULONG Frame)
705 {
706 PULONG StackBase, StackEnd;
707 MEMORY_BASIC_INFORMATION mbi;
708 ULONG ResultLength = sizeof(mbi);
709 NTSTATUS Status;
710
711 DbgPrint("Frames:\n");
712 _SEH_TRY
713 {
714 Status = MiQueryVirtualMemory (
715 (HANDLE)-1,
716 Frame,
717 MemoryBasicInformation,
718 &mbi,
719 sizeof(mbi),
720 &ResultLength );
721 if ( !NT_SUCCESS(Status) )
722 {
723 DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
724 return;
725 }
726
727 StackBase = Frame;
728 StackEnd = mbi.BaseAddress + mbi.RegionSize;
729
730 while ( Frame >= StackBase && Frame < StackEnd )
731 {
732 ULONG Addr = Frame[1];
733 if (!KeRosPrintAddress((PVOID)Addr))
734 DbgPrint("<%X>", Addr);
735 if ( Addr == 0 || Addr == 0xDEADBEEF )
736 break;
737 StackBase = Frame;
738 Frame = (PULONG)Frame[0];
739 DbgPrint("\n");
740 }
741 }
742 _SEH_HANDLE
743 {
744 }
745 _SEH_END;
746 DbgPrint("\n");
747 }
748
749 VOID STDCALL
750 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
751 {
752 ULONG i=0;
753 PULONG StackBase, StackEnd;
754 MEMORY_BASIC_INFORMATION mbi;
755 ULONG ResultLength = sizeof(mbi);
756 NTSTATUS Status;
757
758 DbgPrint("Frames: ");
759 _SEH_TRY
760 {
761 if ( !Frame )
762 {
763 #if defined __GNUC__
764 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
765 #elif defined(_MSC_VER)
766 __asm mov [Frame], ebp
767 #endif
768 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
769 }
770
771 Status = MiQueryVirtualMemory (
772 (HANDLE)-1,
773 Frame,
774 MemoryBasicInformation,
775 &mbi,
776 sizeof(mbi),
777 &ResultLength );
778 if ( !NT_SUCCESS(Status) )
779 {
780 DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
781 return;
782 }
783
784 StackBase = Frame;
785 StackEnd = mbi.BaseAddress + mbi.RegionSize;
786
787 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
788 {
789 ULONG Addr = Frame[1];
790 if (!KeRosPrintAddress((PVOID)Addr))
791 DbgPrint("<%X>", Addr);
792 if ( Addr == 0 || Addr == 0xDEADBEEF )
793 break;
794 StackBase = Frame;
795 Frame = (PULONG)Frame[0];
796 DbgPrint(" ");
797 }
798 }
799 _SEH_HANDLE
800 {
801 }
802 _SEH_END;
803 DbgPrint("\n");
804 }
805
806 ULONG STDCALL
807 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
808 {
809 ULONG Count = 0;
810 PULONG StackBase, StackEnd, Frame;
811 MEMORY_BASIC_INFORMATION mbi;
812 ULONG ResultLength = sizeof(mbi);
813 NTSTATUS Status;
814
815 _SEH_TRY
816 {
817 #if defined __GNUC__
818 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
819 #elif defined(_MSC_VER)
820 __asm mov [Frame], ebp
821 #endif
822
823 Status = MiQueryVirtualMemory (
824 (HANDLE)-1,
825 Frame,
826 MemoryBasicInformation,
827 &mbi,
828 sizeof(mbi),
829 &ResultLength );
830 if ( !NT_SUCCESS(Status) )
831 {
832 DPRINT1("Can't get stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
833 return 0;
834 }
835
836 StackBase = Frame;
837 StackEnd = mbi.BaseAddress + mbi.RegionSize;
838
839 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
840 {
841 Frames[Count++] = Frame[1];
842 StackBase = Frame;
843 Frame = (PULONG)Frame[0];
844 }
845 }
846 _SEH_HANDLE
847 {
848 }
849 _SEH_END;
850 return Count;
851 }
852
853 static void
854 set_system_call_gate(unsigned int sel, unsigned int func)
855 {
856 DPRINT("sel %x %d\n",sel,sel);
857 KiIdt[sel].a = (((int)func)&0xffff) +
858 (KERNEL_CS << 16);
859 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
860 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
861 }
862
863 static void set_interrupt_gate(unsigned int sel, unsigned int func)
864 {
865 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
866 KiIdt[sel].a = (((int)func)&0xffff) +
867 (KERNEL_CS << 16);
868 KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
869 }
870
871 static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
872 {
873 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
874 ASSERT(dpl <= 3);
875 KiIdt[sel].a = (((int)func)&0xffff) +
876 (KERNEL_CS << 16);
877 KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
878 }
879
880 static void
881 set_task_gate(unsigned int sel, unsigned task_sel)
882 {
883 KiIdt[sel].a = task_sel << 16;
884 KiIdt[sel].b = 0x8500;
885 }
886
887 VOID INIT_FUNCTION
888 KeInitExceptions(VOID)
889 /*
890 * FUNCTION: Initalize CPU exception handling
891 */
892 {
893 int i;
894
895 DPRINT("KeInitExceptions()\n");
896
897 /*
898 * Set up the other gates
899 */
900 set_trap_gate(0, (ULONG)KiTrap0, 0);
901 set_trap_gate(1, (ULONG)KiTrap1, 0);
902 set_trap_gate(2, (ULONG)KiTrap2, 0);
903 set_trap_gate(3, (ULONG)KiTrap3, 3);
904 set_trap_gate(4, (ULONG)KiTrap4, 0);
905 set_trap_gate(5, (ULONG)KiTrap5, 0);
906 set_trap_gate(6, (ULONG)KiTrap6, 0);
907 set_trap_gate(7, (ULONG)KiTrap7, 0);
908 set_task_gate(8, TRAP_TSS_SELECTOR);
909 set_trap_gate(9, (ULONG)KiTrap9, 0);
910 set_trap_gate(10, (ULONG)KiTrap10, 0);
911 set_trap_gate(11, (ULONG)KiTrap11, 0);
912 set_trap_gate(12, (ULONG)KiTrap12, 0);
913 set_trap_gate(13, (ULONG)KiTrap13, 0);
914 set_interrupt_gate(14, (ULONG)KiTrap14);
915 set_trap_gate(15, (ULONG)KiTrap15, 0);
916 set_trap_gate(16, (ULONG)KiTrap16, 0);
917 set_trap_gate(17, (ULONG)KiTrap17, 0);
918 set_trap_gate(18, (ULONG)KiTrap18, 0);
919 set_trap_gate(19, (ULONG)KiTrap19, 0);
920
921 for (i = 20; i < 256; i++)
922 {
923 set_trap_gate(i,(int)KiTrapUnknown, 0);
924 }
925
926 set_system_call_gate(0x2d,(int)interrupt_handler2d);
927 set_system_call_gate(0x2e,(int)KiSystemService);
928 }
929
930 /*
931 * @implemented
932 */
933 NTSTATUS STDCALL
934 KeRaiseUserException(IN NTSTATUS ExceptionCode)
935 {
936 ULONG OldEip;
937 PKTHREAD Thread = KeGetCurrentThread();
938
939 _SEH_TRY {
940 Thread->Teb->ExceptionCode = ExceptionCode;
941 } _SEH_HANDLE {
942 return(ExceptionCode);
943 } _SEH_END;
944
945 OldEip = Thread->TrapFrame->Eip;
946 Thread->TrapFrame->Eip = (ULONG_PTR)LdrpGetSystemDllRaiseExceptionDispatcher();
947 return((NTSTATUS)OldEip);
948 }
949
950 /*
951 * @implemented
952 */
953 NTSTATUS
954 STDCALL
955 NtRaiseException (
956 IN PEXCEPTION_RECORD ExceptionRecord,
957 IN PCONTEXT Context,
958 IN BOOLEAN SearchFrames)
959 {
960 PKTHREAD Thread = KeGetCurrentThread();
961 PKTRAP_FRAME TrapFrame = Thread->TrapFrame;
962 PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
963
964 KeGetCurrentKPCR()->Tib.ExceptionList = TrapFrame->ExceptionList;
965
966 KiDispatchException(ExceptionRecord,
967 Context,
968 TrapFrame,
969 KeGetPreviousMode(),
970 SearchFrames);
971
972 /* Restore the user context */
973 Thread->TrapFrame = PrevTrapFrame;
974 __asm__("mov %%ebx, %%esp;\n" "jmp _KiServiceExit": : "b" (TrapFrame));
975
976 /* We never get here */
977 return(STATUS_SUCCESS);
978 }