V86 mode fixes
[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 * PROGRAMMER: David Welch (welch@cwcom.net)
24 * REVISION HISTORY:
25 * ??/??/??: Created
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <internal/ntoskrnl.h>
32 #include <internal/ke.h>
33 #include <internal/i386/segment.h>
34 #include <internal/i386/mm.h>
35 #include <internal/module.h>
36 #include <internal/mm.h>
37 #include <internal/ps.h>
38 #include <internal/trap.h>
39
40 #define NDEBUG
41 #include <internal/debug.h>
42
43 /* GLOBALS *****************************************************************/
44
45 #define _STR(x) #x
46 #define STR(x) _STR(x)
47
48 extern void interrupt_handler2e(void);
49 extern void interrupt_handler2d(void);
50
51 extern VOID KiTrap0(VOID);
52 extern VOID KiTrap1(VOID);
53 extern VOID KiTrap2(VOID);
54 extern VOID KiTrap3(VOID);
55 extern VOID KiTrap4(VOID);
56 extern VOID KiTrap5(VOID);
57 extern VOID KiTrap6(VOID);
58 extern VOID KiTrap7(VOID);
59 extern VOID KiTrap8(VOID);
60 extern VOID KiTrap9(VOID);
61 extern VOID KiTrap10(VOID);
62 extern VOID KiTrap11(VOID);
63 extern VOID KiTrap12(VOID);
64 extern VOID KiTrap13(VOID);
65 extern VOID KiTrap14(VOID);
66 extern VOID KiTrap15(VOID);
67 extern VOID KiTrap16(VOID);
68 extern VOID KiTrapUnknown(VOID);
69
70 extern ULONG init_stack;
71 extern ULONG init_stack_top;
72
73 /* FUNCTIONS ****************************************************************/
74
75 extern unsigned int _text_start__, _text_end__;
76
77 STATIC BOOLEAN
78 print_address(PVOID address)
79 {
80 PLIST_ENTRY current_entry;
81 PMODULE_OBJECT current;
82 extern LIST_ENTRY ModuleListHead;
83
84 current_entry = ModuleListHead.Flink;
85
86 while (current_entry != &ModuleListHead &&
87 current_entry != NULL)
88 {
89 current = CONTAINING_RECORD(current_entry, MODULE_OBJECT, ListEntry);
90
91 if (address >= current->Base &&
92 address < (current->Base + current->Length))
93 {
94 DbgPrint("<%wZ: %x>", &current->FullName,
95 address - current->Base);
96 return(TRUE);
97 }
98
99 current_entry = current_entry->Flink;
100 }
101 #if 0
102 DbgPrint("<%x>", address);
103 #endif
104 return(FALSE);
105 }
106
107 ULONG
108 KiUserTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
109 {
110 EXCEPTION_RECORD Er;
111
112 if (ExceptionNr == 0)
113 {
114 Er.ExceptionCode = STATUS_INTEGER_DIVIDE_BY_ZERO;
115 }
116 else if (ExceptionNr == 1)
117 {
118 Er.ExceptionCode = STATUS_SINGLE_STEP;
119 }
120 else if (ExceptionNr == 3)
121 {
122 Er.ExceptionCode = STATUS_BREAKPOINT;
123 }
124 else if (ExceptionNr == 4)
125 {
126 Er.ExceptionCode = STATUS_INTEGER_OVERFLOW;
127 }
128 else if (ExceptionNr == 5)
129 {
130 Er.ExceptionCode = STATUS_ARRAY_BOUNDS_EXCEEDED;
131 }
132 else if (ExceptionNr == 6)
133 {
134 Er.ExceptionCode = STATUS_ILLEGAL_INSTRUCTION;
135 }
136 else
137 {
138 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
139 }
140 Er.ExceptionFlags = 0;
141 Er.ExceptionRecord = NULL;
142 Er.ExceptionAddress = (PVOID)Tf->Eip;
143 if (ExceptionNr == 14)
144 {
145 Er.NumberParameters = 2;
146 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
147 Er.ExceptionInformation[1] = (ULONG)Cr2;
148 }
149 else
150 {
151 Er.NumberParameters = 0;
152 }
153
154
155 KiDispatchException(&Er, 0, Tf, UserMode, TRUE);
156 return(0);
157 }
158
159 ULONG
160 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
161 /*
162 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
163 * message and halt the computer
164 * ARGUMENTS:
165 * Complete CPU context
166 */
167 {
168 unsigned int cr2, cr3;
169 unsigned int i;
170 // unsigned int j, sym;
171 PULONG stack;
172 NTSTATUS Status;
173 ULONG Esp0;
174 static char *TypeStrings[] =
175 {
176 "Divide Error",
177 "Debug Trap",
178 "NMI",
179 "Breakpoint",
180 "Overflow",
181 "BOUND range exceeded",
182 "Invalid Opcode",
183 "No Math Coprocessor",
184 "Double Fault",
185 "Unknown(9)",
186 "Invalid TSS",
187 "Segment Not Present",
188 "Stack Segment Fault",
189 "General Protection",
190 "Page Fault",
191 "Math Fault",
192 "Alignment Check",
193 "Machine Check"
194 };
195
196 /* Use the address of the trap frame as approximation to the ring0 esp */
197 Esp0 = (ULONG)Tf;
198
199 /* Get CR2 */
200 __asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
201
202 /*
203 * If this was a V86 mode exception then handle it specially
204 */
205 if (Tf->Eflags & (1 << 17))
206 {
207 return(KeV86Exception(ExceptionNr, Tf, cr2));
208 }
209
210 /*
211 * Check for stack underflow
212 */
213 if (PsGetCurrentThread() != NULL &&
214 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
215 {
216 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
217 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
218 ExceptionNr = 12;
219 }
220
221 if (ExceptionNr == 14)
222 {
223 __asm__("sti\n\t");
224 Status = MmPageFault(Tf->Cs&0xffff,
225 &Tf->Eip,
226 &Tf->Eax,
227 cr2,
228 Tf->ErrorCode);
229 if (NT_SUCCESS(Status))
230 {
231 return(0);
232 }
233 }
234
235 #if 0
236 if ((Tf->Cs & 0xFFFF) == USER_CS)
237 {
238 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
239 }
240 #endif
241
242 /*
243 * Print out the CPU registers
244 */
245 if (ExceptionNr < 19)
246 {
247 DbgPrint("%s Exception: %d(%x)\n",TypeStrings[ExceptionNr],
248 ExceptionNr, Tf->ErrorCode&0xffff);
249 }
250 else
251 {
252 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
253 }
254 DbgPrint("CS:EIP %x:%x ", Tf->Cs&0xffff, Tf->Eip);
255 print_address((PVOID)Tf->Eip);
256 DbgPrint("\n");
257 __asm__("movl %%cr3,%0\n\t" : "=d" (cr3));
258 DbgPrint("cr2 %x cr3 %x ", cr2, cr3);
259 DbgPrint("Proc: %x ",PsGetCurrentProcess());
260 if (PsGetCurrentProcess() != NULL)
261 {
262 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
263 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
264 }
265 if (PsGetCurrentThread() != NULL)
266 {
267 DbgPrint("Thrd: %x Tid: %x",
268 PsGetCurrentThread(),
269 PsGetCurrentThread()->Cid.UniqueThread);
270 }
271 DbgPrint("\n");
272 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
273 Tf->Fs&0xffff, Tf->Gs&0xfff);
274 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
275 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\n", Tf->Edx, Tf->Ebp, Tf->Esi);
276 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
277 if ((Tf->Cs&0xffff) == KERNEL_CS)
278 {
279 DbgPrint("kESP %.8x ", Esp0);
280 if (PsGetCurrentThread() != NULL)
281 {
282 DbgPrint("kernel stack base %x\n",
283 PsGetCurrentThread()->Tcb.StackLimit);
284
285 }
286 }
287 else
288 {
289 DbgPrint("User ESP %.8x\n", Tf->Esp);
290 }
291 if ((Tf->Cs & 0xffff) == KERNEL_CS)
292 {
293 DbgPrint("ESP %x\n", Esp0);
294 stack = (PULONG) (Esp0 + 24);
295 stack = (PULONG)(((ULONG)stack) & (~0x3));
296
297 DbgPrint("stack<%p>: ", stack);
298
299 for (i = 0; i < 18; i = i + 6)
300 {
301 DbgPrint("%.8x %.8x %.8x %.8x\n",
302 stack[i], stack[i+1],
303 stack[i+2], stack[i+3],
304 stack[i+4], stack[i+5]);
305 }
306 DbgPrint("Frames:\n");
307 for (i = 0; i < 32; i++)
308 {
309 if (stack[i] > ((unsigned int) &_text_start__) &&
310 !(stack[i] >= ((ULONG)&init_stack) &&
311 stack[i] <= ((ULONG)&init_stack_top)))
312 {
313 // DbgPrint(" %.8x", stack[i]);
314 print_address((PVOID)stack[i]);
315 DbgPrint(" ");
316 }
317 }
318 }
319 else
320 {
321 #if 1
322 DbgPrint("SS:ESP %x:%x\n", Tf->Ss, Tf->Esp);
323 stack=(PULONG)(Tf->Esp);
324
325 DbgPrint("Stack:\n");
326 for (i=0; i<64; i++)
327 {
328 if (MmIsPagePresent(NULL,&stack[i]))
329 {
330 DbgPrint("%.8x ",stack[i]);
331 if (((i+1)%8) == 0)
332 {
333 DbgPrint("\n");
334 }
335 }
336 }
337
338 if (MmIsPagePresent(NULL, (PVOID)Tf->Eip))
339 {
340 unsigned char instrs[512];
341
342 memcpy(instrs, (PVOID)Tf->Eip, 512);
343
344 DbgPrint("Instrs: ");
345
346 for (i=0; i<10; i++)
347 {
348 DbgPrint("%x ", instrs[i]);
349 }
350 }
351 #endif
352 }
353
354 DbgPrint("\n");
355 if ((Tf->Cs&0xffff) == USER_CS &&
356 Tf->Eip < KERNEL_BASE)
357 {
358 DbgPrint("Killing current task\n");
359 KeLowerIrql(PASSIVE_LEVEL);
360 if ((Tf->Cs&0xffff) == USER_CS)
361 {
362 ZwTerminateProcess(NtCurrentProcess(),
363 STATUS_NONCONTINUABLE_EXCEPTION);
364 }
365 }
366 for(;;);
367 }
368
369 VOID KeDumpStackFrames(PVOID _Stack, ULONG NrFrames)
370 {
371 PULONG Stack = (PULONG)_Stack;
372 ULONG i;
373
374 Stack = (PVOID)(((ULONG)Stack) & (~0x3));
375 DbgPrint("Stack: %x\n", Stack);
376 if (PsGetCurrentThread() != NULL)
377 {
378 DbgPrint("kernel stack base %x\n",
379 PsGetCurrentThread()->Tcb.StackLimit);
380 }
381
382 DbgPrint("Frames:\n");
383 for (i=0; i<NrFrames; i++)
384 {
385 // if (Stack[i] > KERNEL_BASE && Stack[i] < ((ULONG)&etext))
386 if (Stack[i] > KERNEL_BASE)
387 {
388 // DbgPrint("%.8x ",Stack[i]);
389 print_address((PVOID)Stack[i]);
390 DbgPrint(" ");
391 }
392 if (Stack[i] == 0xceafbeef)
393 {
394 DbgPrint("IRQ ");
395 }
396 }
397 DbgPrint("\n");
398 }
399
400 static void set_system_call_gate(unsigned int sel, unsigned int func)
401 {
402 DPRINT("sel %x %d\n",sel,sel);
403 KiIdt[sel].a = (((int)func)&0xffff) +
404 (KERNEL_CS << 16);
405 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
406 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
407 }
408
409 static void set_interrupt_gate(unsigned int sel, unsigned int func)
410 {
411 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
412 KiIdt[sel].a = (((int)func)&0xffff) +
413 (KERNEL_CS << 16);
414 KiIdt[sel].b = 0x8f00 + (((int)func)&0xffff0000);
415 }
416
417 void KeInitExceptions(void)
418 /*
419 * FUNCTION: Initalize CPU exception handling
420 */
421 {
422 int i;
423
424 DPRINT("KeInitExceptions()\n",0);
425
426 set_interrupt_gate(0, (ULONG)KiTrap0);
427 set_interrupt_gate(1, (ULONG)KiTrap1);
428 set_interrupt_gate(2, (ULONG)KiTrap2);
429 set_interrupt_gate(3, (ULONG)KiTrap3);
430 set_interrupt_gate(4, (ULONG)KiTrap4);
431 set_interrupt_gate(5, (ULONG)KiTrap5);
432 set_interrupt_gate(6, (ULONG)KiTrap6);
433 set_interrupt_gate(7, (ULONG)KiTrap7);
434 set_interrupt_gate(8, (ULONG)KiTrap8);
435 set_interrupt_gate(9, (ULONG)KiTrap9);
436 set_interrupt_gate(10, (ULONG)KiTrap10);
437 set_interrupt_gate(11, (ULONG)KiTrap11);
438 set_interrupt_gate(12, (ULONG)KiTrap12);
439 set_interrupt_gate(13, (ULONG)KiTrap13);
440 set_interrupt_gate(14, (ULONG)KiTrap14);
441 set_interrupt_gate(15, (ULONG)KiTrap15);
442 set_interrupt_gate(16, (ULONG)KiTrap16);
443
444 for (i=17;i<256;i++)
445 {
446 set_interrupt_gate(i,(int)KiTrapUnknown);
447 }
448
449 set_system_call_gate(0x2d,(int)interrupt_handler2d);
450 set_system_call_gate(0x2e,(int)interrupt_handler2e);
451 }