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