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