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