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 * PROGRAMMERS: David Welch (welch@cwcom.net)
24 * Skywing (skywing@valhallalegends.com)
27 * 09/12/03: KeRaiseUserException added (Skywing).
30 /* INCLUDES *****************************************************************/
33 #include <ddk/ntddk.h>
34 #include <internal/ntoskrnl.h>
35 #include <internal/ke.h>
36 #include <internal/i386/segment.h>
37 #include <internal/i386/mm.h>
38 #include <internal/module.h>
39 #include <internal/mm.h>
40 #include <internal/ps.h>
41 #include <internal/trap.h>
42 #include <ntdll/ldr.h>
43 #include <internal/safe.h>
44 #include <internal/kd.h>
45 #include <internal/ldr.h>
48 #include <internal/debug.h>
50 /* GLOBALS *****************************************************************/
52 #define FLAG_IF (1<<9)
55 #define STR(x) _STR(x)
57 extern void interrupt_handler2e(void);
58 extern void interrupt_handler2d(void);
60 extern VOID
KiTrap0(VOID
);
61 extern VOID
KiTrap1(VOID
);
62 extern VOID
KiTrap2(VOID
);
63 extern VOID
KiTrap3(VOID
);
64 extern VOID
KiTrap4(VOID
);
65 extern VOID
KiTrap5(VOID
);
66 extern VOID
KiTrap6(VOID
);
67 extern VOID
KiTrap7(VOID
);
68 extern VOID
KiTrap8(VOID
);
69 extern VOID
KiTrap9(VOID
);
70 extern VOID
KiTrap10(VOID
);
71 extern VOID
KiTrap11(VOID
);
72 extern VOID
KiTrap12(VOID
);
73 extern VOID
KiTrap13(VOID
);
74 extern VOID
KiTrap14(VOID
);
75 extern VOID
KiTrap15(VOID
);
76 extern VOID
KiTrap16(VOID
);
77 extern VOID
KiTrapUnknown(VOID
);
79 extern ULONG init_stack
;
80 extern ULONG init_stack_top
;
82 static char *ExceptionTypeStrings
[] =
89 "BOUND range exceeded",
91 "No Math Coprocessor",
95 "Segment Not Present",
96 "Stack Segment Fault",
104 static NTSTATUS ExceptionToNtStatus
[] =
106 STATUS_INTEGER_DIVIDE_BY_ZERO
,
108 STATUS_ACCESS_VIOLATION
,
110 STATUS_INTEGER_OVERFLOW
,
111 STATUS_ARRAY_BOUNDS_EXCEEDED
,
112 STATUS_ILLEGAL_INSTRUCTION
,
113 STATUS_ACCESS_VIOLATION
, /* STATUS_FLT_INVALID_OPERATION */
114 STATUS_ACCESS_VIOLATION
,
115 STATUS_ACCESS_VIOLATION
,
116 STATUS_ACCESS_VIOLATION
,
117 STATUS_ACCESS_VIOLATION
,
118 STATUS_STACK_OVERFLOW
,
119 STATUS_ACCESS_VIOLATION
,
120 STATUS_ACCESS_VIOLATION
,
121 STATUS_ACCESS_VIOLATION
, /* STATUS_FLT_INVALID_OPERATION */
122 STATUS_DATATYPE_MISALIGNMENT
,
123 STATUS_ACCESS_VIOLATION
126 extern unsigned int _text_start__
, _text_end__
;
128 /* FUNCTIONS ****************************************************************/
131 print_address(PVOID address
)
133 PLIST_ENTRY current_entry
;
134 MODULE_TEXT_SECTION
* current
;
135 extern LIST_ENTRY ModuleTextListHead
;
136 ULONG_PTR RelativeAddress
;
138 current_entry
= ModuleTextListHead
.Flink
;
140 while (current_entry
!= &ModuleTextListHead
&&
141 current_entry
!= NULL
)
144 CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
146 if (address
>= (PVOID
)current
->Base
&&
147 address
< (PVOID
)(current
->Base
+ current
->Length
))
149 RelativeAddress
= (ULONG_PTR
) address
- current
->Base
;
150 DbgPrint("<%ws: %x>", current
->Name
, RelativeAddress
);
153 current_entry
= current_entry
->Flink
;
159 KiKernelTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
163 Er
.ExceptionFlags
= 0;
164 Er
.ExceptionRecord
= NULL
;
165 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
167 if (ExceptionNr
== 14)
169 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
170 Er
.NumberParameters
= 2;
171 Er
.ExceptionInformation
[0] = Tf
->ErrorCode
& 0x1;
172 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
176 if (ExceptionNr
< 16)
178 Er
.ExceptionCode
= ExceptionToNtStatus
[ExceptionNr
];
182 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
184 Er
.NumberParameters
= 0;
187 Er
.ExceptionFlags
= ((NTSTATUS
) STATUS_SINGLE_STEP
== (NTSTATUS
) Er
.ExceptionCode
188 || (NTSTATUS
) STATUS_BREAKPOINT
== (NTSTATUS
) Er
.ExceptionCode
) ?
189 EXCEPTION_NONCONTINUABLE
: 0;
191 KiDispatchException(&Er
, 0, Tf
, KernelMode
, TRUE
);
197 KiDoubleFaultHandler(VOID
)
203 ULONG ExceptionNr
= 8;
209 static PVOID StackTrace
[MM_STACK_SIZE
/ sizeof(PVOID
)];
210 static ULONG StackRepeatCount
[MM_STACK_SIZE
/ sizeof(PVOID
)];
211 static ULONG StackRepeatLength
[MM_STACK_SIZE
/ sizeof(PVOID
)];
216 OldTss
= KeGetCurrentKPCR()->TSS
;
220 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
222 if (PsGetCurrentThread() != NULL
&&
223 PsGetCurrentThread()->ThreadsProcess
!= NULL
)
226 PsGetCurrentThread()->ThreadsProcess
->Pcb
.DirectoryTableBase
.QuadPart
;
234 * Check for stack underflow
236 if (PsGetCurrentThread() != NULL
&&
237 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
239 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
240 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
245 * Print out the CPU registers
247 if (ExceptionNr
< 19)
249 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
254 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
256 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
257 print_address((PVOID
)OldTss
->Eip
);
259 DbgPrint("cr2 %x cr3 %x ", cr2
, OldCr3
);
260 DbgPrint("Proc: %x ",PsGetCurrentProcess());
261 if (PsGetCurrentProcess() != NULL
)
263 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
264 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
266 if (PsGetCurrentThread() != NULL
)
268 DbgPrint("Thrd: %x Tid: %x",
269 PsGetCurrentThread(),
270 PsGetCurrentThread()->Cid
.UniqueThread
);
273 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
274 OldTss
->Fs
, OldTss
->Gs
);
275 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
277 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss
->Edx
, OldTss
->Ebp
,
279 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
280 if (OldTss
->Cs
== KERNEL_CS
)
282 DbgPrint("kESP %.8x ", Esp0
);
283 if (PsGetCurrentThread() != NULL
)
285 DbgPrint("kernel stack base %x\n",
286 PsGetCurrentThread()->Tcb
.StackLimit
);
292 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
294 if ((OldTss
->Cs
& 0xffff) == KERNEL_CS
)
296 DbgPrint("ESP %x\n", Esp0
);
297 if (PsGetCurrentThread() != NULL
)
299 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
300 StackBase
= (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
;
304 StackLimit
= (ULONG
)&init_stack_top
;
305 StackBase
= (ULONG
)&init_stack
;
309 DbgPrint("Frames: ");
310 Frame
= (PULONG
)OldTss
->Ebp
;
311 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
313 print_address((PVOID
)Frame
[1]);
314 Frame
= (PULONG
)Frame
[0];
318 DbgPrint("Frames: ");
320 Frame
= (PULONG
)OldTss
->Ebp
;
321 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
323 StackTrace
[i
] = (PVOID
)Frame
[1];
324 Frame
= (PULONG
)Frame
[0];
330 while (i
< TraceLength
)
332 StackRepeatCount
[i
] = 0;
335 while ((j
- i
) <= (TraceLength
- j
) && FoundRepeat
== FALSE
)
337 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
338 (j
- i
) * sizeof(PVOID
)) == 0)
340 StackRepeatCount
[i
] = 2;
341 StackRepeatLength
[i
] = j
- i
;
349 if (FoundRepeat
== FALSE
)
354 j
= j
+ StackRepeatLength
[i
];
355 while ((TraceLength
- j
) >= StackRepeatLength
[i
] &&
358 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
359 StackRepeatLength
[i
] * sizeof(PVOID
)) == 0)
361 StackRepeatCount
[i
]++;
362 j
= j
+ StackRepeatLength
[i
];
373 while (i
< TraceLength
)
375 if (StackRepeatCount
[i
] == 0)
377 print_address(StackTrace
[i
]);
383 if (StackRepeatLength
[i
] == 0)
387 for (j
= 0; j
< StackRepeatLength
[i
]; j
++)
389 print_address(StackTrace
[i
+ j
]);
391 DbgPrint("}*%d", StackRepeatCount
[i
]);
392 i
= i
+ StackRepeatLength
[i
] * StackRepeatCount
[i
];
403 KiDumpTrapFrame(PKTRAP_FRAME Tf
, ULONG Parameter1
, ULONG Parameter2
)
410 ULONG ExceptionNr
= (ULONG
)Tf
->DebugArgMark
;
411 ULONG cr2
= (ULONG
)Tf
->DebugPointer
;
416 * Print out the CPU registers
418 if (ExceptionNr
< 19)
420 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
421 ExceptionNr
, Tf
->ErrorCode
&0xffff);
425 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrorCode
&0xffff);
427 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
428 Tf
->Cs
&0xffff, Tf
->Eip
);
429 print_address((PVOID
)Tf
->Eip
);
431 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3
));
432 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3
);
433 DbgPrint("Proc: %x ",PsGetCurrentProcess());
434 if (PsGetCurrentProcess() != NULL
)
436 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
437 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
439 if (PsGetCurrentThread() != NULL
)
441 DbgPrint("Thrd: %x Tid: %x",
442 PsGetCurrentThread(),
443 PsGetCurrentThread()->Cid
.UniqueThread
);
446 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->Ds
&0xffff, Tf
->Es
&0xffff,
447 Tf
->Fs
&0xffff, Tf
->Gs
&0xfff);
448 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
449 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf
->Edx
, Tf
->Ebp
, Tf
->Esi
);
450 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->Eflags
);
451 if ((Tf
->Cs
&0xffff) == KERNEL_CS
)
453 DbgPrint("kESP %.8x ", Esp0
);
454 if (PsGetCurrentThread() != NULL
)
456 DbgPrint("kernel stack base %x\n",
457 PsGetCurrentThread()->Tcb
.StackLimit
);
462 DbgPrint("ESP %x\n", Esp0
);
464 if (PsGetCurrentThread() != NULL
)
466 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
470 StackLimit
= (ULONG
)&init_stack_top
;
474 * Dump the stack frames
476 DbgPrint("Frames: ");
478 Frame
= (PULONG
)Tf
->Ebp
;
479 while (Frame
!= NULL
)
481 print_address((PVOID
)Frame
[1]);
482 Frame
= (PULONG
)Frame
[0];
489 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
491 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
492 * message and halt the computer
494 * Complete CPU context
501 /* Store the exception number in an unused field in the trap frame. */
502 Tf
->DebugArgMark
= (PVOID
)ExceptionNr
;
504 /* Use the address of the trap frame as approximation to the ring0 esp */
505 Esp0
= (ULONG
)&Tf
->Eip
;
508 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
509 Tf
->DebugPointer
= (PVOID
)cr2
;
512 * If this was a V86 mode exception then handle it specially
514 if (Tf
->Eflags
& (1 << 17))
516 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
520 * Check for stack underflow, this may be obsolete
522 if (PsGetCurrentThread() != NULL
&&
523 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
525 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
526 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
531 * Maybe handle the page fault and return
533 if (ExceptionNr
== 14)
535 if (Tf
->Eflags
& FLAG_IF
)
539 Status
= MmPageFault(Tf
->Cs
&0xffff,
544 if (NT_SUCCESS(Status
))
551 * Handle user exceptions differently
553 if ((Tf
->Cs
& 0xFFFF) == USER_CS
)
555 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
559 return(KiKernelTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
564 KeDumpStackFrames(PULONG Frame
)
568 DbgPrint("Frames: ");
570 while (Frame
!= NULL
)
572 print_address((PVOID
)Frame
[1]);
573 Frame
= (PULONG
)Frame
[0];
579 static void set_system_call_gate(unsigned int sel
, unsigned int func
)
581 DPRINT("sel %x %d\n",sel
,sel
);
582 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
584 KiIdt
[sel
].b
= 0xef00 + (((int)func
)&0xffff0000);
585 DPRINT("idt[sel].b %x\n",KiIdt
[sel
].b
);
588 static void set_interrupt_gate(unsigned int sel
, unsigned int func
)
590 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel
,func
);
591 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
593 KiIdt
[sel
].b
= 0x8e00 + (((int)func
)&0xffff0000);
596 static void set_trap_gate(unsigned int sel
, unsigned int func
, unsigned int dpl
)
598 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel
, func
, dpl
);
600 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
602 KiIdt
[sel
].b
= 0x8f00 + (dpl
<< 13) + (((int)func
)&0xffff0000);
606 set_task_gate(unsigned int sel
, unsigned task_sel
)
608 KiIdt
[sel
].a
= task_sel
<< 16;
609 KiIdt
[sel
].b
= 0x8500;
613 KeInitExceptions(VOID
)
615 * FUNCTION: Initalize CPU exception handling
620 DPRINT("KeInitExceptions()\n");
623 * Set up the other gates
625 set_trap_gate(0, (ULONG
)KiTrap0
, 0);
626 set_trap_gate(1, (ULONG
)KiTrap1
, 0);
627 set_trap_gate(2, (ULONG
)KiTrap2
, 0);
628 set_trap_gate(3, (ULONG
)KiTrap3
, 3);
629 set_trap_gate(4, (ULONG
)KiTrap4
, 0);
630 set_trap_gate(5, (ULONG
)KiTrap5
, 0);
631 set_trap_gate(6, (ULONG
)KiTrap6
, 0);
632 set_trap_gate(7, (ULONG
)KiTrap7
, 0);
633 set_task_gate(8, TRAP_TSS_SELECTOR
);
634 set_trap_gate(9, (ULONG
)KiTrap9
, 0);
635 set_trap_gate(10, (ULONG
)KiTrap10
, 0);
636 set_trap_gate(11, (ULONG
)KiTrap11
, 0);
637 set_trap_gate(12, (ULONG
)KiTrap12
, 0);
638 set_trap_gate(13, (ULONG
)KiTrap13
, 0);
639 set_interrupt_gate(14, (ULONG
)KiTrap14
);
640 set_trap_gate(15, (ULONG
)KiTrap15
, 0);
641 set_trap_gate(16, (ULONG
)KiTrap16
, 0);
645 set_trap_gate(i
,(int)KiTrapUnknown
, 0);
648 set_system_call_gate(0x2d,(int)interrupt_handler2d
);
649 set_system_call_gate(0x2e,(int)interrupt_handler2e
);
657 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
659 /* FIXME: This needs SEH */
661 PKTHREAD Thread
= KeGetCurrentThread();
663 ProbeForWrite(&Thread
->Teb
->ExceptionCode
, sizeof(NTSTATUS
), sizeof(NTSTATUS
)); /* NT doesn't check this -- bad? */
664 Thread
->TrapFrame
->Eip
= (ULONG_PTR
)LdrpGetSystemDllRaiseExceptionDispatcher();
665 Thread
->Teb
->ExceptionCode
= ExceptionCode
;