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>
31 #include <internal/config.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>
43 #include <internal/debug.h>
45 /* GLOBALS *****************************************************************/
48 #define STR(x) _STR(x)
50 extern void interrupt_handler2e(void);
51 extern void interrupt_handler2d(void);
53 extern VOID
KiTrap0(VOID
);
54 extern VOID
KiTrap1(VOID
);
55 extern VOID
KiTrap2(VOID
);
56 extern VOID
KiTrap3(VOID
);
57 extern VOID
KiTrap4(VOID
);
58 extern VOID
KiTrap5(VOID
);
59 extern VOID
KiTrap6(VOID
);
60 extern VOID
KiTrap7(VOID
);
61 extern VOID
KiTrap8(VOID
);
62 extern VOID
KiTrap9(VOID
);
63 extern VOID
KiTrap10(VOID
);
64 extern VOID
KiTrap11(VOID
);
65 extern VOID
KiTrap12(VOID
);
66 extern VOID
KiTrap13(VOID
);
67 extern VOID
KiTrap14(VOID
);
68 extern VOID
KiTrap15(VOID
);
69 extern VOID
KiTrap16(VOID
);
70 extern VOID
KiTrapUnknown(VOID
);
72 extern ULONG init_stack
;
73 extern ULONG init_stack_top
;
75 static char *ExceptionTypeStrings
[] =
82 "BOUND range exceeded",
84 "No Math Coprocessor",
88 "Segment Not Present",
89 "Stack Segment Fault",
97 /* FUNCTIONS ****************************************************************/
99 extern unsigned int _text_start__
, _text_end__
;
102 print_kernel_address(PVOID address
)
106 PSYMBOL Symbol
, NextSymbol
;
107 BOOLEAN Printed
= FALSE
;
110 PLIST_ENTRY current_entry
;
111 MODULE_TEXT_SECTION
* current
;
112 extern LIST_ENTRY ModuleTextListHead
;
114 current_entry
= ModuleTextListHead
.Flink
;
116 while (current_entry
!= &ModuleTextListHead
&&
117 current_entry
!= NULL
)
120 CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
122 if (address
>= (PVOID
)current
->Base
&&
123 address
< (PVOID
)(current
->Base
+ current
->Length
))
128 Offset
= (ULONG
)((ULONG
)address
- current
->Base
);
129 Symbol
= current
->Symbols
.Symbols
;
130 while (Symbol
!= NULL
)
132 NextSymbol
= Symbol
->Next
;
133 if (NextSymbol
!= NULL
)
134 NextAddress
= NextSymbol
->RelativeAddress
;
136 NextAddress
= current
->Length
;
138 if ((Offset
>= Symbol
->RelativeAddress
) &&
139 (Offset
< NextAddress
))
141 DbgPrint("<%ws: %x (%wZ)>", current
->Name
, Offset
, &Symbol
->Name
);
148 DbgPrint("<%ws: %x>", current
->Name
, Offset
);
152 DbgPrint("<%ws: %x>", current
->Name
,
153 address
- current
->Base
);
160 current_entry
= current_entry
->Flink
;
166 print_user_address(PVOID address
)
170 PSYMBOL Symbol
, NextSymbol
;
171 BOOLEAN Printed
= FALSE
;
174 PLIST_ENTRY current_entry
;
176 PEPROCESS CurrentProcess
;
179 CurrentProcess
= PsGetCurrentProcess();
180 if (NULL
!= CurrentProcess
)
182 Peb
= CurrentProcess
->Peb
;
187 DbgPrint("<%x>", address
);
191 current_entry
= Peb
->Ldr
->InLoadOrderModuleList
.Flink
;
193 while (current_entry
!= &Peb
->Ldr
->InLoadOrderModuleList
&&
194 current_entry
!= NULL
)
197 CONTAINING_RECORD(current_entry
, LDR_MODULE
, InLoadOrderModuleList
);
199 if (address
>= (PVOID
)current
->BaseAddress
&&
200 address
< (PVOID
)(current
->BaseAddress
+ current
->SizeOfImage
))
204 Offset
= (ULONG
)(address
- current
->BaseAddress
);
205 Symbol
= current
->Symbols
.Symbols
;
206 while (Symbol
!= NULL
)
208 NextSymbol
= Symbol
->Next
;
209 if (NextSymbol
!= NULL
)
210 NextAddress
= NextSymbol
->RelativeAddress
;
212 NextAddress
= current
->SizeOfImage
;
214 if ((Offset
>= Symbol
->RelativeAddress
) &&
215 (Offset
< NextAddress
))
217 DbgPrint("<%wZ: %x (%wZ)>",
218 ¤t
->BaseDllName
, Offset
, &Symbol
->Name
);
225 DbgPrint("<%wZ: %x>", ¤t
->BaseDllName
, Offset
);
229 DbgPrint("<%wZ: %x>", ¤t
->BaseDllName
,
230 address
- current
->BaseAddress
);
237 current_entry
= current_entry
->Flink
;
243 print_address(PVOID address
)
245 /* FIXME: There is a variable with this value somewhere...use it */
246 if ((ULONG
)address
>= 0xc0000000)
248 return print_kernel_address(address
);
252 return print_user_address(address
);
258 KiUserTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
262 if (ExceptionNr
== 0)
264 Er
.ExceptionCode
= STATUS_INTEGER_DIVIDE_BY_ZERO
;
266 else if (ExceptionNr
== 1)
268 Er
.ExceptionCode
= STATUS_SINGLE_STEP
;
270 else if (ExceptionNr
== 3)
272 Er
.ExceptionCode
= STATUS_BREAKPOINT
;
274 else if (ExceptionNr
== 4)
276 Er
.ExceptionCode
= STATUS_INTEGER_OVERFLOW
;
278 else if (ExceptionNr
== 5)
280 Er
.ExceptionCode
= STATUS_ARRAY_BOUNDS_EXCEEDED
;
282 else if (ExceptionNr
== 6)
284 Er
.ExceptionCode
= STATUS_ILLEGAL_INSTRUCTION
;
288 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
290 Er
.ExceptionFlags
= 0;
291 Er
.ExceptionRecord
= NULL
;
292 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
293 if (ExceptionNr
== 14)
295 Er
.NumberParameters
= 2;
296 Er
.ExceptionInformation
[0] = Tf
->ErrorCode
& 0x1;
297 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
301 Er
.NumberParameters
= 0;
305 KiDispatchException(&Er
, 0, Tf
, UserMode
, TRUE
);
311 KiUserTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
320 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3
));
323 * Print out the CPU registers
325 if (ExceptionNr
< 19)
327 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
328 ExceptionNr
, Tf
->ErrorCode
&0xffff);
332 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrorCode
&0xffff);
334 DbgPrint("CS:EIP %x:%x ", Tf
->Cs
&0xffff, Tf
->Eip
);
335 print_address((PVOID
)Tf
->Eip
);
337 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3
));
338 DbgPrint("CR2 %x CR3 %x ", Cr2
, cr3
);
339 DbgPrint("Process: %x ",PsGetCurrentProcess());
340 if (PsGetCurrentProcess() != NULL
)
342 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
343 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
345 if (PsGetCurrentThread() != NULL
)
347 DbgPrint("Thrd: %x Tid: %x",
348 PsGetCurrentThread(),
349 PsGetCurrentThread()->Cid
.UniqueThread
);
352 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->Ds
&0xffff, Tf
->Es
&0xffff,
353 Tf
->Fs
&0xffff, Tf
->Gs
&0xfff);
354 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
355 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf
->Edx
, Tf
->Ebp
, Tf
->Esi
);
356 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->Eflags
);
357 DbgPrint("SS:ESP %x:%x\n", Tf
->Ss
, Tf
->Esp
);
360 stack
=(PULONG
)(Tf
->Esp
);
362 DbgPrint("Stack:\n");
365 if (MmIsPagePresent(NULL
,&stack
[i
]))
367 DbgPrint("%.8x ",stack
[i
]);
377 if (MmIsPagePresent(NULL
, (PVOID
)Tf
->Eip
))
379 unsigned char instrs
[512];
381 memcpy(instrs
, (PVOID
)Tf
->Eip
, 512);
383 DbgPrint("Instrs: ");
387 DbgPrint("%x ", instrs
[i
]);
393 * Dump the stack frames
395 DbgPrint("Frames: ");
397 Frame
= (PULONG
)Tf
->Ebp
;
398 while (Frame
!= NULL
)
400 print_address((PVOID
)Frame
[1]);
401 Frame
= (PULONG
)Frame
[0];
406 * Kill the faulting task
409 ZwTerminateProcess(NtCurrentProcess(),
410 STATUS_NONCONTINUABLE_EXCEPTION
);
413 * If terminating the process fails then bugcheck
420 KiDoubleFaultHandler(VOID
)
427 ULONG ExceptionNr
= 8;
430 /* Use the address of the trap frame as approximation to the ring0 esp */
431 OldTss
= KeGetCurrentKPCR()->TSS
;
435 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
438 * Check for stack underflow
440 if (PsGetCurrentThread() != NULL
&&
441 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
443 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
444 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
449 * Print out the CPU registers
451 if (ExceptionNr
< 19)
453 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
458 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
460 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
461 print_address((PVOID
)OldTss
->Eip
);
463 DbgPrint("cr2 %x cr3 %x ", cr2
, OldTss
->Cr3
);
464 DbgPrint("Proc: %x ",PsGetCurrentProcess());
465 if (PsGetCurrentProcess() != NULL
)
467 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
468 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
470 if (PsGetCurrentThread() != NULL
)
472 DbgPrint("Thrd: %x Tid: %x",
473 PsGetCurrentThread(),
474 PsGetCurrentThread()->Cid
.UniqueThread
);
477 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
478 OldTss
->Fs
, OldTss
->Gs
);
479 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
481 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss
->Edx
, OldTss
->Ebp
,
483 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
484 if (OldTss
->Cs
== KERNEL_CS
)
486 DbgPrint("kESP %.8x ", Esp0
);
487 if (PsGetCurrentThread() != NULL
)
489 DbgPrint("kernel stack base %x\n",
490 PsGetCurrentThread()->Tcb
.StackLimit
);
496 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
498 if ((OldTss
->Cs
& 0xffff) == KERNEL_CS
)
500 DbgPrint("ESP %x\n", Esp0
);
501 stack
= (PULONG
) (Esp0
+ 24);
502 stack
= (PULONG
)(((ULONG
)stack
) & (~0x3));
503 if (PsGetCurrentThread() != NULL
)
505 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
509 StackLimit
= (ULONG
)&init_stack_top
;
512 DbgPrint("stack<%p>: ", stack
);
514 for (i
= 0; i
< 18 && (((ULONG
)&stack
[i
+5]) < StackLimit
); i
= i
+ 6)
516 DbgPrint("%.8x %.8x %.8x %.8x\n",
517 stack
[i
], stack
[i
+1],
518 stack
[i
+2], stack
[i
+3],
519 stack
[i
+4], stack
[i
+5]);
521 DbgPrint("Frames:\n");
522 for (i
= 0; i
< 32 && (((ULONG
)&stack
[i
]) < StackLimit
); i
++)
524 if (stack
[i
] > ((unsigned int) &_text_start__
) &&
525 !(stack
[i
] >= ((ULONG
)&init_stack
) &&
526 stack
[i
] <= ((ULONG
)&init_stack_top
)))
528 print_address((PVOID
)stack
[i
]);
539 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
541 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
542 * message and halt the computer
544 * Complete CPU context
547 unsigned int cr2
, cr3
;
549 // unsigned int j, sym;
555 /* Use the address of the trap frame as approximation to the ring0 esp */
556 Esp0
= (ULONG
)&Tf
->Eip
;
559 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
562 * If this was a V86 mode exception then handle it specially
564 if (Tf
->Eflags
& (1 << 17))
566 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
570 * Check for stack underflow, this may be obsolete
572 if (PsGetCurrentThread() != NULL
&&
573 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
575 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
576 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
581 * Maybe handle the page fault and return
583 if (ExceptionNr
== 14)
586 Status
= MmPageFault(Tf
->Cs
&0xffff,
591 if (NT_SUCCESS(Status
))
598 * Handle user exceptions differently
600 if ((Tf
->Cs
& 0xFFFF) == USER_CS
)
602 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
606 * Print out the CPU registers
608 if (ExceptionNr
< 19)
610 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
611 ExceptionNr
, Tf
->ErrorCode
&0xffff);
615 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrorCode
&0xffff);
617 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
618 Tf
->Cs
&0xffff, Tf
->Eip
);
619 print_address((PVOID
)Tf
->Eip
);
621 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3
));
622 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3
);
623 DbgPrint("Proc: %x ",PsGetCurrentProcess());
624 if (PsGetCurrentProcess() != NULL
)
626 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
627 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
629 if (PsGetCurrentThread() != NULL
)
631 DbgPrint("Thrd: %x Tid: %x",
632 PsGetCurrentThread(),
633 PsGetCurrentThread()->Cid
.UniqueThread
);
636 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->Ds
&0xffff, Tf
->Es
&0xffff,
637 Tf
->Fs
&0xffff, Tf
->Gs
&0xfff);
638 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
639 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf
->Edx
, Tf
->Ebp
, Tf
->Esi
);
640 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->Eflags
);
641 if ((Tf
->Cs
&0xffff) == KERNEL_CS
)
643 DbgPrint("kESP %.8x ", Esp0
);
644 if (PsGetCurrentThread() != NULL
)
646 DbgPrint("kernel stack base %x\n",
647 PsGetCurrentThread()->Tcb
.StackLimit
);
652 DbgPrint("ESP %x\n", Esp0
);
654 if (PsGetCurrentThread() != NULL
)
656 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
660 StackLimit
= (ULONG
)&init_stack_top
;
664 * Dump the stack frames
666 DbgPrint("Frames: ");
668 Frame
= (PULONG
)Tf
->Ebp
;
669 while (Frame
!= NULL
)
671 print_address((PVOID
)Frame
[1]);
672 Frame
= (PULONG
)Frame
[0];
684 KeDumpStackFrames(PULONG Frame
)
688 DbgPrint("Frames: ");
690 while (Frame
!= NULL
)
692 print_address((PVOID
)Frame
[1]);
693 Frame
= (PULONG
)Frame
[0];
702 static void set_system_call_gate(unsigned int sel
, unsigned int func
)
704 DPRINT("sel %x %d\n",sel
,sel
);
705 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
707 KiIdt
[sel
].b
= 0xef00 + (((int)func
)&0xffff0000);
708 DPRINT("idt[sel].b %x\n",KiIdt
[sel
].b
);
711 static void set_interrupt_gate(unsigned int sel
, unsigned int func
)
713 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel
,func
);
714 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
716 KiIdt
[sel
].b
= 0x8f00 + (((int)func
)&0xffff0000);
720 set_task_gate(unsigned int sel
, unsigned task_sel
)
722 KiIdt
[sel
].a
= task_sel
<< 16;
723 KiIdt
[sel
].b
= 0x8500;
727 KeInitExceptions(VOID
)
729 * FUNCTION: Initalize CPU exception handling
734 DPRINT("KeInitExceptions()\n");
737 * Set up the other gates
739 set_interrupt_gate(0, (ULONG
)KiTrap0
);
740 set_interrupt_gate(1, (ULONG
)KiTrap1
);
741 set_interrupt_gate(2, (ULONG
)KiTrap2
);
742 set_interrupt_gate(3, (ULONG
)KiTrap3
);
743 set_interrupt_gate(4, (ULONG
)KiTrap4
);
744 set_interrupt_gate(5, (ULONG
)KiTrap5
);
745 set_interrupt_gate(6, (ULONG
)KiTrap6
);
746 set_interrupt_gate(7, (ULONG
)KiTrap7
);
747 set_task_gate(8, TRAP_TSS_SELECTOR
);
748 set_interrupt_gate(9, (ULONG
)KiTrap9
);
749 set_interrupt_gate(10, (ULONG
)KiTrap10
);
750 set_interrupt_gate(11, (ULONG
)KiTrap11
);
751 set_interrupt_gate(12, (ULONG
)KiTrap12
);
752 set_interrupt_gate(13, (ULONG
)KiTrap13
);
753 set_interrupt_gate(14, (ULONG
)KiTrap14
);
754 set_interrupt_gate(15, (ULONG
)KiTrap15
);
755 set_interrupt_gate(16, (ULONG
)KiTrap16
);
759 set_interrupt_gate(i
,(int)KiTrapUnknown
);
762 set_system_call_gate(0x2d,(int)interrupt_handler2d
);
763 set_system_call_gate(0x2e,(int)interrupt_handler2e
);