3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/exp.c
22 * PURPOSE: Handling exceptions
23 * PROGRAMMER: David Welch (welch@cwcom.net)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
32 #include <internal/ntoskrnl.h>
33 #include <internal/ke.h>
34 #include <internal/i386/segment.h>
35 #include <internal/i386/mm.h>
36 #include <internal/module.h>
37 #include <internal/mm.h>
38 #include <internal/ps.h>
39 #include <internal/trap.h>
40 #include <ntdll/ldr.h>
41 #include <internal/safe.h>
42 #include <internal/kd.h>
45 #include <internal/debug.h>
47 /* GLOBALS *****************************************************************/
49 #define FLAG_IF (1<<9)
52 #define STR(x) _STR(x)
54 extern void interrupt_handler2e(void);
55 extern void interrupt_handler2d(void);
57 extern VOID KiTrap0(VOID);
58 extern VOID KiTrap1(VOID);
59 extern VOID KiTrap2(VOID);
60 extern VOID KiTrap3(VOID);
61 extern VOID KiTrap4(VOID);
62 extern VOID KiTrap5(VOID);
63 extern VOID KiTrap6(VOID);
64 extern VOID KiTrap7(VOID);
65 extern VOID KiTrap8(VOID);
66 extern VOID KiTrap9(VOID);
67 extern VOID KiTrap10(VOID);
68 extern VOID KiTrap11(VOID);
69 extern VOID KiTrap12(VOID);
70 extern VOID KiTrap13(VOID);
71 extern VOID KiTrap14(VOID);
72 extern VOID KiTrap15(VOID);
73 extern VOID KiTrap16(VOID);
74 extern VOID KiTrapUnknown(VOID);
76 extern ULONG init_stack;
77 extern ULONG init_stack_top;
79 static char *ExceptionTypeStrings[] =
86 "BOUND range exceeded",
88 "No Math Coprocessor",
92 "Segment Not Present",
93 "Stack Segment Fault",
101 static NTSTATUS ExceptionToNtStatus[] =
103 STATUS_INTEGER_DIVIDE_BY_ZERO,
105 STATUS_ACCESS_VIOLATION,
107 STATUS_INTEGER_OVERFLOW,
108 STATUS_ARRAY_BOUNDS_EXCEEDED,
109 STATUS_ILLEGAL_INSTRUCTION,
110 STATUS_ACCESS_VIOLATION, /* STATUS_FLT_INVALID_OPERATION */
111 STATUS_ACCESS_VIOLATION,
112 STATUS_ACCESS_VIOLATION,
113 STATUS_ACCESS_VIOLATION,
114 STATUS_ACCESS_VIOLATION,
115 STATUS_STACK_OVERFLOW,
116 STATUS_ACCESS_VIOLATION,
117 STATUS_ACCESS_VIOLATION,
118 STATUS_ACCESS_VIOLATION, /* STATUS_FLT_INVALID_OPERATION */
119 STATUS_DATATYPE_MISALIGNMENT,
120 STATUS_ACCESS_VIOLATION
123 extern unsigned int _text_start__, _text_end__;
125 /* FUNCTIONS ****************************************************************/
128 print_address(PVOID address)
130 PLIST_ENTRY current_entry;
131 MODULE_TEXT_SECTION* current;
132 extern LIST_ENTRY ModuleTextListHead;
133 ULONG_PTR RelativeAddress;
135 current_entry = ModuleTextListHead.Flink;
137 while (current_entry != &ModuleTextListHead &&
138 current_entry != NULL)
141 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
143 if (address >= (PVOID)current->Base &&
144 address < (PVOID)(current->Base + current->Length))
146 RelativeAddress = (ULONG_PTR) address - current->Base;
147 DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
150 current_entry = current_entry->Flink;
156 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
160 Er.ExceptionFlags = 0;
161 Er.ExceptionRecord = NULL;
162 Er.ExceptionAddress = (PVOID)Tf->Eip;
164 if (ExceptionNr == 14)
166 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
167 Er.NumberParameters = 2;
168 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
169 Er.ExceptionInformation[1] = (ULONG)Cr2;
173 if (ExceptionNr < 16)
175 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
179 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
181 Er.NumberParameters = 0;
184 Er.ExceptionFlags = (STATUS_SINGLE_STEP == (NTSTATUS) Er.ExceptionCode || STATUS_BREAKPOINT == (NTSTATUS) Er.ExceptionCode ?
185 0 : EXCEPTION_NONCONTINUABLE);
187 KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
193 KiDoubleFaultHandler(VOID)
199 ULONG ExceptionNr = 8;
205 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
206 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
207 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
212 OldTss = KeGetCurrentKPCR()->TSS;
216 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
218 if (PsGetCurrentThread() != NULL &&
219 PsGetCurrentThread()->ThreadsProcess != NULL)
222 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
230 * Check for stack underflow
232 if (PsGetCurrentThread() != NULL &&
233 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
235 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
236 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
241 * Print out the CPU registers
243 if (ExceptionNr < 19)
245 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
250 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
252 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
253 print_address((PVOID)OldTss->Eip);
255 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
256 DbgPrint("Proc: %x ",PsGetCurrentProcess());
257 if (PsGetCurrentProcess() != NULL)
259 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
260 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
262 if (PsGetCurrentThread() != NULL)
264 DbgPrint("Thrd: %x Tid: %x",
265 PsGetCurrentThread(),
266 PsGetCurrentThread()->Cid.UniqueThread);
269 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
270 OldTss->Fs, OldTss->Gs);
271 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
273 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss->Edx, OldTss->Ebp,
275 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
276 if (OldTss->Cs == KERNEL_CS)
278 DbgPrint("kESP %.8x ", Esp0);
279 if (PsGetCurrentThread() != NULL)
281 DbgPrint("kernel stack base %x\n",
282 PsGetCurrentThread()->Tcb.StackLimit);
288 DbgPrint("User ESP %.8x\n", OldTss->Esp);
290 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
292 DbgPrint("ESP %x\n", Esp0);
293 if (PsGetCurrentThread() != NULL)
295 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
296 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
300 StackLimit = (ULONG)&init_stack_top;
301 StackBase = (ULONG)&init_stack;
305 DbgPrint("Frames: ");
306 Frame = (PULONG)OldTss->Ebp;
307 while (Frame != NULL && (ULONG)Frame >= StackBase)
309 print_address((PVOID)Frame[1]);
310 Frame = (PULONG)Frame[0];
314 DbgPrint("Frames: ");
316 Frame = (PULONG)OldTss->Ebp;
317 while (Frame != NULL && (ULONG)Frame >= StackBase)
319 StackTrace[i] = (PVOID)Frame[1];
320 Frame = (PULONG)Frame[0];
326 while (i < TraceLength)
328 StackRepeatCount[i] = 0;
331 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
333 if (memcmp(&StackTrace[i], &StackTrace[j],
334 (j - i) * sizeof(PVOID)) == 0)
336 StackRepeatCount[i] = 2;
337 StackRepeatLength[i] = j - i;
345 if (FoundRepeat == FALSE)
350 j = j + StackRepeatLength[i];
351 while ((TraceLength - j) >= StackRepeatLength[i] &&
354 if (memcmp(&StackTrace[i], &StackTrace[j],
355 StackRepeatLength[i] * sizeof(PVOID)) == 0)
357 StackRepeatCount[i]++;
358 j = j + StackRepeatLength[i];
369 while (i < TraceLength)
371 if (StackRepeatCount[i] == 0)
373 print_address(StackTrace[i]);
379 if (StackRepeatLength[i] == 0)
383 for (j = 0; j < StackRepeatLength[i]; j++)
385 print_address(StackTrace[i + j]);
387 DbgPrint("}*%d", StackRepeatCount[i]);
388 i = i + StackRepeatLength[i] * StackRepeatCount[i];
399 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
406 ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
407 ULONG cr2 = (ULONG)Tf->DebugPointer;
412 * Print out the CPU registers
414 if (ExceptionNr < 19)
416 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
417 ExceptionNr, Tf->ErrorCode&0xffff);
421 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
423 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
424 Tf->Cs&0xffff, Tf->Eip);
425 print_address((PVOID)Tf->Eip);
427 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3));
428 DbgPrint("cr2 %x cr3 %x ", cr2, cr3);
429 DbgPrint("Proc: %x ",PsGetCurrentProcess());
430 if (PsGetCurrentProcess() != NULL)
432 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
433 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
435 if (PsGetCurrentThread() != NULL)
437 DbgPrint("Thrd: %x Tid: %x",
438 PsGetCurrentThread(),
439 PsGetCurrentThread()->Cid.UniqueThread);
442 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
443 Tf->Fs&0xffff, Tf->Gs&0xfff);
444 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
445 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf->Edx, Tf->Ebp, Tf->Esi);
446 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
447 if ((Tf->Cs&0xffff) == KERNEL_CS)
449 DbgPrint("kESP %.8x ", Esp0);
450 if (PsGetCurrentThread() != NULL)
452 DbgPrint("kernel stack base %x\n",
453 PsGetCurrentThread()->Tcb.StackLimit);
458 DbgPrint("ESP %x\n", Esp0);
460 if (PsGetCurrentThread() != NULL)
462 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
466 StackLimit = (ULONG)&init_stack_top;
470 * Dump the stack frames
472 DbgPrint("Frames: ");
474 Frame = (PULONG)Tf->Ebp;
475 while (Frame != NULL)
477 print_address((PVOID)Frame[1]);
478 Frame = (PULONG)Frame[0];
485 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
487 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
488 * message and halt the computer
490 * Complete CPU context
497 /* Store the exception number in an unused field in the trap frame. */
498 Tf->DebugArgMark = (PVOID)ExceptionNr;
500 /* Use the address of the trap frame as approximation to the ring0 esp */
501 Esp0 = (ULONG)&Tf->Eip;
504 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
505 Tf->DebugPointer = (PVOID)cr2;
508 * If this was a V86 mode exception then handle it specially
510 if (Tf->Eflags & (1 << 17))
512 return(KeV86Exception(ExceptionNr, Tf, cr2));
516 * Check for stack underflow, this may be obsolete
518 if (PsGetCurrentThread() != NULL &&
519 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
521 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
522 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
527 * Maybe handle the page fault and return
529 if (ExceptionNr == 14)
531 if (Tf->Eflags & FLAG_IF)
535 Status = MmPageFault(Tf->Cs&0xffff,
540 if (NT_SUCCESS(Status))
547 * Handle user exceptions differently
549 if ((Tf->Cs & 0xFFFF) == USER_CS)
551 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
555 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
560 KeDumpStackFrames(PULONG Frame)
564 DbgPrint("Frames: ");
566 while (Frame != NULL)
568 print_address((PVOID)Frame[1]);
569 Frame = (PULONG)Frame[0];
575 static void set_system_call_gate(unsigned int sel, unsigned int func)
577 DPRINT("sel %x %d\n",sel,sel);
578 KiIdt[sel].a = (((int)func)&0xffff) +
580 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
581 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
584 static void set_interrupt_gate(unsigned int sel, unsigned int func)
586 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
587 KiIdt[sel].a = (((int)func)&0xffff) +
589 KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
592 static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
594 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
596 KiIdt[sel].a = (((int)func)&0xffff) +
598 KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
602 set_task_gate(unsigned int sel, unsigned task_sel)
604 KiIdt[sel].a = task_sel << 16;
605 KiIdt[sel].b = 0x8500;
609 KeInitExceptions(VOID)
611 * FUNCTION: Initalize CPU exception handling
616 DPRINT("KeInitExceptions()\n");
619 * Set up the other gates
621 set_trap_gate(0, (ULONG)KiTrap0, 0);
622 set_trap_gate(1, (ULONG)KiTrap1, 0);
623 set_trap_gate(2, (ULONG)KiTrap2, 0);
624 set_trap_gate(3, (ULONG)KiTrap3, 3);
625 set_trap_gate(4, (ULONG)KiTrap4, 0);
626 set_trap_gate(5, (ULONG)KiTrap5, 0);
627 set_trap_gate(6, (ULONG)KiTrap6, 0);
628 set_trap_gate(7, (ULONG)KiTrap7, 0);
629 set_task_gate(8, TRAP_TSS_SELECTOR);
630 set_trap_gate(9, (ULONG)KiTrap9, 0);
631 set_trap_gate(10, (ULONG)KiTrap10, 0);
632 set_trap_gate(11, (ULONG)KiTrap11, 0);
633 set_trap_gate(12, (ULONG)KiTrap12, 0);
634 set_trap_gate(13, (ULONG)KiTrap13, 0);
635 set_interrupt_gate(14, (ULONG)KiTrap14);
636 set_trap_gate(15, (ULONG)KiTrap15, 0);
637 set_trap_gate(16, (ULONG)KiTrap16, 0);
641 set_trap_gate(i,(int)KiTrapUnknown, 0);
644 set_system_call_gate(0x2d,(int)interrupt_handler2d);
645 set_system_call_gate(0x2e,(int)interrupt_handler2e);