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