:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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 _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 }