Fixed some bugs.
[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 #ifdef DBG
49
50 NTSTATUS
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);
56
57 #endif /* DBG */
58
59 #define _STR(x) #x
60 #define STR(x) _STR(x)
61
62 extern void interrupt_handler2e(void);
63 extern void interrupt_handler2d(void);
64
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);
83
84 extern ULONG init_stack;
85 extern ULONG init_stack_top;
86
87 static char *ExceptionTypeStrings[] =
88 {
89 "Divide Error",
90 "Debug Trap",
91 "NMI",
92 "Breakpoint",
93 "Overflow",
94 "BOUND range exceeded",
95 "Invalid Opcode",
96 "No Math Coprocessor",
97 "Double Fault",
98 "Unknown(9)",
99 "Invalid TSS",
100 "Segment Not Present",
101 "Stack Segment Fault",
102 "General Protection",
103 "Page Fault",
104 "Math Fault",
105 "Alignment Check",
106 "Machine Check"
107 };
108
109 static NTSTATUS ExceptionToNtStatus[] =
110 {
111 STATUS_INTEGER_DIVIDE_BY_ZERO,
112 STATUS_SINGLE_STEP,
113 STATUS_ACCESS_VIOLATION,
114 STATUS_BREAKPOINT,
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
129 };
130
131 extern unsigned int _text_start__, _text_end__;
132
133 /* FUNCTIONS ****************************************************************/
134
135 STATIC BOOLEAN
136 print_address(PVOID address)
137 {
138 PLIST_ENTRY current_entry;
139 MODULE_TEXT_SECTION* current;
140 extern LIST_ENTRY ModuleTextListHead;
141 ULONG_PTR RelativeAddress;
142 #ifdef DBG
143 NTSTATUS Status;
144 ULONG LineNumber;
145 CHAR FileName[256];
146 CHAR FunctionName[256];
147 #endif
148
149 current_entry = ModuleTextListHead.Flink;
150
151 while (current_entry != &ModuleTextListHead &&
152 current_entry != NULL)
153 {
154 current =
155 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
156
157 if (address >= (PVOID)current->Base &&
158 address < (PVOID)(current->Base + current->Length))
159 {
160 RelativeAddress = (ULONG_PTR) address - current->Base;
161 #ifdef DBG
162 Status = LdrGetAddressInformation(&current->SymbolInfo,
163 RelativeAddress,
164 &LineNumber,
165 FileName,
166 FunctionName);
167 if (NT_SUCCESS(Status))
168 {
169 DbgPrint("<%ws: %x (%s:%d (%s))>",
170 current->Name, RelativeAddress, FileName, LineNumber, FunctionName);
171 }
172 else
173 {
174 DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
175 }
176 #else /* !DBG */
177 DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
178 #endif /* !DBG */
179 return(TRUE);
180 }
181 current_entry = current_entry->Flink;
182 }
183 return(FALSE);
184 }
185
186 ULONG
187 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
188 {
189 EXCEPTION_RECORD Er;
190
191 Er.ExceptionFlags = 0;
192 Er.ExceptionRecord = NULL;
193 Er.ExceptionAddress = (PVOID)Tf->Eip;
194
195 if (ExceptionNr == 14)
196 {
197 Er.NumberParameters = 2;
198 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
199 Er.ExceptionInformation[1] = (ULONG)Cr2;
200 }
201 else
202 {
203 if (ExceptionNr < 16)
204 {
205 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
206 }
207 else
208 {
209 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
210 }
211 Er.NumberParameters = 0;
212 }
213
214 KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
215
216 return(0);
217 }
218
219 ULONG
220 KiDoubleFaultHandler(VOID)
221 {
222 unsigned int cr2;
223 ULONG StackLimit;
224 ULONG StackBase;
225 ULONG Esp0;
226 ULONG ExceptionNr = 8;
227 KTSS* OldTss;
228 PULONG Frame;
229 ULONG OldCr3;
230 #if 0
231 ULONG i, j;
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)];
235 ULONG TraceLength;
236 BOOLEAN FoundRepeat;
237 #endif
238
239 OldTss = KeGetCurrentKPCR()->TSS;
240 Esp0 = OldTss->Esp;
241
242 /* Get CR2 */
243 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
244
245 if (PsGetCurrentThread() != NULL &&
246 PsGetCurrentThread()->ThreadsProcess != NULL)
247 {
248 OldCr3 =
249 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
250 }
251 else
252 {
253 OldCr3 = 0xBEADF0AL;
254 }
255
256 /*
257 * Check for stack underflow
258 */
259 if (PsGetCurrentThread() != NULL &&
260 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
261 {
262 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
263 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
264 ExceptionNr = 12;
265 }
266
267 /*
268 * Print out the CPU registers
269 */
270 if (ExceptionNr < 19)
271 {
272 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
273 ExceptionNr, 0);
274 }
275 else
276 {
277 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
278 }
279 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
280 print_address((PVOID)OldTss->Eip);
281 DbgPrint("\n");
282 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
283 DbgPrint("Proc: %x ",PsGetCurrentProcess());
284 if (PsGetCurrentProcess() != NULL)
285 {
286 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
287 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
288 }
289 if (PsGetCurrentThread() != NULL)
290 {
291 DbgPrint("Thrd: %x Tid: %x",
292 PsGetCurrentThread(),
293 PsGetCurrentThread()->Cid.UniqueThread);
294 }
295 DbgPrint("\n");
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,
299 OldTss->Ecx);
300 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss->Edx, OldTss->Ebp,
301 OldTss->Esi);
302 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
303 if (OldTss->Cs == KERNEL_CS)
304 {
305 DbgPrint("kESP %.8x ", Esp0);
306 if (PsGetCurrentThread() != NULL)
307 {
308 DbgPrint("kernel stack base %x\n",
309 PsGetCurrentThread()->Tcb.StackLimit);
310
311 }
312 }
313 else
314 {
315 DbgPrint("User ESP %.8x\n", OldTss->Esp);
316 }
317 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
318 {
319 DbgPrint("ESP %x\n", Esp0);
320 if (PsGetCurrentThread() != NULL)
321 {
322 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
323 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
324 }
325 else
326 {
327 StackLimit = (ULONG)&init_stack_top;
328 StackBase = (ULONG)&init_stack;
329 }
330
331 #if 1
332 DbgPrint("Frames: ");
333 Frame = (PULONG)OldTss->Ebp;
334 while (Frame != NULL && (ULONG)Frame >= StackBase)
335 {
336 print_address((PVOID)Frame[1]);
337 Frame = (PULONG)Frame[0];
338 DbgPrint("\n");
339 }
340 #else
341 DbgPrint("Frames: ");
342 i = 0;
343 Frame = (PULONG)OldTss->Ebp;
344 while (Frame != NULL && (ULONG)Frame >= StackBase)
345 {
346 StackTrace[i] = (PVOID)Frame[1];
347 Frame = (PULONG)Frame[0];
348 i++;
349 }
350 TraceLength = i;
351
352 i = 0;
353 while (i < TraceLength)
354 {
355 StackRepeatCount[i] = 0;
356 j = i + 1;
357 FoundRepeat = FALSE;
358 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
359 {
360 if (memcmp(&StackTrace[i], &StackTrace[j],
361 (j - i) * sizeof(PVOID)) == 0)
362 {
363 StackRepeatCount[i] = 2;
364 StackRepeatLength[i] = j - i;
365 FoundRepeat = TRUE;
366 }
367 else
368 {
369 j++;
370 }
371 }
372 if (FoundRepeat == FALSE)
373 {
374 i++;
375 continue;
376 }
377 j = j + StackRepeatLength[i];
378 while ((TraceLength - j) >= StackRepeatLength[i] &&
379 FoundRepeat == TRUE)
380 {
381 if (memcmp(&StackTrace[i], &StackTrace[j],
382 StackRepeatLength[i] * sizeof(PVOID)) == 0)
383 {
384 StackRepeatCount[i]++;
385 j = j + StackRepeatLength[i];
386 }
387 else
388 {
389 FoundRepeat = FALSE;
390 }
391 }
392 i = j;
393 }
394
395 i = 0;
396 while (i < TraceLength)
397 {
398 if (StackRepeatCount[i] == 0)
399 {
400 print_address(StackTrace[i]);
401 i++;
402 }
403 else
404 {
405 DbgPrint("{");
406 if (StackRepeatLength[i] == 0)
407 {
408 for(;;);
409 }
410 for (j = 0; j < StackRepeatLength[i]; j++)
411 {
412 print_address(StackTrace[i + j]);
413 }
414 DbgPrint("}*%d", StackRepeatCount[i]);
415 i = i + StackRepeatLength[i] * StackRepeatCount[i];
416 }
417 }
418 #endif
419 }
420
421 DbgPrint("\n");
422 for(;;);
423 }
424
425 VOID
426 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
427 {
428 unsigned int cr3;
429 unsigned int i;
430 ULONG StackLimit;
431 PULONG Frame;
432 ULONG Esp0;
433 ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
434 ULONG cr2 = (ULONG)Tf->DebugPointer;
435
436 Esp0 = (ULONG)Tf;
437
438 /*
439 * Print out the CPU registers
440 */
441 if (ExceptionNr < 19)
442 {
443 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
444 ExceptionNr, Tf->ErrorCode&0xffff);
445 }
446 else
447 {
448 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
449 }
450 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
451 Tf->Cs&0xffff, Tf->Eip);
452 print_address((PVOID)Tf->Eip);
453 DbgPrint("\n");
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)
458 {
459 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
460 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
461 }
462 if (PsGetCurrentThread() != NULL)
463 {
464 DbgPrint("Thrd: %x Tid: %x",
465 PsGetCurrentThread(),
466 PsGetCurrentThread()->Cid.UniqueThread);
467 }
468 DbgPrint("\n");
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)
475 {
476 DbgPrint("kESP %.8x ", Esp0);
477 if (PsGetCurrentThread() != NULL)
478 {
479 DbgPrint("kernel stack base %x\n",
480 PsGetCurrentThread()->Tcb.StackLimit);
481
482 }
483 }
484
485 DbgPrint("ESP %x\n", Esp0);
486
487 if (PsGetCurrentThread() != NULL)
488 {
489 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
490 }
491 else
492 {
493 StackLimit = (ULONG)&init_stack_top;
494 }
495
496 /*
497 * Dump the stack frames
498 */
499 DbgPrint("Frames: ");
500 i = 1;
501 Frame = (PULONG)Tf->Ebp;
502 while (Frame != NULL)
503 {
504 print_address((PVOID)Frame[1]);
505 Frame = (PULONG)Frame[0];
506 i++;
507 DbgPrint("\n");
508 }
509 }
510
511 ULONG
512 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
513 /*
514 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
515 * message and halt the computer
516 * ARGUMENTS:
517 * Complete CPU context
518 */
519 {
520 unsigned int cr2;
521 NTSTATUS Status;
522 ULONG Esp0;
523
524 /* Store the exception number in an unused field in the trap frame. */
525 Tf->DebugArgMark = (PVOID)ExceptionNr;
526
527 /* Use the address of the trap frame as approximation to the ring0 esp */
528 Esp0 = (ULONG)&Tf->Eip;
529
530 /* Get CR2 */
531 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
532 Tf->DebugPointer = (PVOID)cr2;
533
534 /*
535 * If this was a V86 mode exception then handle it specially
536 */
537 if (Tf->Eflags & (1 << 17))
538 {
539 return(KeV86Exception(ExceptionNr, Tf, cr2));
540 }
541
542 /*
543 * Check for stack underflow, this may be obsolete
544 */
545 if (PsGetCurrentThread() != NULL &&
546 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
547 {
548 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
549 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
550 ExceptionNr = 12;
551 }
552
553 /*
554 * Maybe handle the page fault and return
555 */
556 if (ExceptionNr == 14)
557 {
558 __asm__("sti\n\t");
559 Status = MmPageFault(Tf->Cs&0xffff,
560 &Tf->Eip,
561 &Tf->Eax,
562 cr2,
563 Tf->ErrorCode);
564 if (NT_SUCCESS(Status))
565 {
566 return(0);
567 }
568
569 }
570
571 /*
572 * Handle user exceptions differently
573 */
574 if ((Tf->Cs & 0xFFFF) == USER_CS)
575 {
576 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
577 }
578 else
579 {
580 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
581 }
582 }
583
584 VOID
585 KeDumpStackFrames(PULONG Frame)
586 {
587 ULONG i;
588
589 DbgPrint("Frames: ");
590 i = 1;
591 while (Frame != NULL)
592 {
593 print_address((PVOID)Frame[1]);
594 Frame = (PULONG)Frame[0];
595 i++;
596 DbgPrint("\n");
597 }
598 }
599
600 static void set_system_call_gate(unsigned int sel, unsigned int func)
601 {
602 DPRINT("sel %x %d\n",sel,sel);
603 KiIdt[sel].a = (((int)func)&0xffff) +
604 (KERNEL_CS << 16);
605 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
606 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
607 }
608
609 static void set_interrupt_gate(unsigned int sel, unsigned int func)
610 {
611 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
612 KiIdt[sel].a = (((int)func)&0xffff) +
613 (KERNEL_CS << 16);
614 KiIdt[sel].b = 0x8f00 + (((int)func)&0xffff0000);
615 }
616
617 static void
618 set_task_gate(unsigned int sel, unsigned task_sel)
619 {
620 KiIdt[sel].a = task_sel << 16;
621 KiIdt[sel].b = 0x8500;
622 }
623
624 VOID
625 KeInitExceptions(VOID)
626 /*
627 * FUNCTION: Initalize CPU exception handling
628 */
629 {
630 int i;
631
632 DPRINT("KeInitExceptions()\n");
633
634 /*
635 * Set up the other gates
636 */
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);
654
655 for (i=17;i<256;i++)
656 {
657 set_interrupt_gate(i,(int)KiTrapUnknown);
658 }
659
660 set_system_call_gate(0x2d,(int)interrupt_handler2d);
661 set_system_call_gate(0x2e,(int)interrupt_handler2e);
662 }