Some fixes.
[reactos.git] / reactos / ntoskrnl / ke / i386 / exp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/hal/x86/exp.c
5 * PURPOSE: Handling exceptions
6 * PROGRAMMER: David Welch (welch@cwcom.net)
7 * REVISION HISTORY:
8 * ??/??/??: Created
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/ntoskrnl.h>
15 #include <internal/ke.h>
16 #include <internal/i386/segment.h>
17 #include <internal/mmhal.h>
18 #include <internal/module.h>
19 #include <internal/mm.h>
20
21 #define NDEBUG
22 #include <internal/debug.h>
23
24 /* GLOBALS *****************************************************************/
25
26 static exception_hook* exception_hooks[256]={NULL,};
27
28 #define _STR(x) #x
29 #define STR(x) _STR(x)
30
31 extern void interrupt_handler2e(void);
32 extern void interrupt_handler2d(void);
33
34 extern ULONG init_stack;
35 extern ULONG init_stack_top;
36
37 /* FUNCTIONS ****************************************************************/
38
39 #define EXCEPTION_HANDLER_WITH_ERROR(x,y) \
40 void exception_handler##y (void); \
41 void tmp_exception_handler##y (void) { \
42 __asm__("\n\t_exception_handler"##x":\n\t" \
43 "pushl %gs\n\t" \
44 "pushl %fs\n\t" \
45 "pushl %es\n\t" \
46 "pushl %ds\n\t" \
47 "pushl $"##x"\n\t" \
48 "pusha\n\t" \
49 "movw $"STR(KERNEL_DS)",%ax\n\t" \
50 "movw %ax,%ds\n\t" \
51 "movw %ax,%es\n\t" \
52 "movw %ax,%fs\n\t" \
53 "movw %ax,%gs\n\t" \
54 "call _exception_handler\n\t" \
55 "popa\n\t" \
56 "addl $4,%esp\n\t" \
57 "popl %ds\n\t" \
58 "popl %es\n\t" \
59 "popl %fs\n\t" \
60 "popl %gs\n\t" \
61 "addl $4,%esp\n\t" \
62 "iret\n\t"); }
63
64 #define EXCEPTION_HANDLER_WITHOUT_ERROR(x,y) \
65 asmlinkage void exception_handler##y (void); \
66 void tmp_exception_handler##y (void) { \
67 __asm__("\n\t_exception_handler"##x":\n\t" \
68 "pushl $0\n\t" \
69 "pushl %gs\n\t" \
70 "pushl %fs\n\t" \
71 "pushl %es\n\t" \
72 "pushl %ds\n\t" \
73 "pushl $"##x"\n\t" \
74 "pusha\n\t" \
75 "movw $"STR(KERNEL_DS)",%ax\n\t" \
76 "movw %ax,%ds\n\t" \
77 "movw %ax,%es\n\t" \
78 "movw %ax,%fs\n\t" \
79 "movw %ax,%gs\n\t" \
80 "call _exception_handler\n\t" \
81 "popa\n\t" \
82 "addl $4,%esp\n\t" \
83 "popl %ds\n\t" \
84 "popl %es\n\t" \
85 "popl %fs\n\t" \
86 "popl %gs\n\t" \
87 "addl $4,%esp\n\t" \
88 "iret\n\t"); }
89
90 asmlinkage void exception_handler_unknown(void);
91 asmlinkage void tmp_exception_handler_unknown(void)
92 {
93 __asm__("\n\t_exception_handler_unknown:\n\t"
94 "pushl $0\n\t"
95 "pushl %gs\n\t"
96 "pushl %fs\n\t"
97 "pushl %es\n\t"
98 "pushl %ds\n\t"
99 "pushl %ds\n\t"
100 "pushl $0xff\n\t"
101 "pusha\n\t"
102 "movw $"STR(KERNEL_DS)",%ax\n\t"
103 "movw %ax,%ds\n\t"
104 "movw %ax,%es\n\t"
105 "movw %ax,%fs\n\t"
106 "movw %ax,%gs\n\t"
107 "call _exception_handler\n\t"
108 "popa\n\t"
109 "addl $8,%esp\n\t"
110 "iret\n\t");
111 }
112
113 EXCEPTION_HANDLER_WITHOUT_ERROR("0",0);
114 EXCEPTION_HANDLER_WITHOUT_ERROR("1",1);
115 EXCEPTION_HANDLER_WITHOUT_ERROR("2",2);
116 EXCEPTION_HANDLER_WITHOUT_ERROR("3",3);
117 EXCEPTION_HANDLER_WITHOUT_ERROR("4",4);
118 EXCEPTION_HANDLER_WITHOUT_ERROR("5",5);
119 EXCEPTION_HANDLER_WITHOUT_ERROR("6",6);
120 EXCEPTION_HANDLER_WITHOUT_ERROR("7",7);
121 EXCEPTION_HANDLER_WITH_ERROR("8",8);
122 EXCEPTION_HANDLER_WITHOUT_ERROR("9",9);
123 EXCEPTION_HANDLER_WITH_ERROR("10",10);
124 EXCEPTION_HANDLER_WITH_ERROR("11",11);
125 EXCEPTION_HANDLER_WITH_ERROR("12",12);
126 EXCEPTION_HANDLER_WITH_ERROR("13",13);
127 EXCEPTION_HANDLER_WITH_ERROR("14",14);
128 EXCEPTION_HANDLER_WITH_ERROR("15",15);
129 EXCEPTION_HANDLER_WITHOUT_ERROR("16",16);
130
131 extern unsigned int stext, etext;
132
133 static void print_address(PVOID address)
134 {
135 PLIST_ENTRY current_entry;
136 PMODULE_OBJECT current;
137 extern LIST_ENTRY ModuleListHead;
138
139 current_entry = ModuleListHead.Flink;
140
141 while (current_entry != &ModuleListHead &&
142 current_entry != NULL)
143 {
144 current = CONTAINING_RECORD(current_entry, MODULE_OBJECT, ListEntry);
145
146 if (address >= current->Base &&
147 address < (current->Base + current->Length))
148 {
149 DbgPrint("<%S: %x>", current->Name,
150 address - current->Base);
151 return;
152 }
153
154 current_entry = current_entry->Flink;
155 }
156 DbgPrint("<%x>", address);
157 }
158
159 asmlinkage void exception_handler(unsigned int edi,
160 unsigned int esi, unsigned int ebp,
161 unsigned int esp, unsigned int ebx,
162 unsigned int edx, unsigned int ecx,
163 ULONG eax,
164 unsigned int type,
165 unsigned int ds,
166 unsigned int es,
167 unsigned int fs,
168 unsigned int gs,
169 unsigned int error_code,
170 ULONG eip,
171 unsigned int cs, unsigned int eflags,
172 unsigned int esp0, unsigned int ss0)
173 /*
174 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
175 * message and halt the computer
176 * ARGUMENTS:
177 * Complete CPU context
178 */
179 {
180 unsigned int cr2, cr3;
181 unsigned int i;
182 // unsigned int j, sym;
183 PULONG stack;
184 NTSTATUS Status;
185 static char *TypeStrings[] =
186 {
187 "Divide Error",
188 "Debug Trap",
189 "NMI",
190 "Breakpoint",
191 "Overflow",
192 "BOUND range exceeded",
193 "Invalid Opcode",
194 "No Math Coprocessor",
195 "Double Fault",
196 "Unknown(9)",
197 "Invalid TSS",
198 "Segment Not Present",
199 "Stack Segment Fault",
200 "General Protection",
201 "Page Fault",
202 "Math Fault",
203 "Alignment Check",
204 "Machine Check"
205 };
206
207 __asm__("movl %%cr2,%0\n\t"
208 : "=d" (cr2));
209
210 if (PsGetCurrentThread() != NULL &&
211 esp < (ULONG)PsGetCurrentThread()->Tcb.Context.KernelStackBase)
212 {
213 DbgPrint("Stack underflow\n");
214 type = 12;
215 }
216
217 if (type == 14)
218 {
219 __asm__("sti\n\t");
220 Status = MmPageFault(cs&0xffff,
221 &eip,
222 &eax,
223 cr2,
224 error_code);
225 if (NT_SUCCESS(Status))
226 {
227 return;
228 }
229 }
230 if (type==1)
231 {
232 DbgPrint("Trap at CS:EIP %x:%x\n",cs&0xffff,eip);
233 return;
234 }
235
236 /*
237 * Activate any hook for the exception
238 */
239 if (exception_hooks[type]!=NULL)
240 {
241 exception_hooks[type](NULL,type);
242 }
243
244 /*
245 * Print out the CPU registers
246 */
247 if (type < 19)
248 {
249 DbgPrint("%s Exception: %d(%x)\n",TypeStrings[type],type,
250 error_code&0xffff);
251 }
252 else
253 {
254 DbgPrint("Exception: %d(%x)\n",type,error_code&0xffff);
255 }
256 DbgPrint("CS:EIP %x:%x ",cs&0xffff,eip);
257 print_address((PVOID)eip);
258 DbgPrint("\n");
259 __asm__("movl %%cr3,%0\n\t"
260 : "=d" (cr3));
261 DbgPrint("cr2 %x cr3 %x ",cr2,cr3);
262 // for(;;);
263 DbgPrint("Proc: %x ",PsGetCurrentProcess());
264 if (PsGetCurrentProcess() != NULL)
265 {
266 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
267 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
268 }
269 if (PsGetCurrentThread() != NULL)
270 {
271 DbgPrint("Thrd: %x Tid: %x",
272 PsGetCurrentThread(),
273 PsGetCurrentThread()->Cid.UniqueThread);
274 }
275 DbgPrint("\n");
276 DbgPrint("DS %x ES %x FS %x GS %x\n",ds&0xffff,es&0xffff,fs&0xffff,
277 gs&0xfff);
278 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n",eax,ebx,ecx);
279 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n",edx,ebp,esi);
280 DbgPrint("EDI: %.8x EFLAGS: %.8x ",edi,eflags);
281 if ((cs&0xffff) == KERNEL_CS)
282 {
283 DbgPrint("kESP %.8x ",esp);
284 if (PsGetCurrentThread() != NULL)
285 {
286 DbgPrint("kernel stack base %x\n",
287 PsGetCurrentThread()->Tcb.Context.KernelStackBase);
288
289 }
290 }
291 else
292 {
293 DbgPrint("kernel ESP %.8x\n",esp);
294 }
295 if ((cs & 0xffff) == KERNEL_CS)
296 {
297 DbgPrint("ESP %x\n",esp);
298 stack = (PULONG) (esp + 24);
299 stack = (PULONG)(((ULONG)stack) & (~0x3));
300
301 DbgPrint("stack<%p>: ", stack);
302
303 for (i = 0; i < 16; i = i + 4)
304 {
305 DbgPrint("%.8x %.8x %.8x %.8x\n",
306 stack[i],
307 stack[i+1],
308 stack[i+2],
309 stack[i+3]);
310 }
311 DbgPrint("Frames:\n");
312 for (i = 0; i < 32; i++)
313 {
314 if (stack[i] > ((unsigned int) &stext) &&
315 !(stack[i] >= ((ULONG)&init_stack) &&
316 stack[i] <= ((ULONG)&init_stack_top)))
317 {
318 // DbgPrint(" %.8x", stack[i]);
319 print_address((PVOID)stack[i]);
320 DbgPrint(" ");
321 }
322 }
323 }
324 else
325 {
326 #if 1
327 DbgPrint("SS:ESP %x:%x\n",ss0,esp0);
328 stack=(PULONG)(esp0);
329
330 DbgPrint("Stack:\n");
331 for (i=0; i<64; i++)
332 {
333 if (MmIsPagePresent(NULL,&stack[i]))
334 {
335 DbgPrint("%.8x ",stack[i]);
336 if (((i+1)%4) == 0)
337 {
338 DbgPrint("\n");
339 }
340 }
341 }
342 #endif
343 }
344
345 DbgPrint("\n");
346 if ((cs&0xffff) == USER_CS &&
347 eip < KERNEL_BASE)
348 {
349 DbgPrint("Killing current task\n");
350 // for(;;);
351 KeLowerIrql(PASSIVE_LEVEL);
352 if ((cs&0xffff) == USER_CS)
353 {
354 ZwTerminateProcess(NtCurrentProcess(),
355 STATUS_NONCONTINUABLE_EXCEPTION);
356 }
357 }
358 for(;;);
359 }
360
361 VOID KeDumpStackFrames(PVOID _Stack, ULONG NrFrames)
362 {
363 PULONG Stack = (PULONG)_Stack;
364 ULONG i;
365
366 Stack = (PVOID)(((ULONG)Stack) & (~0x3));
367 DbgPrint("Stack: %x\n", Stack);
368 if (PsGetCurrentThread() != NULL)
369 {
370 DbgPrint("kernel stack base %x\n",
371 PsGetCurrentThread()->Tcb.Context.KernelStackBase);
372 }
373
374 DbgPrint("Frames:\n");
375 for (i=0; i<NrFrames; i++)
376 {
377 // if (Stack[i] > KERNEL_BASE && Stack[i] < ((ULONG)&etext))
378 if (Stack[i] > KERNEL_BASE)
379 {
380 // DbgPrint("%.8x ",Stack[i]);
381 print_address((PVOID)Stack[i]);
382 DbgPrint(" ");
383 }
384 if (Stack[i] == 0xceafbeef)
385 {
386 DbgPrint("IRQ ");
387 }
388 }
389 DbgPrint("\n");
390 }
391
392 static void set_system_call_gate(unsigned int sel, unsigned int func)
393 {
394 DPRINT("sel %x %d\n",sel,sel);
395 KiIdt[sel].a = (((int)func)&0xffff) +
396 (KERNEL_CS << 16);
397 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
398 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
399 }
400
401 static void set_interrupt_gate(unsigned int sel, unsigned int func)
402 {
403 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
404 KiIdt[sel].a = (((int)func)&0xffff) +
405 (KERNEL_CS << 16);
406 KiIdt[sel].b = 0x8f00 + (((int)func)&0xffff0000);
407 }
408
409 asmlinkage unsigned int ExHookException(exception_hook fn, unsigned int exp)
410 /*
411 * FUNCTION: Hook an exception
412 */
413 {
414 if (exp>=256)
415 {
416 return(1);
417 }
418 exception_hooks[exp]=fn;
419 return(0);
420 }
421
422 asmlinkage void KeInitExceptions(void)
423 /*
424 * FUNCTION: Initalize CPU exception handling
425 */
426 {
427 int i;
428
429 DPRINT("KeInitExceptions()\n",0);
430
431 set_interrupt_gate(0,(int)exception_handler0);
432 set_interrupt_gate(1,(int)exception_handler1);
433 set_interrupt_gate(2,(int)exception_handler2);
434 set_interrupt_gate(3,(int)exception_handler3);
435 set_interrupt_gate(4,(int)exception_handler4);
436 set_interrupt_gate(5,(int)exception_handler5);
437 set_interrupt_gate(6,(int)exception_handler6);
438 set_interrupt_gate(7,(int)exception_handler7);
439 set_interrupt_gate(8,(int)exception_handler8);
440 set_interrupt_gate(9,(int)exception_handler9);
441 set_interrupt_gate(10,(int)exception_handler10);
442 set_interrupt_gate(11,(int)exception_handler11);
443 set_interrupt_gate(12,(int)exception_handler12);
444 set_interrupt_gate(13,(int)exception_handler13);
445 set_interrupt_gate(14,(int)exception_handler14);
446 set_interrupt_gate(15,(int)exception_handler15);
447 set_interrupt_gate(16,(int)exception_handler16);
448
449 for (i=17;i<256;i++)
450 {
451 set_interrupt_gate(i,(int)exception_handler_unknown);
452 }
453
454 set_system_call_gate(0x2d,(int)interrupt_handler2d);
455 set_system_call_gate(0x2e,(int)interrupt_handler2e);
456 }