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/ntoskrnl.h>
32 #include <internal/ke.h>
33 #include <internal/i386/segment.h>
34 #include <internal/i386/mm.h>
35 #include <internal/module.h>
36 #include <internal/mm.h>
37 #include <internal/ps.h>
38 #include <internal/trap.h>
41 #include <internal/debug.h>
43 /* GLOBALS *****************************************************************/
46 #define STR(x) _STR(x)
48 extern void interrupt_handler2e(void);
49 extern void interrupt_handler2d(void);
51 extern VOID
KiTrap0(VOID
);
52 extern VOID
KiTrap1(VOID
);
53 extern VOID
KiTrap2(VOID
);
54 extern VOID
KiTrap3(VOID
);
55 extern VOID
KiTrap4(VOID
);
56 extern VOID
KiTrap5(VOID
);
57 extern VOID
KiTrap6(VOID
);
58 extern VOID
KiTrap7(VOID
);
59 extern VOID
KiTrap8(VOID
);
60 extern VOID
KiTrap9(VOID
);
61 extern VOID
KiTrap10(VOID
);
62 extern VOID
KiTrap11(VOID
);
63 extern VOID
KiTrap12(VOID
);
64 extern VOID
KiTrap13(VOID
);
65 extern VOID
KiTrap14(VOID
);
66 extern VOID
KiTrap15(VOID
);
67 extern VOID
KiTrap16(VOID
);
68 extern VOID
KiTrapUnknown(VOID
);
70 extern ULONG init_stack
;
71 extern ULONG init_stack_top
;
73 static char KiNullLdt
[8] = {0,};
75 /* FUNCTIONS ****************************************************************/
77 extern unsigned int _text_start__
, _text_end__
;
80 print_address(PVOID address
)
82 PLIST_ENTRY current_entry
;
83 MODULE_TEXT_SECTION
* current
;
84 extern LIST_ENTRY ModuleTextListHead
;
86 current_entry
= ModuleTextListHead
.Flink
;
88 while (current_entry
!= &ModuleTextListHead
&&
89 current_entry
!= NULL
)
92 CONTAINING_RECORD(current_entry
, MODULE_TEXT_SECTION
, ListEntry
);
94 if (address
>= (PVOID
)current
->Base
&&
95 address
< (PVOID
)(current
->Base
+ current
->Length
))
97 DbgPrint("<%ws: %x>", current
->Name
,
98 address
- current
->Base
);
102 current_entry
= current_entry
->Flink
;
105 DbgPrint("<%x>", address
);
111 KiUserTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
115 if (ExceptionNr
== 0)
117 Er
.ExceptionCode
= STATUS_INTEGER_DIVIDE_BY_ZERO
;
119 else if (ExceptionNr
== 1)
121 Er
.ExceptionCode
= STATUS_SINGLE_STEP
;
123 else if (ExceptionNr
== 3)
125 Er
.ExceptionCode
= STATUS_BREAKPOINT
;
127 else if (ExceptionNr
== 4)
129 Er
.ExceptionCode
= STATUS_INTEGER_OVERFLOW
;
131 else if (ExceptionNr
== 5)
133 Er
.ExceptionCode
= STATUS_ARRAY_BOUNDS_EXCEEDED
;
135 else if (ExceptionNr
== 6)
137 Er
.ExceptionCode
= STATUS_ILLEGAL_INSTRUCTION
;
141 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
143 Er
.ExceptionFlags
= 0;
144 Er
.ExceptionRecord
= NULL
;
145 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
146 if (ExceptionNr
== 14)
148 Er
.NumberParameters
= 2;
149 Er
.ExceptionInformation
[0] = Tf
->ErrorCode
& 0x1;
150 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
154 Er
.NumberParameters
= 0;
158 KiDispatchException(&Er
, 0, Tf
, UserMode
, TRUE
);
163 KiDoubleFaultHandler(VOID
)
170 ULONG ExceptionNr
= 8;
172 static char *TypeStrings
[] =
179 "BOUND range exceeded",
181 "No Math Coprocessor",
185 "Segment Not Present",
186 "Stack Segment Fault",
187 "General Protection",
194 /* Use the address of the trap frame as approximation to the ring0 esp */
198 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
201 * Check for stack underflow
203 if (PsGetCurrentThread() != NULL
&&
204 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
206 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
207 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
212 * Print out the CPU registers
214 if (ExceptionNr
< 19)
216 DbgPrint("%s Exception: %d(%x)\n",TypeStrings
[ExceptionNr
],
221 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
223 DbgPrint("CS:EIP %x:%x ", KiTss
.Cs
, KiTss
.Eip
);
224 print_address((PVOID
)KiTss
.Eip
);
226 DbgPrint("cr2 %x cr3 %x ", cr2
, KiTss
.Cr3
);
227 DbgPrint("Proc: %x ",PsGetCurrentProcess());
228 if (PsGetCurrentProcess() != NULL
)
230 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
231 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
233 if (PsGetCurrentThread() != NULL
)
235 DbgPrint("Thrd: %x Tid: %x",
236 PsGetCurrentThread(),
237 PsGetCurrentThread()->Cid
.UniqueThread
);
240 DbgPrint("DS %x ES %x FS %x GS %x\n", KiTss
.Ds
, KiTss
.Es
,
242 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", KiTss
.Eax
, KiTss
.Ebx
,
244 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", KiTss
.Edx
, KiTss
.Ebp
,
246 DbgPrint("EDI: %.8x EFLAGS: %.8x ", KiTss
.Edi
, KiTss
.Eflags
);
247 if (KiTss
.Cs
== KERNEL_CS
)
249 DbgPrint("kESP %.8x ", Esp0
);
250 if (PsGetCurrentThread() != NULL
)
252 DbgPrint("kernel stack base %x\n",
253 PsGetCurrentThread()->Tcb
.StackLimit
);
259 DbgPrint("User ESP %.8x\n", KiTss
.Esp
);
261 if ((KiTss
.Cs
& 0xffff) == KERNEL_CS
)
263 DbgPrint("ESP %x\n", Esp0
);
264 stack
= (PULONG
) (Esp0
+ 24);
265 stack
= (PULONG
)(((ULONG
)stack
) & (~0x3));
266 if (PsGetCurrentThread() != NULL
)
268 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
272 StackLimit
= (ULONG
)&init_stack_top
;
275 DbgPrint("stack<%p>: ", stack
);
277 for (i
= 0; i
< 18 && (((ULONG
)&stack
[i
+5]) < StackLimit
); i
= i
+ 6)
279 DbgPrint("%.8x %.8x %.8x %.8x\n",
280 stack
[i
], stack
[i
+1],
281 stack
[i
+2], stack
[i
+3],
282 stack
[i
+4], stack
[i
+5]);
284 DbgPrint("Frames:\n");
285 for (i
= 0; i
< 32 && (((ULONG
)&stack
[i
]) < StackLimit
); i
++)
287 if (stack
[i
] > ((unsigned int) &_text_start__
) &&
288 !(stack
[i
] >= ((ULONG
)&init_stack
) &&
289 stack
[i
] <= ((ULONG
)&init_stack_top
)))
291 print_address((PVOID
)stack
[i
]);
302 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
304 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
305 * message and halt the computer
307 * Complete CPU context
310 unsigned int cr2
, cr3
;
312 // unsigned int j, sym;
317 static char *TypeStrings
[] =
324 "BOUND range exceeded",
326 "No Math Coprocessor",
330 "Segment Not Present",
331 "Stack Segment Fault",
332 "General Protection",
339 /* Use the address of the trap frame as approximation to the ring0 esp */
340 Esp0
= (ULONG
)&Tf
->Eip
;
343 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2
));
346 * If this was a V86 mode exception then handle it specially
348 if (Tf
->Eflags
& (1 << 17))
350 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
354 * Check for stack underflow
356 if (PsGetCurrentThread() != NULL
&&
357 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
359 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
360 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
364 if (ExceptionNr
== 14)
367 Status
= MmPageFault(Tf
->Cs
&0xffff,
372 if (NT_SUCCESS(Status
))
379 if ((Tf
->Cs
& 0xFFFF) == USER_CS
)
381 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
386 * Print out the CPU registers
388 if (ExceptionNr
< 19)
390 DbgPrint("%s Exception: %d(%x)\n",TypeStrings
[ExceptionNr
],
391 ExceptionNr
, Tf
->ErrorCode
&0xffff);
395 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrorCode
&0xffff);
397 DbgPrint("CS:EIP %x:%x ", Tf
->Cs
&0xffff, Tf
->Eip
);
398 print_address((PVOID
)Tf
->Eip
);
400 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3
));
401 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3
);
402 DbgPrint("Proc: %x ",PsGetCurrentProcess());
403 if (PsGetCurrentProcess() != NULL
)
405 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
406 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName
);
408 if (PsGetCurrentThread() != NULL
)
410 DbgPrint("Thrd: %x Tid: %x",
411 PsGetCurrentThread(),
412 PsGetCurrentThread()->Cid
.UniqueThread
);
415 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->Ds
&0xffff, Tf
->Es
&0xffff,
416 Tf
->Fs
&0xffff, Tf
->Gs
&0xfff);
417 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
418 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf
->Edx
, Tf
->Ebp
, Tf
->Esi
);
419 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->Eflags
);
420 if ((Tf
->Cs
&0xffff) == KERNEL_CS
)
422 DbgPrint("kESP %.8x ", Esp0
);
423 if (PsGetCurrentThread() != NULL
)
425 DbgPrint("kernel stack base %x\n",
426 PsGetCurrentThread()->Tcb
.StackLimit
);
432 DbgPrint("User ESP %.8x\n", Tf
->Esp
);
434 if ((Tf
->Cs
& 0xffff) == KERNEL_CS
)
436 DbgPrint("ESP %x\n", Esp0
);
437 stack
= (PULONG
) (Esp0
+ 24);
438 stack
= (PULONG
)(((ULONG
)stack
) & (~0x3));
440 DbgPrint("stack<%p>: ", stack
);
442 if (PsGetCurrentThread() != NULL
)
444 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
448 StackLimit
= (ULONG
)&init_stack_top
;
451 for (i
= 0; i
< 18; i
= i
+ 6)
453 DbgPrint("%.8x %.8x %.8x %.8x\n",
454 stack
[i
], stack
[i
+1],
455 stack
[i
+2], stack
[i
+3],
456 stack
[i
+4], stack
[i
+5]);
458 DbgPrint("Frames:\n");
459 for (i
= 0; i
< 32 && ((ULONG
)&stack
[i
] < StackLimit
); i
++)
461 if (stack
[i
] > ((unsigned int) &_text_start__
) &&
462 !(stack
[i
] >= ((ULONG
)&init_stack
) &&
463 stack
[i
] <= ((ULONG
)&init_stack_top
)))
465 // DbgPrint(" %.8x", stack[i]);
466 print_address((PVOID
)stack
[i
]);
474 DbgPrint("SS:ESP %x:%x\n", Tf
->Ss
, Tf
->Esp
);
475 stack
=(PULONG
)(Tf
->Esp
);
477 DbgPrint("Stack:\n");
480 if (MmIsPagePresent(NULL
,&stack
[i
]))
482 DbgPrint("%.8x ",stack
[i
]);
490 if (MmIsPagePresent(NULL
, (PVOID
)Tf
->Eip
))
492 unsigned char instrs
[512];
494 memcpy(instrs
, (PVOID
)Tf
->Eip
, 512);
496 DbgPrint("Instrs: ");
500 DbgPrint("%x ", instrs
[i
]);
507 if ((Tf
->Cs
&0xffff) == USER_CS
&&
508 Tf
->Eip
< KERNEL_BASE
)
510 DbgPrint("Killing current task\n");
511 KeLowerIrql(PASSIVE_LEVEL
);
512 if ((Tf
->Cs
&0xffff) == USER_CS
)
514 ZwTerminateProcess(NtCurrentProcess(),
515 STATUS_NONCONTINUABLE_EXCEPTION
);
522 KeDumpStackFrames(PVOID _Stack
, ULONG NrFrames
)
524 PULONG Stack
= (PULONG
)_Stack
;
528 Stack
= (PVOID
)(((ULONG
)Stack
) & (~0x3));
529 DbgPrint("Stack: %x\n", Stack
);
530 if (PsGetCurrentThread() != NULL
)
532 DbgPrint("kernel stack base %x\n",
533 PsGetCurrentThread()->Tcb
.StackLimit
);
536 if (PsGetCurrentThread() != NULL
)
538 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
542 StackLimit
= (ULONG
)&init_stack_top
;
545 DbgPrint("Frames:\n");
546 for (i
=0; i
<NrFrames
&& ((ULONG
)&Stack
[i
] < StackLimit
); i
++)
548 if (Stack
[i
] > KERNEL_BASE
)
550 print_address((PVOID
)Stack
[i
]);
553 if (Stack
[i
] == 0xceafbeef)
561 static void set_system_call_gate(unsigned int sel
, unsigned int func
)
563 DPRINT("sel %x %d\n",sel
,sel
);
564 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
566 KiIdt
[sel
].b
= 0xef00 + (((int)func
)&0xffff0000);
567 DPRINT("idt[sel].b %x\n",KiIdt
[sel
].b
);
570 static void set_interrupt_gate(unsigned int sel
, unsigned int func
)
572 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel
,func
);
573 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
575 KiIdt
[sel
].b
= 0x8f00 + (((int)func
)&0xffff0000);
579 set_task_gate(unsigned int sel
, unsigned task_sel
)
581 KiIdt
[sel
].a
= task_sel
<< 16;
582 KiIdt
[sel
].b
= 0x8500;
585 void KeInitExceptions(void)
587 * FUNCTION: Initalize CPU exception handling
592 extern USHORT KiGdt
[];
593 extern unsigned int trap_stack_top
;
595 extern KTSS KiTrapTss
;
598 DPRINT("KeInitExceptions()\n",0);
600 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3
));
603 * Set up an a descriptor for the LDT
605 memset(KiNullLdt
, 0, sizeof(KiNullLdt
));
606 base
= (unsigned int)&KiNullLdt
;
607 length
= sizeof(KiNullLdt
) - 1;
609 KiGdt
[(LDT_SELECTOR
/ 2) + 0] = (length
& 0xFFFF);
610 KiGdt
[(LDT_SELECTOR
/ 2) + 1] = (base
& 0xFFFF);
611 KiGdt
[(LDT_SELECTOR
/ 2) + 2] = ((base
& 0xFF0000) >> 16) | 0x8200;
612 KiGdt
[(LDT_SELECTOR
/ 2) + 3] = ((length
& 0xF0000) >> 16) |
613 ((base
& 0xFF000000) >> 16);
616 * Set up a descriptor for the TSS
618 memset(&KiTss
, 0, sizeof(KiTss
));
619 base
= (unsigned int)&KiTss
;
620 length
= sizeof(KiTss
) - 1;
622 KiGdt
[(TSS_SELECTOR
/ 2) + 0] = (length
& 0xFFFF);
623 KiGdt
[(TSS_SELECTOR
/ 2) + 1] = (base
& 0xFFFF);
624 KiGdt
[(TSS_SELECTOR
/ 2) + 2] = ((base
& 0xFF0000) >> 16) | 0x8900;
625 KiGdt
[(TSS_SELECTOR
/ 2) + 3] = ((length
& 0xF0000) >> 16) |
626 ((base
& 0xFF000000) >> 16);
631 KiTss
.Esp0
= (ULONG
)&init_stack_top
;
632 KiTss
.Ss0
= KERNEL_DS
;
633 // KiTss.IoMapBase = FIELD_OFFSET(KTSS, IoBitmap);
634 KiTss
.IoMapBase
= 0xFFFF; /* No i/o bitmap */
635 KiTss
.IoBitmap
[0] = 0xFF;
636 KiTss
.Ldt
= LDT_SELECTOR
;
639 * Load the task register
643 : "a" (TSS_SELECTOR
));
646 * Set up the TSS for handling double faults
648 memset(&KiTrapTss
, 0, sizeof(KiTrapTss
));
649 base
= (unsigned int)&KiTrapTss
;
650 length
= sizeof(KiTrapTss
) - 1;
652 KiGdt
[(TRAP_TSS_SELECTOR
/ 2) + 0] = (length
& 0xFFFF);
653 KiGdt
[(TRAP_TSS_SELECTOR
/ 2) + 1] = (base
& 0xFFFF);
654 KiGdt
[(TRAP_TSS_SELECTOR
/ 2) + 2] = ((base
& 0xFF0000) >> 16) | 0x8900;
655 KiGdt
[(TRAP_TSS_SELECTOR
/ 2) + 3] = ((length
& 0xF0000) >> 16) |
656 ((base
& 0xFF000000) >> 16);
658 KiTrapTss
.Eflags
= 0;
659 KiTrapTss
.Esp0
= (ULONG
)&trap_stack_top
;
660 KiTrapTss
.Ss0
= KERNEL_DS
;
661 KiTrapTss
.Esp
= (ULONG
)&trap_stack_top
;
662 KiTrapTss
.Cs
= KERNEL_CS
;
663 KiTrapTss
.Eip
= (ULONG
)KiTrap8
;
664 KiTrapTss
.Ss
= KERNEL_DS
;
665 KiTrapTss
.Ds
= KERNEL_DS
;
666 KiTrapTss
.Es
= KERNEL_DS
;
667 KiTrapTss
.Fs
= PCR_SELECTOR
;
668 KiTrapTss
.IoMapBase
= 0xFFFF; /* No i/o bitmap */
669 KiTrapTss
.IoBitmap
[0] = 0xFF;
670 KiTrapTss
.Ldt
= LDT_SELECTOR
;
674 * Set up the other gates
676 set_interrupt_gate(0, (ULONG
)KiTrap0
);
677 set_interrupt_gate(1, (ULONG
)KiTrap1
);
678 set_interrupt_gate(2, (ULONG
)KiTrap2
);
679 set_interrupt_gate(3, (ULONG
)KiTrap3
);
680 set_interrupt_gate(4, (ULONG
)KiTrap4
);
681 set_interrupt_gate(5, (ULONG
)KiTrap5
);
682 set_interrupt_gate(6, (ULONG
)KiTrap6
);
683 set_interrupt_gate(7, (ULONG
)KiTrap7
);
684 set_task_gate(8, TRAP_TSS_SELECTOR
);
685 set_interrupt_gate(9, (ULONG
)KiTrap9
);
686 set_interrupt_gate(10, (ULONG
)KiTrap10
);
687 set_interrupt_gate(11, (ULONG
)KiTrap11
);
688 set_interrupt_gate(12, (ULONG
)KiTrap12
);
689 set_interrupt_gate(13, (ULONG
)KiTrap13
);
690 set_interrupt_gate(14, (ULONG
)KiTrap14
);
691 set_interrupt_gate(15, (ULONG
)KiTrap15
);
692 set_interrupt_gate(16, (ULONG
)KiTrap16
);
696 set_interrupt_gate(i
,(int)KiTrapUnknown
);
699 set_system_call_gate(0x2d,(int)interrupt_handler2d
);
700 set_system_call_gate(0x2e,(int)interrupt_handler2e
);