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>
44 #include <internal/debug.h>
46 /* GLOBALS *****************************************************************/
51 LdrGetAddressInformation(IN PIMAGE_SYMBOL_INFO SymbolInfo
,
52 IN ULONG_PTR RelativeAddress
,
53 OUT PULONG LineNumber
,
54 OUT PCH FileName OPTIONAL
,
55 OUT PCH FunctionName OPTIONAL
);
60 #define STR(x) _STR(x)
62 extern void interrupt_handler2e(void);
63 extern void interrupt_handler2d(void);
65 extern VOID
KiTrap0(VOID
);
66 extern VOID
KiTrap1(VOID
);
67 extern VOID
KiTrap2(VOID
);
68 extern VOID
KiTrap3(VOID
);
69 extern VOID
KiTrap4(VOID
);
70 extern VOID
KiTrap5(VOID
);
71 extern VOID
KiTrap6(VOID
);
72 extern VOID
KiTrap7(VOID
);
73 extern VOID
KiTrap8(VOID
);
74 extern VOID
KiTrap9(VOID
);
75 extern VOID
KiTrap10(VOID
);
76 extern VOID
KiTrap11(VOID
);
77 extern VOID
KiTrap12(VOID
);
78 extern VOID
KiTrap13(VOID
);
79 extern VOID
KiTrap14(VOID
);
80 extern VOID
KiTrap15(VOID
);
81 extern VOID
KiTrap16(VOID
);
82 extern VOID
KiTrapUnknown(VOID
);
84 extern ULONG init_stack
;
85 extern ULONG init_stack_top
;
87 static char *ExceptionTypeStrings
[] =
94 "BOUND range exceeded",
96 "No Math Coprocessor",
100 "Segment Not Present",
101 "Stack Segment Fault",
102 "General Protection",
109 static NTSTATUS ExceptionToNtStatus
[] =
111 STATUS_INTEGER_DIVIDE_BY_ZERO
,
113 STATUS_ACCESS_VIOLATION
,
115 STATUS_INTEGER_OVERFLOW
,
116 STATUS_ARRAY_BOUNDS_EXCEEDED
,
117 STATUS_ILLEGAL_INSTRUCTION
,
118 STATUS_ACCESS_VIOLATION
, /* STATUS_FLT_INVALID_OPERATION */
119 STATUS_ACCESS_VIOLATION
,
120 STATUS_ACCESS_VIOLATION
,
121 STATUS_ACCESS_VIOLATION
,
122 STATUS_ACCESS_VIOLATION
,
123 STATUS_STACK_OVERFLOW
,
124 STATUS_ACCESS_VIOLATION
,
125 STATUS_ACCESS_VIOLATION
,
126 STATUS_ACCESS_VIOLATION
, /* STATUS_FLT_INVALID_OPERATION */
127 STATUS_DATATYPE_MISALIGNMENT
,
128 STATUS_ACCESS_VIOLATION
131 extern unsigned int _text_start__
, _text_end__
;
133 /* FUNCTIONS ****************************************************************/
136 print_address(PVOID address
)
138 PLIST_ENTRY current_entry
;
139 MODULE_TEXT_SECTION
* current
;
140 extern LIST_ENTRY ModuleTextListHead
;
141 ULONG_PTR RelativeAddress
;
146 CHAR FunctionName
[256];
149 current_entry
= ModuleTextListHead
.Flink
;
151 while (current_entry
!= &ModuleTextListHead
&&
152 current_entry
!= NULL
)
155 CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
157 if (address
>= (PVOID
)current
->Base
&&
158 address
< (PVOID
)(current
->Base
+ current
->Length
))
160 RelativeAddress
= (ULONG_PTR
) address
- current
->Base
;
162 Status
= LdrGetAddressInformation(¤t
->SymbolInfo
,
167 if (NT_SUCCESS(Status
))
169 DbgPrint("<%ws: %x (%s:%d (%s))>",
170 current
->Name
, RelativeAddress
, FileName
, LineNumber
, FunctionName
);
174 DbgPrint("<%ws: %x>", current
->Name
, RelativeAddress
);
177 DbgPrint("<%ws: %x>", current
->Name
, RelativeAddress
);
181 current_entry
= current_entry
->Flink
;
187 KiKernelTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
191 Er
.ExceptionFlags
= 0;
192 Er
.ExceptionRecord
= NULL
;
193 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
195 if (ExceptionNr
== 14)
197 Er
.NumberParameters
= 2;
198 Er
.ExceptionInformation
[0] = Tf
->ErrorCode
& 0x1;
199 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
203 if (ExceptionNr
< 16)
205 Er
.ExceptionCode
= ExceptionToNtStatus
[ExceptionNr
];
209 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
211 Er
.NumberParameters
= 0;
214 KiDispatchException(&Er
, 0, Tf
, KernelMode
, TRUE
);
220 KiDoubleFaultHandler(VOID
)
226 ULONG ExceptionNr
= 8;
232 static PVOID StackTrace
[MM_STACK_SIZE
/ sizeof(PVOID
)];
233 static ULONG StackRepeatCount
[MM_STACK_SIZE
/ sizeof(PVOID
)];
234 static ULONG StackRepeatLength
[MM_STACK_SIZE
/ sizeof(PVOID
)];
239 OldTss
= KeGetCurrentKPCR()->TSS
;
243 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
245 if (PsGetCurrentThread() != NULL
&&
246 PsGetCurrentThread()->ThreadsProcess
!= NULL
)
249 PsGetCurrentThread()->ThreadsProcess
->Pcb
.DirectoryTableBase
.QuadPart
;
257 * Check for stack underflow
259 if (PsGetCurrentThread() != NULL
&&
260 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
262 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
263 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
268 * Print out the CPU registers
270 if (ExceptionNr
< 19)
272 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
277 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
279 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
280 print_address((PVOID
)OldTss
->Eip
);
282 DbgPrint("cr2 %x cr3 %x ", cr2
, OldCr3
);
283 DbgPrint("Proc: %x ",PsGetCurrentProcess());
284 if (PsGetCurrentProcess() != NULL
)
286 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
287 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
289 if (PsGetCurrentThread() != NULL
)
291 DbgPrint("Thrd: %x Tid: %x",
292 PsGetCurrentThread(),
293 PsGetCurrentThread()->Cid
.UniqueThread
);
296 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
297 OldTss
->Fs
, OldTss
->Gs
);
298 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
300 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss
->Edx
, OldTss
->Ebp
,
302 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
303 if (OldTss
->Cs
== KERNEL_CS
)
305 DbgPrint("kESP %.8x ", Esp0
);
306 if (PsGetCurrentThread() != NULL
)
308 DbgPrint("kernel stack base %x\n",
309 PsGetCurrentThread()->Tcb
.StackLimit
);
315 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
317 if ((OldTss
->Cs
& 0xffff) == KERNEL_CS
)
319 DbgPrint("ESP %x\n", Esp0
);
320 if (PsGetCurrentThread() != NULL
)
322 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
323 StackBase
= (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
;
327 StackLimit
= (ULONG
)&init_stack_top
;
328 StackBase
= (ULONG
)&init_stack
;
332 DbgPrint("Frames: ");
333 Frame
= (PULONG
)OldTss
->Ebp
;
334 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
336 print_address((PVOID
)Frame
[1]);
337 Frame
= (PULONG
)Frame
[0];
341 DbgPrint("Frames: ");
343 Frame
= (PULONG
)OldTss
->Ebp
;
344 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
346 StackTrace
[i
] = (PVOID
)Frame
[1];
347 Frame
= (PULONG
)Frame
[0];
353 while (i
< TraceLength
)
355 StackRepeatCount
[i
] = 0;
358 while ((j
- i
) <= (TraceLength
- j
) && FoundRepeat
== FALSE
)
360 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
361 (j
- i
) * sizeof(PVOID
)) == 0)
363 StackRepeatCount
[i
] = 2;
364 StackRepeatLength
[i
] = j
- i
;
372 if (FoundRepeat
== FALSE
)
377 j
= j
+ StackRepeatLength
[i
];
378 while ((TraceLength
- j
) >= StackRepeatLength
[i
] &&
381 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
382 StackRepeatLength
[i
] * sizeof(PVOID
)) == 0)
384 StackRepeatCount
[i
]++;
385 j
= j
+ StackRepeatLength
[i
];
396 while (i
< TraceLength
)
398 if (StackRepeatCount
[i
] == 0)
400 print_address(StackTrace
[i
]);
406 if (StackRepeatLength
[i
] == 0)
410 for (j
= 0; j
< StackRepeatLength
[i
]; j
++)
412 print_address(StackTrace
[i
+ j
]);
414 DbgPrint("}*%d", StackRepeatCount
[i
]);
415 i
= i
+ StackRepeatLength
[i
] * StackRepeatCount
[i
];
426 KiDumpTrapFrame(PKTRAP_FRAME Tf
, ULONG Parameter1
, ULONG Parameter2
)
433 ULONG ExceptionNr
= (ULONG
)Tf
->DebugArgMark
;
434 ULONG cr2
= (ULONG
)Tf
->DebugPointer
;
439 * Print out the CPU registers
441 if (ExceptionNr
< 19)
443 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
444 ExceptionNr
, Tf
->ErrorCode
&0xffff);
448 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrorCode
&0xffff);
450 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
451 Tf
->Cs
&0xffff, Tf
->Eip
);
452 print_address((PVOID
)Tf
->Eip
);
454 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3
));
455 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3
);
456 DbgPrint("Proc: %x ",PsGetCurrentProcess());
457 if (PsGetCurrentProcess() != NULL
)
459 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
460 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
462 if (PsGetCurrentThread() != NULL
)
464 DbgPrint("Thrd: %x Tid: %x",
465 PsGetCurrentThread(),
466 PsGetCurrentThread()->Cid
.UniqueThread
);
469 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->Ds
&0xffff, Tf
->Es
&0xffff,
470 Tf
->Fs
&0xffff, Tf
->Gs
&0xfff);
471 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
472 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf
->Edx
, Tf
->Ebp
, Tf
->Esi
);
473 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->Eflags
);
474 if ((Tf
->Cs
&0xffff) == KERNEL_CS
)
476 DbgPrint("kESP %.8x ", Esp0
);
477 if (PsGetCurrentThread() != NULL
)
479 DbgPrint("kernel stack base %x\n",
480 PsGetCurrentThread()->Tcb
.StackLimit
);
485 DbgPrint("ESP %x\n", Esp0
);
487 if (PsGetCurrentThread() != NULL
)
489 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
493 StackLimit
= (ULONG
)&init_stack_top
;
497 * Dump the stack frames
499 DbgPrint("Frames: ");
501 Frame
= (PULONG
)Tf
->Ebp
;
502 while (Frame
!= NULL
)
504 print_address((PVOID
)Frame
[1]);
505 Frame
= (PULONG
)Frame
[0];
512 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
514 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
515 * message and halt the computer
517 * Complete CPU context
524 /* Store the exception number in an unused field in the trap frame. */
525 Tf
->DebugArgMark
= (PVOID
)ExceptionNr
;
527 /* Use the address of the trap frame as approximation to the ring0 esp */
528 Esp0
= (ULONG
)&Tf
->Eip
;
531 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
532 Tf
->DebugPointer
= (PVOID
)cr2
;
535 * If this was a V86 mode exception then handle it specially
537 if (Tf
->Eflags
& (1 << 17))
539 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
543 * Check for stack underflow, this may be obsolete
545 if (PsGetCurrentThread() != NULL
&&
546 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
548 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
549 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
554 * Maybe handle the page fault and return
556 if (ExceptionNr
== 14)
559 Status
= MmPageFault(Tf
->Cs
&0xffff,
564 if (NT_SUCCESS(Status
))
572 * Handle user exceptions differently
574 if ((Tf
->Cs
& 0xFFFF) == USER_CS
)
576 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
580 return(KiKernelTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
585 KeDumpStackFrames(PULONG Frame
)
589 DbgPrint("Frames: ");
591 while (Frame
!= NULL
)
593 print_address((PVOID
)Frame
[1]);
594 Frame
= (PULONG
)Frame
[0];
600 static void set_system_call_gate(unsigned int sel
, unsigned int func
)
602 DPRINT("sel %x %d\n",sel
,sel
);
603 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
605 KiIdt
[sel
].b
= 0xef00 + (((int)func
)&0xffff0000);
606 DPRINT("idt[sel].b %x\n",KiIdt
[sel
].b
);
609 static void set_interrupt_gate(unsigned int sel
, unsigned int func
)
611 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel
,func
);
612 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
614 KiIdt
[sel
].b
= 0x8f00 + (((int)func
)&0xffff0000);
618 set_task_gate(unsigned int sel
, unsigned task_sel
)
620 KiIdt
[sel
].a
= task_sel
<< 16;
621 KiIdt
[sel
].b
= 0x8500;
625 KeInitExceptions(VOID
)
627 * FUNCTION: Initalize CPU exception handling
632 DPRINT("KeInitExceptions()\n");
635 * Set up the other gates
637 set_interrupt_gate(0, (ULONG
)KiTrap0
);
638 set_interrupt_gate(1, (ULONG
)KiTrap1
);
639 set_interrupt_gate(2, (ULONG
)KiTrap2
);
640 set_interrupt_gate(3, (ULONG
)KiTrap3
);
641 set_interrupt_gate(4, (ULONG
)KiTrap4
);
642 set_interrupt_gate(5, (ULONG
)KiTrap5
);
643 set_interrupt_gate(6, (ULONG
)KiTrap6
);
644 set_interrupt_gate(7, (ULONG
)KiTrap7
);
645 set_task_gate(8, TRAP_TSS_SELECTOR
);
646 set_interrupt_gate(9, (ULONG
)KiTrap9
);
647 set_interrupt_gate(10, (ULONG
)KiTrap10
);
648 set_interrupt_gate(11, (ULONG
)KiTrap11
);
649 set_interrupt_gate(12, (ULONG
)KiTrap12
);
650 set_interrupt_gate(13, (ULONG
)KiTrap13
);
651 set_interrupt_gate(14, (ULONG
)KiTrap14
);
652 set_interrupt_gate(15, (ULONG
)KiTrap15
);
653 set_interrupt_gate(16, (ULONG
)KiTrap16
);
657 set_interrupt_gate(i
,(int)KiTrapUnknown
);
660 set_system_call_gate(0x2d,(int)interrupt_handler2d
);
661 set_system_call_gate(0x2e,(int)interrupt_handler2e
);