7790c0d6b2f0c185b2fe9d812449539de4dc95d3
[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, &Symbol->Name);
166 Printed = TRUE;
167 break;
168 }
169 Symbol = NextSymbol;
170 }
171 if (!Printed)
172 DbgPrint("<%ws: %x>", current->Name, Offset);
173
174 #else /* KDBG */
175
176 DbgPrint("<%ws: %x>", current->Name,
177 address - current->Base);
178
179 #endif /* KDBG */
180
181 return(TRUE);
182 }
183
184 current_entry = current_entry->Flink;
185 }
186 return(FALSE);
187 }
188
189 ULONG
190 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
191 {
192 EXCEPTION_RECORD Er;
193
194 Er.ExceptionFlags = 0;
195 Er.ExceptionRecord = NULL;
196 Er.ExceptionAddress = (PVOID)Tf->Eip;
197
198 if (ExceptionNr == 14)
199 {
200 Er.NumberParameters = 2;
201 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
202 Er.ExceptionInformation[1] = (ULONG)Cr2;
203 }
204 else
205 {
206 if (ExceptionNr < 16)
207 {
208 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
209 }
210 else
211 {
212 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
213 }
214 Er.NumberParameters = 0;
215 }
216
217 KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
218
219 return(0);
220 }
221
222 ULONG
223 KiDoubleFaultHandler(VOID)
224 {
225 unsigned int cr2;
226 ULONG i, j;
227 ULONG StackLimit;
228 ULONG StackBase;
229 ULONG Esp0;
230 ULONG ExceptionNr = 8;
231 KTSS* OldTss;
232 PULONG Frame;
233 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
234 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
235 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
236 ULONG TraceLength;
237 BOOLEAN FoundRepeat;
238
239 /* Use the address of the trap frame as approximation to the ring0 esp */
240 OldTss = KeGetCurrentKPCR()->TSS;
241 Esp0 = OldTss->Esp;
242
243 /* Get CR2 */
244 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
245
246 /*
247 * Check for stack underflow
248 */
249 if (PsGetCurrentThread() != NULL &&
250 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
251 {
252 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
253 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
254 ExceptionNr = 12;
255 }
256
257 /*
258 * Print out the CPU registers
259 */
260 if (ExceptionNr < 19)
261 {
262 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
263 ExceptionNr, 0);
264 }
265 else
266 {
267 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
268 }
269 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
270 print_address((PVOID)OldTss->Eip);
271 DbgPrint("\n");
272 DbgPrint("cr2 %x cr3 %x ", cr2, OldTss->Cr3);
273 DbgPrint("Proc: %x ",PsGetCurrentProcess());
274 if (PsGetCurrentProcess() != NULL)
275 {
276 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
277 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
278 }
279 if (PsGetCurrentThread() != NULL)
280 {
281 DbgPrint("Thrd: %x Tid: %x",
282 PsGetCurrentThread(),
283 PsGetCurrentThread()->Cid.UniqueThread);
284 }
285 DbgPrint("\n");
286 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
287 OldTss->Fs, OldTss->Gs);
288 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
289 OldTss->Ecx);
290 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", OldTss->Edx, OldTss->Ebp,
291 OldTss->Esi);
292 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
293 if (OldTss->Cs == KERNEL_CS)
294 {
295 DbgPrint("kESP %.8x ", Esp0);
296 if (PsGetCurrentThread() != NULL)
297 {
298 DbgPrint("kernel stack base %x\n",
299 PsGetCurrentThread()->Tcb.StackLimit);
300
301 }
302 }
303 else
304 {
305 DbgPrint("User ESP %.8x\n", OldTss->Esp);
306 }
307 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
308 {
309 DbgPrint("ESP %x\n", Esp0);
310 if (PsGetCurrentThread() != NULL)
311 {
312 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
313 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
314 }
315 else
316 {
317 StackLimit = (ULONG)&init_stack_top;
318 StackBase = (ULONG)&init_stack;
319 }
320
321 DbgPrint("Frames: ");
322 i = 0;
323 Frame = (PULONG)OldTss->Ebp;
324 while (Frame != NULL && (ULONG)Frame >= StackBase)
325 {
326 StackTrace[i] = (PVOID)Frame[1];
327 Frame = (PULONG)Frame[0];
328 i++;
329 }
330 TraceLength = i;
331
332 i = 0;
333 while (i < TraceLength)
334 {
335 StackRepeatCount[i] = 0;
336 j = i + 1;
337 FoundRepeat = FALSE;
338 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
339 {
340 if (memcmp(&StackTrace[i], &StackTrace[j],
341 (j - i) * sizeof(PVOID)) == 0)
342 {
343 StackRepeatCount[i] = 2;
344 StackRepeatLength[i] = j - i;
345 FoundRepeat = TRUE;
346 }
347 else
348 {
349 j++;
350 }
351 }
352 if (FoundRepeat == FALSE)
353 {
354 i++;
355 continue;
356 }
357 j = j + StackRepeatLength[i];
358 while ((TraceLength - j) >= StackRepeatLength[i] &&
359 FoundRepeat == TRUE)
360 {
361 if (memcmp(&StackTrace[i], &StackTrace[j],
362 StackRepeatLength[i] * sizeof(PVOID)) == 0)
363 {
364 StackRepeatCount[i]++;
365 j = j + StackRepeatLength[i];
366 }
367 else
368 {
369 FoundRepeat = FALSE;
370 }
371 }
372 i = j;
373 }
374
375 i = 0;
376 while (i < TraceLength)
377 {
378 if (StackRepeatCount[i] == 0)
379 {
380 print_address(StackTrace[i]);
381 i++;
382 }
383 else
384 {
385 DbgPrint("{");
386 if (StackRepeatLength[i] == 0)
387 {
388 for(;;);
389 }
390 for (j = 0; j < StackRepeatLength[i]; j++)
391 {
392 print_address(StackTrace[i + j]);
393 }
394 DbgPrint("}*%d", StackRepeatCount[i]);
395 i = i + StackRepeatLength[i] * StackRepeatCount[i];
396 }
397 }
398 }
399
400 DbgPrint("\n");
401 for(;;);
402 }
403
404 ULONG
405 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
406 /*
407 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
408 * message and halt the computer
409 * ARGUMENTS:
410 * Complete CPU context
411 */
412 {
413 #define SEH
414 unsigned int cr2;
415 #ifndef SEH
416 unsigned int cr3;
417 unsigned int i;
418 ULONG StackLimit;
419 PULONG Frame;
420 #endif
421 // unsigned int j, sym;
422 NTSTATUS Status;
423 ULONG Esp0;
424
425 /* Use the address of the trap frame as approximation to the ring0 esp */
426 Esp0 = (ULONG)&Tf->Eip;
427
428 /* Get CR2 */
429 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
430
431 /*
432 * If this was a V86 mode exception then handle it specially
433 */
434 if (Tf->Eflags & (1 << 17))
435 {
436 return(KeV86Exception(ExceptionNr, Tf, cr2));
437 }
438
439 /*
440 * Check for stack underflow, this may be obsolete
441 */
442 if (PsGetCurrentThread() != NULL &&
443 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
444 {
445 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
446 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
447 ExceptionNr = 12;
448 }
449
450 /*
451 * Maybe handle the page fault and return
452 */
453 if (ExceptionNr == 14)
454 {
455 __asm__("sti\n\t");
456 Status = MmPageFault(Tf->Cs&0xffff,
457 &Tf->Eip,
458 &Tf->Eax,
459 cr2,
460 Tf->ErrorCode);
461 if (NT_SUCCESS(Status))
462 {
463 return(0);
464 }
465
466 }
467
468 /*
469 * Handle user exceptions differently
470 */
471 if ((Tf->Cs & 0xFFFF) == USER_CS)
472 {
473 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
474 }
475 else
476 {
477 #ifdef SEH
478 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
479 #endif
480 }
481
482
483 #ifndef SEH
484
485 /*
486 * Print out the CPU registers
487 */
488 if (ExceptionNr < 19)
489 {
490 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
491 ExceptionNr, Tf->ErrorCode&0xffff);
492 }
493 else
494 {
495 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
496 }
497 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
498 Tf->Cs&0xffff, Tf->Eip);
499 print_address((PVOID)Tf->Eip);
500 DbgPrint("\n");
501 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3));
502 DbgPrint("cr2 %x cr3 %x ", cr2, cr3);
503 DbgPrint("Proc: %x ",PsGetCurrentProcess());
504 if (PsGetCurrentProcess() != NULL)
505 {
506 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
507 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
508 }
509 if (PsGetCurrentThread() != NULL)
510 {
511 DbgPrint("Thrd: %x Tid: %x",
512 PsGetCurrentThread(),
513 PsGetCurrentThread()->Cid.UniqueThread);
514 }
515 DbgPrint("\n");
516 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
517 Tf->Fs&0xffff, Tf->Gs&0xfff);
518 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
519 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf->Edx, Tf->Ebp, Tf->Esi);
520 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
521 if ((Tf->Cs&0xffff) == KERNEL_CS)
522 {
523 DbgPrint("kESP %.8x ", Esp0);
524 if (PsGetCurrentThread() != NULL)
525 {
526 DbgPrint("kernel stack base %x\n",
527 PsGetCurrentThread()->Tcb.StackLimit);
528
529 }
530 }
531
532 DbgPrint("ESP %x\n", Esp0);
533
534 if (PsGetCurrentThread() != NULL)
535 {
536 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
537 }
538 else
539 {
540 StackLimit = (ULONG)&init_stack_top;
541 }
542
543 /*
544 * Dump the stack frames
545 */
546 DbgPrint("Frames: ");
547 i = 1;
548 Frame = (PULONG)Tf->Ebp;
549 while (Frame != NULL)
550 {
551 print_address((PVOID)Frame[1]);
552 Frame = (PULONG)Frame[0];
553 i++;
554 }
555 if ((i % 8) != 0)
556 {
557 DbgPrint("\n");
558 }
559
560 for(;;);
561
562 return 0;
563 #endif
564 }
565
566 VOID
567 KeDumpStackFrames(PULONG Frame)
568 {
569 ULONG i;
570
571 DbgPrint("Frames: ");
572 i = 1;
573 while (Frame != NULL)
574 {
575 print_address((PVOID)Frame[1]);
576 Frame = (PULONG)Frame[0];
577 i++;
578 }
579 if ((i % 8) != 0)
580 {
581 DbgPrint("\n");
582 }
583 }
584
585 static void set_system_call_gate(unsigned int sel, unsigned int func)
586 {
587 DPRINT("sel %x %d\n",sel,sel);
588 KiIdt[sel].a = (((int)func)&0xffff) +
589 (KERNEL_CS << 16);
590 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
591 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
592 }
593
594 static void set_interrupt_gate(unsigned int sel, unsigned int func)
595 {
596 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
597 KiIdt[sel].a = (((int)func)&0xffff) +
598 (KERNEL_CS << 16);
599 KiIdt[sel].b = 0x8f00 + (((int)func)&0xffff0000);
600 }
601
602 static void
603 set_task_gate(unsigned int sel, unsigned task_sel)
604 {
605 KiIdt[sel].a = task_sel << 16;
606 KiIdt[sel].b = 0x8500;
607 }
608
609 VOID
610 KeInitExceptions(VOID)
611 /*
612 * FUNCTION: Initalize CPU exception handling
613 */
614 {
615 int i;
616
617 DPRINT("KeInitExceptions()\n");
618
619 /*
620 * Set up the other gates
621 */
622 set_interrupt_gate(0, (ULONG)KiTrap0);
623 set_interrupt_gate(1, (ULONG)KiTrap1);
624 set_interrupt_gate(2, (ULONG)KiTrap2);
625 set_interrupt_gate(3, (ULONG)KiTrap3);
626 set_interrupt_gate(4, (ULONG)KiTrap4);
627 set_interrupt_gate(5, (ULONG)KiTrap5);
628 set_interrupt_gate(6, (ULONG)KiTrap6);
629 set_interrupt_gate(7, (ULONG)KiTrap7);
630 set_task_gate(8, TRAP_TSS_SELECTOR);
631 set_interrupt_gate(9, (ULONG)KiTrap9);
632 set_interrupt_gate(10, (ULONG)KiTrap10);
633 set_interrupt_gate(11, (ULONG)KiTrap11);
634 set_interrupt_gate(12, (ULONG)KiTrap12);
635 set_interrupt_gate(13, (ULONG)KiTrap13);
636 set_interrupt_gate(14, (ULONG)KiTrap14);
637 set_interrupt_gate(15, (ULONG)KiTrap15);
638 set_interrupt_gate(16, (ULONG)KiTrap16);
639
640 for (i=17;i<256;i++)
641 {
642 set_interrupt_gate(i,(int)KiTrapUnknown);
643 }
644
645 set_system_call_gate(0x2d,(int)interrupt_handler2d);
646 set_system_call_gate(0x2e,(int)interrupt_handler2e);
647 }