Reverted the MPW changes (keep these in a seperate branch)
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/ke/i386/exp.c
22 * PURPOSE: Handling exceptions
23 * PROGRAMMER: David Welch (welch@cwcom.net)
24 * REVISION HISTORY:
25 * ??/??/??: Created
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <roscfg.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
43 #define NDEBUG
44 #include <internal/debug.h>
45
46 /* GLOBALS *****************************************************************/
47
48 #define _STR(x) #x
49 #define STR(x) _STR(x)
50
51 extern void interrupt_handler2e(void);
52 extern void interrupt_handler2d(void);
53
54 extern VOID KiTrap0(VOID);
55 extern VOID KiTrap1(VOID);
56 extern VOID KiTrap2(VOID);
57 extern VOID KiTrap3(VOID);
58 extern VOID KiTrap4(VOID);
59 extern VOID KiTrap5(VOID);
60 extern VOID KiTrap6(VOID);
61 extern VOID KiTrap7(VOID);
62 extern VOID KiTrap8(VOID);
63 extern VOID KiTrap9(VOID);
64 extern VOID KiTrap10(VOID);
65 extern VOID KiTrap11(VOID);
66 extern VOID KiTrap12(VOID);
67 extern VOID KiTrap13(VOID);
68 extern VOID KiTrap14(VOID);
69 extern VOID KiTrap15(VOID);
70 extern VOID KiTrap16(VOID);
71 extern VOID KiTrapUnknown(VOID);
72
73 extern ULONG init_stack;
74 extern ULONG init_stack_top;
75
76 static char *ExceptionTypeStrings[] =
77 {
78 "Divide Error",
79 "Debug Trap",
80 "NMI",
81 "Breakpoint",
82 "Overflow",
83 "BOUND range exceeded",
84 "Invalid Opcode",
85 "No Math Coprocessor",
86 "Double Fault",
87 "Unknown(9)",
88 "Invalid TSS",
89 "Segment Not Present",
90 "Stack Segment Fault",
91 "General Protection",
92 "Page Fault",
93 "Math Fault",
94 "Alignment Check",
95 "Machine Check"
96 };
97
98 static NTSTATUS ExceptionToNtStatus[] =
99 {
100 STATUS_INTEGER_DIVIDE_BY_ZERO,
101 STATUS_SINGLE_STEP,
102 STATUS_ACCESS_VIOLATION,
103 STATUS_BREAKPOINT,
104 STATUS_INTEGER_OVERFLOW,
105 STATUS_ARRAY_BOUNDS_EXCEEDED,
106 STATUS_ILLEGAL_INSTRUCTION,
107 STATUS_ACCESS_VIOLATION, /* STATUS_FLT_INVALID_OPERATION */
108 STATUS_ACCESS_VIOLATION,
109 STATUS_ACCESS_VIOLATION,
110 STATUS_ACCESS_VIOLATION,
111 STATUS_ACCESS_VIOLATION,
112 STATUS_STACK_OVERFLOW,
113 STATUS_ACCESS_VIOLATION,
114 STATUS_ACCESS_VIOLATION,
115 STATUS_ACCESS_VIOLATION, /* STATUS_FLT_INVALID_OPERATION */
116 STATUS_DATATYPE_MISALIGNMENT,
117 STATUS_ACCESS_VIOLATION
118 };
119
120
121 /* FUNCTIONS ****************************************************************/
122
123 extern unsigned int _text_start__, _text_end__;
124
125 STATIC BOOLEAN
126 print_address(PVOID address)
127 {
128 #ifdef KDBG
129 ULONG Offset;
130 PSYMBOL Symbol, NextSymbol;
131 BOOLEAN Printed = FALSE;
132 ULONG NextAddress;
133 #endif /* KDBG */
134 PLIST_ENTRY current_entry;
135 MODULE_TEXT_SECTION* current;
136 extern LIST_ENTRY ModuleTextListHead;
137
138 current_entry = ModuleTextListHead.Flink;
139
140 while (current_entry != &ModuleTextListHead &&
141 current_entry != NULL)
142 {
143 current =
144 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
145
146 if (address >= (PVOID)current->Base &&
147 address < (PVOID)(current->Base + current->Length))
148 {
149
150 #ifdef KDBG
151
152 Offset = (ULONG)((ULONG)address - current->Base);
153 Symbol = current->Symbols.Symbols;
154 while (Symbol != NULL)
155 {
156 NextSymbol = Symbol->Next;
157 if (NextSymbol != NULL)
158 NextAddress = NextSymbol->RelativeAddress;
159 else
160 NextAddress = current->Length;
161
162 if ((Offset >= Symbol->RelativeAddress) &&
163 (Offset < NextAddress))
164 {
165 DbgPrint("<%ws: %x (%wZ)>", current->Name, Offset,
166 &Symbol->Name);
167 Printed = TRUE;
168 break;
169 }
170 Symbol = NextSymbol;
171 }
172 if (!Printed)
173 DbgPrint("<%ws: %x>", current->Name, Offset);
174
175 #else /* KDBG */
176
177 DbgPrint("<%ws: %x>", current->Name,
178 address - current->Base);
179
180 #endif /* KDBG */
181
182 return(TRUE);
183 }
184
185 current_entry = current_entry->Flink;
186 }
187 return(FALSE);
188 }
189
190 ULONG
191 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
192 {
193 EXCEPTION_RECORD Er;
194
195 Er.ExceptionFlags = 0;
196 Er.ExceptionRecord = NULL;
197 Er.ExceptionAddress = (PVOID)Tf->Eip;
198
199 if (ExceptionNr == 14)
200 {
201 Er.NumberParameters = 2;
202 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
203 Er.ExceptionInformation[1] = (ULONG)Cr2;
204 }
205 else
206 {
207 if (ExceptionNr < 16)
208 {
209 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
210 }
211 else
212 {
213 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
214 }
215 Er.NumberParameters = 0;
216 }
217
218 KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
219
220 return(0);
221 }
222
223 ULONG
224 KiDoubleFaultHandler(VOID)
225 {
226 unsigned int cr2;
227 ULONG StackLimit;
228 ULONG StackBase;
229 ULONG Esp0;
230 ULONG ExceptionNr = 8;
231 KTSS* OldTss;
232 PULONG Frame;
233 #if 0
234 ULONG i, j;
235 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
236 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
237 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
238 ULONG TraceLength;
239 BOOLEAN FoundRepeat;
240 #endif
241
242 /* Use the address of the trap frame as approximation to the ring0 esp */
243 OldTss = KeGetCurrentKPCR()->TSS;
244 Esp0 = OldTss->Esp;
245
246 /* Get CR2 */
247 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
248
249 /*
250 * Check for stack underflow
251 */
252 if (PsGetCurrentThread() != NULL &&
253 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
254 {
255 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
256 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
257 ExceptionNr = 12;
258 }
259
260 /*
261 * Print out the CPU registers
262 */
263 if (ExceptionNr < 19)
264 {
265 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
266 ExceptionNr, 0);
267 }
268 else
269 {
270 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
271 }
272 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
273 print_address((PVOID)OldTss->Eip);
274 DbgPrint("\n");
275 DbgPrint("cr2 %x cr3 %x ", cr2, OldTss->Cr3);
276 DbgPrint("Proc: %x ",PsGetCurrentProcess());
277 if (PsGetCurrentProcess() != NULL)
278 {
279 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
280 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
281 }
282 if (PsGetCurrentThread() != NULL)
283 {
284 DbgPrint("Thrd: %x Tid: %x",
285 PsGetCurrentThread(),
286 PsGetCurrentThread()->Cid.UniqueThread);
287 }
288 DbgPrint("\n");
289 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
290 OldTss->Fs, OldTss->Gs);
291 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
292 OldTss->Ecx);
293 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss->Edx, OldTss->Ebp,
294 OldTss->Esi);
295 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
296 if (OldTss->Cs == KERNEL_CS)
297 {
298 DbgPrint("kESP %.8x ", Esp0);
299 if (PsGetCurrentThread() != NULL)
300 {
301 DbgPrint("kernel stack base %x\n",
302 PsGetCurrentThread()->Tcb.StackLimit);
303
304 }
305 }
306 else
307 {
308 DbgPrint("User ESP %.8x\n", OldTss->Esp);
309 }
310 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
311 {
312 DbgPrint("ESP %x\n", Esp0);
313 if (PsGetCurrentThread() != NULL)
314 {
315 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
316 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
317 }
318 else
319 {
320 StackLimit = (ULONG)&init_stack_top;
321 StackBase = (ULONG)&init_stack;
322 }
323
324 #if 1
325 DbgPrint("Frames: ");
326 Frame = (PULONG)OldTss->Ebp;
327 while (Frame != NULL && (ULONG)Frame >= StackBase)
328 {
329 print_address((PVOID)Frame[1]);
330 Frame = (PULONG)Frame[0];
331 }
332 #else
333 DbgPrint("Frames: ");
334 i = 0;
335 Frame = (PULONG)OldTss->Ebp;
336 while (Frame != NULL && (ULONG)Frame >= StackBase)
337 {
338 StackTrace[i] = (PVOID)Frame[1];
339 Frame = (PULONG)Frame[0];
340 i++;
341 }
342 TraceLength = i;
343
344 i = 0;
345 while (i < TraceLength)
346 {
347 StackRepeatCount[i] = 0;
348 j = i + 1;
349 FoundRepeat = FALSE;
350 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
351 {
352 if (memcmp(&StackTrace[i], &StackTrace[j],
353 (j - i) * sizeof(PVOID)) == 0)
354 {
355 StackRepeatCount[i] = 2;
356 StackRepeatLength[i] = j - i;
357 FoundRepeat = TRUE;
358 }
359 else
360 {
361 j++;
362 }
363 }
364 if (FoundRepeat == FALSE)
365 {
366 i++;
367 continue;
368 }
369 j = j + StackRepeatLength[i];
370 while ((TraceLength - j) >= StackRepeatLength[i] &&
371 FoundRepeat == TRUE)
372 {
373 if (memcmp(&StackTrace[i], &StackTrace[j],
374 StackRepeatLength[i] * sizeof(PVOID)) == 0)
375 {
376 StackRepeatCount[i]++;
377 j = j + StackRepeatLength[i];
378 }
379 else
380 {
381 FoundRepeat = FALSE;
382 }
383 }
384 i = j;
385 }
386
387 i = 0;
388 while (i < TraceLength)
389 {
390 if (StackRepeatCount[i] == 0)
391 {
392 print_address(StackTrace[i]);
393 i++;
394 }
395 else
396 {
397 DbgPrint("{");
398 if (StackRepeatLength[i] == 0)
399 {
400 for(;;);
401 }
402 for (j = 0; j < StackRepeatLength[i]; j++)
403 {
404 print_address(StackTrace[i + j]);
405 }
406 DbgPrint("}*%d", StackRepeatCount[i]);
407 i = i + StackRepeatLength[i] * StackRepeatCount[i];
408 }
409 }
410 #endif
411 }
412
413 DbgPrint("\n");
414 for(;;);
415 }
416
417 VOID
418 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG ExceptionNr, ULONG cr2)
419 {
420 unsigned int cr3;
421 unsigned int i;
422 ULONG StackLimit;
423 PULONG Frame;
424 ULONG Esp0;
425
426 Esp0 = (ULONG)Tf;
427
428 /*
429 * Print out the CPU registers
430 */
431 if (ExceptionNr < 19)
432 {
433 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
434 ExceptionNr, Tf->ErrorCode&0xffff);
435 }
436 else
437 {
438 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
439 }
440 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
441 Tf->Cs&0xffff, Tf->Eip);
442 print_address((PVOID)Tf->Eip);
443 DbgPrint("\n");
444 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3));
445 DbgPrint("cr2 %x cr3 %x ", cr2, cr3);
446 DbgPrint("Proc: %x ",PsGetCurrentProcess());
447 if (PsGetCurrentProcess() != NULL)
448 {
449 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
450 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
451 }
452 if (PsGetCurrentThread() != NULL)
453 {
454 DbgPrint("Thrd: %x Tid: %x",
455 PsGetCurrentThread(),
456 PsGetCurrentThread()->Cid.UniqueThread);
457 }
458 DbgPrint("\n");
459 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
460 Tf->Fs&0xffff, Tf->Gs&0xfff);
461 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
462 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf->Edx, Tf->Ebp, Tf->Esi);
463 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
464 if ((Tf->Cs&0xffff) == KERNEL_CS)
465 {
466 DbgPrint("kESP %.8x ", Esp0);
467 if (PsGetCurrentThread() != NULL)
468 {
469 DbgPrint("kernel stack base %x\n",
470 PsGetCurrentThread()->Tcb.StackLimit);
471
472 }
473 }
474
475 DbgPrint("ESP %x\n", Esp0);
476
477 if (PsGetCurrentThread() != NULL)
478 {
479 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
480 }
481 else
482 {
483 StackLimit = (ULONG)&init_stack_top;
484 }
485
486 /*
487 * Dump the stack frames
488 */
489 DbgPrint("Frames: ");
490 i = 1;
491 Frame = (PULONG)Tf->Ebp;
492 while (Frame != NULL)
493 {
494 print_address((PVOID)Frame[1]);
495 Frame = (PULONG)Frame[0];
496 i++;
497 }
498 if ((i % 8) != 0)
499 {
500 DbgPrint("\n");
501 }
502 }
503
504 ULONG
505 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
506 /*
507 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
508 * message and halt the computer
509 * ARGUMENTS:
510 * Complete CPU context
511 */
512 {
513 unsigned int cr2;
514 NTSTATUS Status;
515 ULONG Esp0;
516
517 /* Use the address of the trap frame as approximation to the ring0 esp */
518 Esp0 = (ULONG)&Tf->Eip;
519
520 /* Get CR2 */
521 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
522
523 /*
524 * If this was a V86 mode exception then handle it specially
525 */
526 if (Tf->Eflags & (1 << 17))
527 {
528 return(KeV86Exception(ExceptionNr, Tf, cr2));
529 }
530
531 /*
532 * Check for stack underflow, this may be obsolete
533 */
534 if (PsGetCurrentThread() != NULL &&
535 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
536 {
537 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
538 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
539 ExceptionNr = 12;
540 }
541
542 /*
543 * Maybe handle the page fault and return
544 */
545 if (ExceptionNr == 14)
546 {
547 __asm__("sti\n\t");
548 Status = MmPageFault(Tf->Cs&0xffff,
549 &Tf->Eip,
550 &Tf->Eax,
551 cr2,
552 Tf->ErrorCode);
553 if (NT_SUCCESS(Status))
554 {
555 return(0);
556 }
557
558 }
559
560 /*
561 * Handle user exceptions differently
562 */
563 if ((Tf->Cs & 0xFFFF) == USER_CS)
564 {
565 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
566 }
567 else
568 {
569 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
570 }
571 }
572
573 VOID
574 KeDumpStackFrames(PULONG Frame)
575 {
576 ULONG i;
577
578 DbgPrint("Frames: ");
579 i = 1;
580 while (Frame != NULL)
581 {
582 print_address((PVOID)Frame[1]);
583 Frame = (PULONG)Frame[0];
584 i++;
585 }
586 if ((i % 8) != 0)
587 {
588 DbgPrint("\n");
589 }
590 }
591
592 static void set_system_call_gate(unsigned int sel, unsigned int func)
593 {
594 DPRINT("sel %x %d\n",sel,sel);
595 KiIdt[sel].a = (((int)func)&0xffff) +
596 (KERNEL_CS << 16);
597 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
598 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
599 }
600
601 static void set_interrupt_gate(unsigned int sel, unsigned int func)
602 {
603 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
604 KiIdt[sel].a = (((int)func)&0xffff) +
605 (KERNEL_CS << 16);
606 KiIdt[sel].b = 0x8f00 + (((int)func)&0xffff0000);
607 }
608
609 static void
610 set_task_gate(unsigned int sel, unsigned task_sel)
611 {
612 KiIdt[sel].a = task_sel << 16;
613 KiIdt[sel].b = 0x8500;
614 }
615
616 VOID
617 KeInitExceptions(VOID)
618 /*
619 * FUNCTION: Initalize CPU exception handling
620 */
621 {
622 int i;
623
624 DPRINT("KeInitExceptions()\n");
625
626 /*
627 * Set up the other gates
628 */
629 set_interrupt_gate(0, (ULONG)KiTrap0);
630 set_interrupt_gate(1, (ULONG)KiTrap1);
631 set_interrupt_gate(2, (ULONG)KiTrap2);
632 set_interrupt_gate(3, (ULONG)KiTrap3);
633 set_interrupt_gate(4, (ULONG)KiTrap4);
634 set_interrupt_gate(5, (ULONG)KiTrap5);
635 set_interrupt_gate(6, (ULONG)KiTrap6);
636 set_interrupt_gate(7, (ULONG)KiTrap7);
637 set_task_gate(8, TRAP_TSS_SELECTOR);
638 set_interrupt_gate(9, (ULONG)KiTrap9);
639 set_interrupt_gate(10, (ULONG)KiTrap10);
640 set_interrupt_gate(11, (ULONG)KiTrap11);
641 set_interrupt_gate(12, (ULONG)KiTrap12);
642 set_interrupt_gate(13, (ULONG)KiTrap13);
643 set_interrupt_gate(14, (ULONG)KiTrap14);
644 set_interrupt_gate(15, (ULONG)KiTrap15);
645 set_interrupt_gate(16, (ULONG)KiTrap16);
646
647 for (i=17;i<256;i++)
648 {
649 set_interrupt_gate(i,(int)KiTrapUnknown);
650 }
651
652 set_system_call_gate(0x2d,(int)interrupt_handler2d);
653 set_system_call_gate(0x2e,(int)interrupt_handler2e);
654 }