Split the page fault handler from the trap handler.
[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/ke/i386/exp.c
5 * PURPOSE: Handling exceptions
6 *
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Skywing (skywing@valhallalegends.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *****************************************************************/
19
20 #define FLAG_IF (1<<9)
21
22 #define _STR(x) #x
23 #define STR(x) _STR(x)
24
25 #ifndef ARRAY_SIZE
26 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
27 #endif
28
29 extern void KiSystemService(void);
30 extern void KiDebugService(void);
31
32 extern VOID KiTrap0(VOID);
33 extern VOID KiTrap1(VOID);
34 extern VOID KiTrap2(VOID);
35 extern VOID KiTrap3(VOID);
36 extern VOID KiTrap4(VOID);
37 extern VOID KiTrap5(VOID);
38 extern VOID KiTrap6(VOID);
39 extern VOID KiTrap7(VOID);
40 extern VOID KiTrap8(VOID);
41 extern VOID KiTrap9(VOID);
42 extern VOID KiTrap10(VOID);
43 extern VOID KiTrap11(VOID);
44 extern VOID KiTrap12(VOID);
45 extern VOID KiTrap13(VOID);
46 extern VOID KiTrap14(VOID);
47 extern VOID KiTrap15(VOID);
48 extern VOID KiTrap16(VOID);
49 extern VOID KiTrap17(VOID);
50 extern VOID KiTrap18(VOID);
51 extern VOID KiTrap19(VOID);
52 extern VOID KiTrapUnknown(VOID);
53
54 extern ULONG init_stack;
55 extern ULONG init_stack_top;
56
57 extern BOOLEAN Ke386NoExecute;
58
59 static char *ExceptionTypeStrings[] =
60 {
61 "Divide Error",
62 "Debug Trap",
63 "NMI",
64 "Breakpoint",
65 "Overflow",
66 "BOUND range exceeded",
67 "Invalid Opcode",
68 "No Math Coprocessor",
69 "Double Fault",
70 "Unknown(9)",
71 "Invalid TSS",
72 "Segment Not Present",
73 "Stack Segment Fault",
74 "General Protection",
75 "Page Fault",
76 "Reserved(15)",
77 "Math Fault",
78 "Alignment Check",
79 "Machine Check",
80 "SIMD Fault"
81 };
82
83 NTSTATUS ExceptionToNtStatus[] =
84 {
85 STATUS_INTEGER_DIVIDE_BY_ZERO,
86 STATUS_SINGLE_STEP,
87 STATUS_ACCESS_VIOLATION,
88 STATUS_BREAKPOINT,
89 STATUS_INTEGER_OVERFLOW,
90 STATUS_ARRAY_BOUNDS_EXCEEDED,
91 STATUS_ILLEGAL_INSTRUCTION,
92 STATUS_FLOAT_INVALID_OPERATION,
93 STATUS_ACCESS_VIOLATION,
94 STATUS_ACCESS_VIOLATION,
95 STATUS_ACCESS_VIOLATION,
96 STATUS_ACCESS_VIOLATION,
97 STATUS_STACK_OVERFLOW,
98 STATUS_ACCESS_VIOLATION,
99 STATUS_ACCESS_VIOLATION,
100 STATUS_ACCESS_VIOLATION, /* RESERVED */
101 STATUS_FLOAT_INVALID_OPERATION, /* Should not be used, the FPU can give more specific info */
102 STATUS_DATATYPE_MISALIGNMENT,
103 STATUS_ACCESS_VIOLATION,
104 STATUS_FLOAT_MULTIPLE_TRAPS,
105 };
106
107 /* FUNCTIONS ****************************************************************/
108
109 BOOLEAN STDCALL
110 KiRosPrintAddress(PVOID address)
111 {
112 PLIST_ENTRY current_entry;
113 MODULE_TEXT_SECTION* current;
114 extern LIST_ENTRY ModuleTextListHead;
115 ULONG_PTR RelativeAddress;
116 ULONG i = 0;
117
118 do
119 {
120 current_entry = ModuleTextListHead.Flink;
121
122 while (current_entry != &ModuleTextListHead &&
123 current_entry != NULL)
124 {
125 current =
126 CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
127
128 if (address >= (PVOID)current->Base &&
129 address < (PVOID)(current->Base + current->Length))
130 {
131 RelativeAddress = (ULONG_PTR) address - current->Base;
132 DbgPrint("<%ws: %x>", current->Name, RelativeAddress);
133 return(TRUE);
134 }
135 current_entry = current_entry->Flink;
136 }
137
138 address = (PVOID)((ULONG_PTR)address & ~(ULONG_PTR)MmSystemRangeStart);
139 } while(++i <= 1);
140
141 return(FALSE);
142 }
143
144 ULONG
145 KiKernelTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr, PVOID Cr2)
146 {
147 EXCEPTION_RECORD Er;
148
149 Er.ExceptionFlags = 0;
150 Er.ExceptionRecord = NULL;
151 Er.ExceptionAddress = (PVOID)Tf->Eip;
152
153 if (ExceptionNr == 14)
154 {
155 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
156 Er.NumberParameters = 2;
157 Er.ExceptionInformation[0] = Tf->ErrorCode & 0x1;
158 Er.ExceptionInformation[1] = (ULONG)Cr2;
159 }
160 else
161 {
162 if (ExceptionNr < ARRAY_SIZE(ExceptionToNtStatus))
163 {
164 Er.ExceptionCode = ExceptionToNtStatus[ExceptionNr];
165 }
166 else
167 {
168 Er.ExceptionCode = STATUS_ACCESS_VIOLATION;
169 }
170 Er.NumberParameters = 0;
171 }
172
173 /* FIXME: Which exceptions are noncontinuable? */
174 Er.ExceptionFlags = 0;
175
176 KiDispatchException(&Er, 0, Tf, KernelMode, TRUE);
177
178 return(0);
179 }
180
181 VOID
182 KiDoubleFaultHandler(VOID)
183 {
184 unsigned int cr2;
185 ULONG StackLimit;
186 ULONG StackBase;
187 ULONG Esp0;
188 ULONG ExceptionNr = 8;
189 KTSS* OldTss;
190 PULONG Frame;
191 ULONG OldCr3;
192 #if 0
193 ULONG i, j;
194 static PVOID StackTrace[MM_STACK_SIZE / sizeof(PVOID)];
195 static ULONG StackRepeatCount[MM_STACK_SIZE / sizeof(PVOID)];
196 static ULONG StackRepeatLength[MM_STACK_SIZE / sizeof(PVOID)];
197 ULONG TraceLength;
198 BOOLEAN FoundRepeat;
199 #endif
200
201 OldTss = KeGetCurrentKPCR()->TSS;
202 Esp0 = OldTss->Esp;
203
204 /* Get CR2 */
205 cr2 = Ke386GetCr2();
206 if (PsGetCurrentThread() != NULL &&
207 PsGetCurrentThread()->ThreadsProcess != NULL)
208 {
209 OldCr3 = (ULONG)
210 PsGetCurrentThread()->ThreadsProcess->Pcb.DirectoryTableBase.QuadPart;
211 }
212 else
213 {
214 OldCr3 = 0xBEADF0AL;
215 }
216
217 /*
218 * Check for stack underflow
219 */
220 if (PsGetCurrentThread() != NULL &&
221 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
222 {
223 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
224 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
225 ExceptionNr = 12;
226 }
227
228 /*
229 * Print out the CPU registers
230 */
231 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
232 {
233 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
234 ExceptionNr, 0);
235 }
236 else
237 {
238 DbgPrint("Exception: %d(%x)\n", ExceptionNr, 0);
239 }
240 DbgPrint("CS:EIP %x:%x ", OldTss->Cs, OldTss->Eip);
241 KeRosPrintAddress((PVOID)OldTss->Eip);
242 DbgPrint("\n");
243 DbgPrint("cr2 %x cr3 %x ", cr2, OldCr3);
244 DbgPrint("Proc: %x ",PsGetCurrentProcess());
245 if (PsGetCurrentProcess() != NULL)
246 {
247 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
248 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
249 }
250 if (PsGetCurrentThread() != NULL)
251 {
252 DbgPrint("Thrd: %x Tid: %x",
253 PsGetCurrentThread(),
254 PsGetCurrentThread()->Cid.UniqueThread);
255 }
256 DbgPrint("\n");
257 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss->Ds, OldTss->Es,
258 OldTss->Fs, OldTss->Gs);
259 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss->Eax, OldTss->Ebx,
260 OldTss->Ecx);
261 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss->Edx,
262 OldTss->Ebp, OldTss->Esi, Esp0);
263 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss->Edi, OldTss->Eflags);
264 if (OldTss->Cs == KERNEL_CS)
265 {
266 DbgPrint("kESP %.8x ", Esp0);
267 if (PsGetCurrentThread() != NULL)
268 {
269 DbgPrint("kernel stack base %x\n",
270 PsGetCurrentThread()->Tcb.StackLimit);
271
272 }
273 }
274 else
275 {
276 DbgPrint("User ESP %.8x\n", OldTss->Esp);
277 }
278 if ((OldTss->Cs & 0xffff) == KERNEL_CS)
279 {
280 if (PsGetCurrentThread() != NULL)
281 {
282 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
283 StackBase = (ULONG)PsGetCurrentThread()->Tcb.StackLimit;
284 }
285 else
286 {
287 StackLimit = (ULONG)init_stack_top;
288 StackBase = (ULONG)init_stack;
289 }
290
291 /*
292 Change to an #if 0 to reduce the amount of information printed on
293 a recursive stack trace.
294 */
295 #if 1
296 DbgPrint("Frames: ");
297 Frame = (PULONG)OldTss->Ebp;
298 while (Frame != NULL && (ULONG)Frame >= StackBase)
299 {
300 KeRosPrintAddress((PVOID)Frame[1]);
301 Frame = (PULONG)Frame[0];
302 DbgPrint("\n");
303 }
304 #else
305 DbgPrint("Frames: ");
306 i = 0;
307 Frame = (PULONG)OldTss->Ebp;
308 while (Frame != NULL && (ULONG)Frame >= StackBase)
309 {
310 StackTrace[i] = (PVOID)Frame[1];
311 Frame = (PULONG)Frame[0];
312 i++;
313 }
314 TraceLength = i;
315
316 i = 0;
317 while (i < TraceLength)
318 {
319 StackRepeatCount[i] = 0;
320 j = i + 1;
321 FoundRepeat = FALSE;
322 while ((j - i) <= (TraceLength - j) && FoundRepeat == FALSE)
323 {
324 if (memcmp(&StackTrace[i], &StackTrace[j],
325 (j - i) * sizeof(PVOID)) == 0)
326 {
327 StackRepeatCount[i] = 2;
328 StackRepeatLength[i] = j - i;
329 FoundRepeat = TRUE;
330 }
331 else
332 {
333 j++;
334 }
335 }
336 if (FoundRepeat == FALSE)
337 {
338 i++;
339 continue;
340 }
341 j = j + StackRepeatLength[i];
342 while ((TraceLength - j) >= StackRepeatLength[i] &&
343 FoundRepeat == TRUE)
344 {
345 if (memcmp(&StackTrace[i], &StackTrace[j],
346 StackRepeatLength[i] * sizeof(PVOID)) == 0)
347 {
348 StackRepeatCount[i]++;
349 j = j + StackRepeatLength[i];
350 }
351 else
352 {
353 FoundRepeat = FALSE;
354 }
355 }
356 i = j;
357 }
358
359 i = 0;
360 while (i < TraceLength)
361 {
362 if (StackRepeatCount[i] == 0)
363 {
364 KeRosPrintAddress(StackTrace[i]);
365 i++;
366 }
367 else
368 {
369 DbgPrint("{");
370 if (StackRepeatLength[i] == 0)
371 {
372 for(;;);
373 }
374 for (j = 0; j < StackRepeatLength[i]; j++)
375 {
376 KeRosPrintAddress(StackTrace[i + j]);
377 }
378 DbgPrint("}*%d", StackRepeatCount[i]);
379 i = i + StackRepeatLength[i] * StackRepeatCount[i];
380 }
381 }
382 #endif
383 }
384
385 DbgPrint("\n");
386 for(;;);
387 }
388
389 VOID
390 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
391 {
392 ULONG cr3_;
393 ULONG StackLimit;
394 ULONG Esp0;
395 ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
396 ULONG cr2 = (ULONG)Tf->DebugPointer;
397
398 Esp0 = (ULONG)Tf;
399
400 /*
401 * Print out the CPU registers
402 */
403 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
404 {
405 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
406 ExceptionNr, Tf->ErrorCode&0xffff);
407 }
408 else
409 {
410 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
411 }
412 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
413 Tf->Cs&0xffff, Tf->Eip);
414 KeRosPrintAddress((PVOID)Tf->Eip);
415 DbgPrint("\n");
416 Ke386GetPageTableDirectory(cr3_);
417 DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
418 DbgPrint("Proc: %x ",PsGetCurrentProcess());
419 if (PsGetCurrentProcess() != NULL)
420 {
421 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
422 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName);
423 }
424 if (PsGetCurrentThread() != NULL)
425 {
426 DbgPrint("Thrd: %x Tid: %x",
427 PsGetCurrentThread(),
428 PsGetCurrentThread()->Cid.UniqueThread);
429 }
430 DbgPrint("\n");
431 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
432 Tf->Fs&0xffff, Tf->Gs&0xfff);
433 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
434 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
435 Tf->Ebp, Tf->Esi, Esp0);
436 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
437 if ((Tf->Cs&0xffff) == KERNEL_CS)
438 {
439 DbgPrint("kESP %.8x ", Esp0);
440 if (PsGetCurrentThread() != NULL)
441 {
442 DbgPrint("kernel stack base %x\n",
443 PsGetCurrentThread()->Tcb.StackLimit);
444
445 }
446 }
447
448 if (PsGetCurrentThread() != NULL)
449 {
450 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
451 }
452 else
453 {
454 StackLimit = (ULONG)init_stack_top;
455 }
456
457 /*
458 * Dump the stack frames
459 */
460 KeDumpStackFrames((PULONG)Tf->Ebp);
461 }
462
463 ULONG
464 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
465 /*
466 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
467 * message and halt the computer
468 * ARGUMENTS:
469 * Complete CPU context
470 */
471 {
472 ULONG_PTR cr2;
473 NTSTATUS Status;
474 ULONG Esp0;
475
476 ASSERT(ExceptionNr != 14);
477
478 /* Store the exception number in an unused field in the trap frame. */
479 Tf->DebugArgMark = (PVOID)ExceptionNr;
480
481 /* Use the address of the trap frame as approximation to the ring0 esp */
482 Esp0 = (ULONG)&Tf->Eip;
483
484 /* Get CR2 */
485 cr2 = Ke386GetCr2();
486 Tf->DebugPointer = (PVOID)cr2;
487
488 /*
489 * If this was a V86 mode exception then handle it specially
490 */
491 if (Tf->Eflags & (1 << 17))
492 {
493 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->Eflags, Tf->Eip, ExceptionNr);
494 return(KeV86Exception(ExceptionNr, Tf, cr2));
495 }
496
497 /*
498 * Check for stack underflow, this may be obsolete
499 */
500 if (PsGetCurrentThread() != NULL &&
501 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
502 {
503 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
504 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit, Tf->Eip);
505 ExceptionNr = 12;
506 }
507
508 if (ExceptionNr == 15)
509 {
510 /*
511 * FIXME:
512 * This exception should never occur. The P6 has a bug, which does sometimes deliver
513 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
514 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
515 * sources. Linux does ignore this exception.
516 *
517 * Hartmut Birr
518 */
519 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
520 return(0);
521 }
522
523 /*
524 * Check for a breakpoint that was only for the attention of the debugger.
525 */
526 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
527 {
528 /*
529 EIP is already adjusted by the processor to point to the instruction
530 after the breakpoint.
531 */
532 return(0);
533 }
534
535 /*
536 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
537 */
538 if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
539 {
540 Status = KiHandleFpuFault(Tf, ExceptionNr);
541 if (NT_SUCCESS(Status))
542 {
543 return(0);
544 }
545 }
546
547 /*
548 * Handle user exceptions differently
549 */
550 if ((Tf->Cs & 0xFFFF) == USER_CS)
551 {
552 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
553 }
554 else
555 {
556 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
557 }
558 }
559
560 BOOLEAN
561 STDCALL
562 KeContextToTrapFrame(PCONTEXT Context,
563 PKTRAP_FRAME TrapFrame)
564 {
565 /* Start with the basic Registers */
566 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
567 {
568 TrapFrame->Esp = Context->Esp;
569 TrapFrame->Ss = Context->SegSs;
570 TrapFrame->Cs = Context->SegCs;
571 TrapFrame->Eip = Context->Eip;
572 TrapFrame->Eflags = Context->EFlags;
573 TrapFrame->Ebp = Context->Ebp;
574 }
575
576 /* Process the Integer Registers */
577 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
578 {
579 TrapFrame->Eax = Context->Eax;
580 TrapFrame->Ebx = Context->Ebx;
581 TrapFrame->Ecx = Context->Ecx;
582 TrapFrame->Edx = Context->Edx;
583 TrapFrame->Esi = Context->Esi;
584 TrapFrame->Edi = Context->Edi;
585 }
586
587 /* Process the Context Segments */
588 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
589 {
590 TrapFrame->Ds = Context->SegDs;
591 TrapFrame->Es = Context->SegEs;
592 TrapFrame->Fs = Context->SegFs;
593 TrapFrame->Gs = Context->SegGs;
594 }
595
596 /* Handle the Debug Registers */
597 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
598 {
599 TrapFrame->Dr0 = Context->Dr0;
600 TrapFrame->Dr1 = Context->Dr1;
601 TrapFrame->Dr2 = Context->Dr2;
602 TrapFrame->Dr3 = Context->Dr3;
603 TrapFrame->Dr6 = Context->Dr6;
604 TrapFrame->Dr7 = Context->Dr7;
605 }
606
607 /* Handle FPU and Extended Registers */
608 return KiContextToFxSaveArea((PFX_SAVE_AREA)(TrapFrame + 1), Context);
609 }
610
611 VOID
612 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
613 PCONTEXT Context)
614 {
615 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
616 {
617 Context->SegSs = TrapFrame->Ss;
618 Context->Esp = TrapFrame->Esp;
619 Context->SegCs = TrapFrame->Cs;
620 Context->Eip = TrapFrame->Eip;
621 Context->EFlags = TrapFrame->Eflags;
622 Context->Ebp = TrapFrame->Ebp;
623 }
624 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
625 {
626 Context->Eax = TrapFrame->Eax;
627 Context->Ebx = TrapFrame->Ebx;
628 Context->Ecx = TrapFrame->Ecx;
629 /*
630 * NOTE: In the trap frame which is built on entry to a system
631 * call TrapFrame->Edx will actually hold the address of the
632 * previous TrapFrame. I don't believe leaking this information
633 * has security implications. Also EDX holds the address of the
634 * arguments to the system call in progress so it isn't of much
635 * interest to the debugger.
636 */
637 Context->Edx = TrapFrame->Edx;
638 Context->Esi = TrapFrame->Esi;
639 Context->Edi = TrapFrame->Edi;
640 }
641 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
642 {
643 Context->SegDs = TrapFrame->Ds;
644 Context->SegEs = TrapFrame->Es;
645 Context->SegFs = TrapFrame->Fs;
646 Context->SegGs = TrapFrame->Gs;
647 }
648 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
649 {
650 /*
651 * FIXME: Implement this case
652 */
653 Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
654 }
655 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
656 {
657 /*
658 * FIXME: Implement this case
659 *
660 * I think this should only be filled for FPU exceptions, otherwise I
661 * would not know where to get it from as it can be the current state
662 * of the FPU or already saved in the thread's FPU save area.
663 * -blight
664 */
665 Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
666 }
667 #if 0
668 if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
669 {
670 /*
671 * FIXME: Investigate this
672 *
673 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
674 * This should only be filled in case of a SIMD exception I think, so
675 * this is not the right place (like for FPU the state could already be
676 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
677 * -blight
678 */
679 Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS;
680 }
681 #endif
682 }
683
684 VOID
685 KeDumpStackFrames(PULONG Frame)
686 {
687 PULONG StackBase, StackEnd;
688 MEMORY_BASIC_INFORMATION mbi;
689 ULONG ResultLength = sizeof(mbi);
690 NTSTATUS Status;
691
692 DbgPrint("Frames:\n");
693 _SEH_TRY
694 {
695 Status = MiQueryVirtualMemory (
696 (HANDLE)-1,
697 Frame,
698 MemoryBasicInformation,
699 &mbi,
700 sizeof(mbi),
701 &ResultLength );
702 if ( !NT_SUCCESS(Status) )
703 {
704 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
705 return;
706 }
707
708 StackBase = Frame;
709 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
710
711 while ( Frame >= StackBase && Frame < StackEnd )
712 {
713 ULONG Addr = Frame[1];
714 if (!KeRosPrintAddress((PVOID)Addr))
715 DbgPrint("<%X>", Addr);
716 if ( Addr == 0 || Addr == 0xDEADBEEF )
717 break;
718 StackBase = Frame;
719 Frame = (PULONG)Frame[0];
720 DbgPrint("\n");
721 }
722 }
723 _SEH_HANDLE
724 {
725 }
726 _SEH_END;
727 DbgPrint("\n");
728 }
729
730 VOID STDCALL
731 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
732 {
733 ULONG i=0;
734 PULONG StackBase, StackEnd;
735 MEMORY_BASIC_INFORMATION mbi;
736 ULONG ResultLength = sizeof(mbi);
737 NTSTATUS Status;
738
739 DbgPrint("Frames: ");
740 _SEH_TRY
741 {
742 if ( !Frame )
743 {
744 #if defined __GNUC__
745 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
746 #elif defined(_MSC_VER)
747 __asm mov [Frame], ebp
748 #endif
749 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
750 }
751
752 Status = MiQueryVirtualMemory (
753 (HANDLE)-1,
754 Frame,
755 MemoryBasicInformation,
756 &mbi,
757 sizeof(mbi),
758 &ResultLength );
759 if ( !NT_SUCCESS(Status) )
760 {
761 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
762 return;
763 }
764
765 StackBase = Frame;
766 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
767
768 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
769 {
770 ULONG Addr = Frame[1];
771 if (!KeRosPrintAddress((PVOID)Addr))
772 DbgPrint("<%X>", Addr);
773 if ( Addr == 0 || Addr == 0xDEADBEEF )
774 break;
775 StackBase = Frame;
776 Frame = (PULONG)Frame[0];
777 DbgPrint(" ");
778 }
779 }
780 _SEH_HANDLE
781 {
782 }
783 _SEH_END;
784 DbgPrint("\n");
785 }
786
787 ULONG STDCALL
788 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
789 {
790 ULONG Count = 0;
791 PULONG StackBase, StackEnd, Frame;
792 MEMORY_BASIC_INFORMATION mbi;
793 ULONG ResultLength = sizeof(mbi);
794 NTSTATUS Status;
795
796 _SEH_TRY
797 {
798 #if defined __GNUC__
799 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
800 #elif defined(_MSC_VER)
801 __asm mov [Frame], ebp
802 #endif
803
804 Status = MiQueryVirtualMemory (
805 (HANDLE)-1,
806 Frame,
807 MemoryBasicInformation,
808 &mbi,
809 sizeof(mbi),
810 &ResultLength );
811 if ( !NT_SUCCESS(Status) )
812 {
813 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
814 return 0;
815 }
816
817 StackBase = Frame;
818 StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
819
820 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
821 {
822 Frames[Count++] = Frame[1];
823 StackBase = Frame;
824 Frame = (PULONG)Frame[0];
825 }
826 }
827 _SEH_HANDLE
828 {
829 }
830 _SEH_END;
831 return Count;
832 }
833
834 static void
835 set_system_call_gate(unsigned int sel, unsigned int func)
836 {
837 DPRINT("sel %x %d\n",sel,sel);
838 KiIdt[sel].a = (((int)func)&0xffff) +
839 (KERNEL_CS << 16);
840 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
841 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
842 }
843
844 static void set_interrupt_gate(unsigned int sel, unsigned int func)
845 {
846 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
847 KiIdt[sel].a = (((int)func)&0xffff) +
848 (KERNEL_CS << 16);
849 KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
850 }
851
852 static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
853 {
854 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
855 ASSERT(dpl <= 3);
856 KiIdt[sel].a = (((int)func)&0xffff) +
857 (KERNEL_CS << 16);
858 KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
859 }
860
861 static void
862 set_task_gate(unsigned int sel, unsigned task_sel)
863 {
864 KiIdt[sel].a = task_sel << 16;
865 KiIdt[sel].b = 0x8500;
866 }
867
868 VOID INIT_FUNCTION
869 KeInitExceptions(VOID)
870 /*
871 * FUNCTION: Initalize CPU exception handling
872 */
873 {
874 int i;
875
876 DPRINT("KeInitExceptions()\n");
877
878 /*
879 * Set up the other gates
880 */
881 set_trap_gate(0, (ULONG)KiTrap0, 0);
882 set_trap_gate(1, (ULONG)KiTrap1, 0);
883 set_trap_gate(2, (ULONG)KiTrap2, 0);
884 set_trap_gate(3, (ULONG)KiTrap3, 3);
885 set_trap_gate(4, (ULONG)KiTrap4, 0);
886 set_trap_gate(5, (ULONG)KiTrap5, 0);
887 set_trap_gate(6, (ULONG)KiTrap6, 0);
888 set_trap_gate(7, (ULONG)KiTrap7, 0);
889 set_task_gate(8, TRAP_TSS_SELECTOR);
890 set_trap_gate(9, (ULONG)KiTrap9, 0);
891 set_trap_gate(10, (ULONG)KiTrap10, 0);
892 set_trap_gate(11, (ULONG)KiTrap11, 0);
893 set_trap_gate(12, (ULONG)KiTrap12, 0);
894 set_trap_gate(13, (ULONG)KiTrap13, 0);
895 set_interrupt_gate(14, (ULONG)KiTrap14);
896 set_trap_gate(15, (ULONG)KiTrap15, 0);
897 set_trap_gate(16, (ULONG)KiTrap16, 0);
898 set_trap_gate(17, (ULONG)KiTrap17, 0);
899 set_trap_gate(18, (ULONG)KiTrap18, 0);
900 set_trap_gate(19, (ULONG)KiTrap19, 0);
901
902 for (i = 20; i < 256; i++)
903 {
904 set_trap_gate(i,(int)KiTrapUnknown, 0);
905 }
906
907 set_system_call_gate(0x2d,(int)KiDebugService);
908 set_system_call_gate(0x2e,(int)KiSystemService);
909 }
910
911 /*
912 * @implemented
913 */
914 NTSTATUS STDCALL
915 KeRaiseUserException(IN NTSTATUS ExceptionCode)
916 {
917 ULONG OldEip;
918 PKTHREAD Thread = KeGetCurrentThread();
919
920 _SEH_TRY {
921 Thread->Teb->ExceptionCode = ExceptionCode;
922 } _SEH_HANDLE {
923 return(ExceptionCode);
924 } _SEH_END;
925
926 OldEip = Thread->TrapFrame->Eip;
927 Thread->TrapFrame->Eip = (ULONG_PTR)LdrpGetSystemDllRaiseExceptionDispatcher();
928 return((NTSTATUS)OldEip);
929 }
930
931 /*
932 * @implemented
933 */
934 NTSTATUS
935 STDCALL
936 NtRaiseException (
937 IN PEXCEPTION_RECORD ExceptionRecord,
938 IN PCONTEXT Context,
939 IN BOOLEAN SearchFrames)
940 {
941 PKTHREAD Thread = KeGetCurrentThread();
942 PKTRAP_FRAME TrapFrame = Thread->TrapFrame;
943 PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
944
945 KeGetCurrentKPCR()->Tib.ExceptionList = TrapFrame->ExceptionList;
946
947 KiDispatchException(ExceptionRecord,
948 Context,
949 TrapFrame,
950 KeGetPreviousMode(),
951 SearchFrames);
952
953 /* Restore the user context */
954 Thread->TrapFrame = PrevTrapFrame;
955 __asm__("mov %%ebx, %%esp;\n" "jmp _KiServiceExit": : "b" (TrapFrame));
956
957 /* We never get here */
958 return(STATUS_SUCCESS);
959 }