Merge 14551:14980 from trunk
[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 & ~0xC0000000);
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 ULONG
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("%.8s> ", 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\n ESP: %.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 return 0;
388 }
389
390 VOID
391 KiDumpTrapFrame(PKTRAP_FRAME Tf, ULONG Parameter1, ULONG Parameter2)
392 {
393 ULONG cr3_;
394 ULONG StackLimit;
395 ULONG Esp0;
396 ULONG ExceptionNr = (ULONG)Tf->DebugArgMark;
397 ULONG cr2 = (ULONG)Tf->DebugPointer;
398
399 Esp0 = (ULONG)Tf;
400
401 /*
402 * Print out the CPU registers
403 */
404 if (ExceptionNr < ARRAY_SIZE(ExceptionTypeStrings))
405 {
406 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings[ExceptionNr],
407 ExceptionNr, Tf->ErrorCode&0xffff);
408 }
409 else
410 {
411 DbgPrint("Exception: %d(%x)\n", ExceptionNr, Tf->ErrorCode&0xffff);
412 }
413 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
414 Tf->Cs&0xffff, Tf->Eip);
415 KeRosPrintAddress((PVOID)Tf->Eip);
416 DbgPrint("\n");
417 Ke386GetPageTableDirectory(cr3_);
418 DbgPrint("cr2 %x cr3 %x ", cr2, cr3_);
419 DbgPrint("Proc: %x ",PsGetCurrentProcess());
420 if (PsGetCurrentProcess() != NULL)
421 {
422 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId);
423 DbgPrint("%.8s> ", PsGetCurrentProcess()->ImageFileName);
424 }
425 if (PsGetCurrentThread() != NULL)
426 {
427 DbgPrint("Thrd: %x Tid: %x",
428 PsGetCurrentThread(),
429 PsGetCurrentThread()->Cid.UniqueThread);
430 }
431 DbgPrint("\n");
432 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf->Ds&0xffff, Tf->Es&0xffff,
433 Tf->Fs&0xffff, Tf->Gs&0xfff);
434 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf->Eax, Tf->Ebx, Tf->Ecx);
435 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf->Edx,
436 Tf->Ebp, Tf->Esi, Esp0);
437 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf->Edi, Tf->Eflags);
438 if ((Tf->Cs&0xffff) == KERNEL_CS)
439 {
440 DbgPrint("kESP %.8x ", Esp0);
441 if (PsGetCurrentThread() != NULL)
442 {
443 DbgPrint("kernel stack base %x\n",
444 PsGetCurrentThread()->Tcb.StackLimit);
445
446 }
447 }
448
449 if (PsGetCurrentThread() != NULL)
450 {
451 StackLimit = (ULONG)PsGetCurrentThread()->Tcb.StackBase;
452 }
453 else
454 {
455 StackLimit = (ULONG)init_stack_top;
456 }
457
458 /*
459 * Dump the stack frames
460 */
461 KeDumpStackFrames((PULONG)Tf->Ebp);
462 }
463
464 ULONG
465 KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr)
466 /*
467 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
468 * message and halt the computer
469 * ARGUMENTS:
470 * Complete CPU context
471 */
472 {
473 unsigned int cr2;
474 NTSTATUS Status;
475 ULONG Esp0;
476
477 /* Store the exception number in an unused field in the trap frame. */
478 Tf->DebugArgMark = (PVOID)ExceptionNr;
479
480 /* Use the address of the trap frame as approximation to the ring0 esp */
481 Esp0 = (ULONG)&Tf->Eip;
482
483 /* Get CR2 */
484 cr2 = Ke386GetCr2();
485 Tf->DebugPointer = (PVOID)cr2;
486
487 if (ExceptionNr == 14 && Tf->Eflags & FLAG_IF)
488 {
489 Ke386EnableInterrupts();
490 }
491
492 /*
493 * If this was a V86 mode exception then handle it specially
494 */
495 if (Tf->Eflags & (1 << 17))
496 {
497 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf->Eflags, Tf->Eip, ExceptionNr);
498 return(KeV86Exception(ExceptionNr, Tf, cr2));
499 }
500
501 /*
502 * Check for stack underflow, this may be obsolete
503 */
504 if (PsGetCurrentThread() != NULL &&
505 Esp0 < (ULONG)PsGetCurrentThread()->Tcb.StackLimit)
506 {
507 DPRINT1("Stack underflow (tf->esp %x Limit %x)\n",
508 Esp0, (ULONG)PsGetCurrentThread()->Tcb.StackLimit);
509 ExceptionNr = 12;
510 }
511
512 if (ExceptionNr == 15)
513 {
514 /*
515 * FIXME:
516 * This exception should never occur. The P6 has a bug, which does sometimes deliver
517 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
518 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
519 * sources. Linux does ignore this exception.
520 *
521 * Hartmut Birr
522 */
523 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
524 return(0);
525 }
526
527 /*
528 * Maybe handle the page fault and return
529 */
530 if (ExceptionNr == 14)
531 {
532 if (Ke386NoExecute && Tf->ErrorCode & 0x10 && cr2 >= KERNEL_BASE)
533 {
534 KEBUGCHECKWITHTF(ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY, 0, 0, 0, 0, Tf);
535 }
536 Status = MmPageFault(Tf->Cs&0xffff,
537 &Tf->Eip,
538 &Tf->Eax,
539 cr2,
540 Tf->ErrorCode);
541 if (NT_SUCCESS(Status))
542 {
543 return(0);
544 }
545 }
546
547 /*
548 * Check for a breakpoint that was only for the attention of the debugger.
549 */
550 if (ExceptionNr == 3 && Tf->Eip == ((ULONG)DbgBreakPointNoBugCheck) + 1)
551 {
552 /*
553 EIP is already adjusted by the processor to point to the instruction
554 after the breakpoint.
555 */
556 return(0);
557 }
558
559 /*
560 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
561 */
562 if (ExceptionNr == 7 || ExceptionNr == 16 || ExceptionNr == 19)
563 {
564 Status = KiHandleFpuFault(Tf, ExceptionNr);
565 if (NT_SUCCESS(Status))
566 {
567 return(0);
568 }
569 }
570
571 /*
572 * Handle user exceptions differently
573 */
574 if ((Tf->Cs & 0xFFFF) == USER_CS)
575 {
576 return(KiUserTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
577 }
578 else
579 {
580 return(KiKernelTrapHandler(Tf, ExceptionNr, (PVOID)cr2));
581 }
582 }
583
584 BOOLEAN
585 STDCALL
586 KeContextToTrapFrame(PCONTEXT Context,
587 PKTRAP_FRAME TrapFrame)
588 {
589 /* Start with the basic Registers */
590 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
591 {
592 TrapFrame->Esp = Context->Esp;
593 TrapFrame->Ss = Context->SegSs;
594 TrapFrame->Cs = Context->SegCs;
595 TrapFrame->Eip = Context->Eip;
596 TrapFrame->Eflags = Context->EFlags;
597 TrapFrame->Ebp = Context->Ebp;
598 }
599
600 /* Process the Integer Registers */
601 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
602 {
603 TrapFrame->Eax = Context->Eax;
604 TrapFrame->Ebx = Context->Ebx;
605 TrapFrame->Ecx = Context->Ecx;
606 TrapFrame->Edx = Context->Edx;
607 TrapFrame->Esi = Context->Esi;
608 TrapFrame->Edi = Context->Edi;
609 }
610
611 /* Process the Context Segments */
612 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
613 {
614 TrapFrame->Ds = Context->SegDs;
615 TrapFrame->Es = Context->SegEs;
616 TrapFrame->Fs = Context->SegFs;
617 TrapFrame->Gs = Context->SegGs;
618 }
619
620 /* Handle the Debug Registers */
621 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
622 {
623 TrapFrame->Dr0 = Context->Dr0;
624 TrapFrame->Dr1 = Context->Dr1;
625 TrapFrame->Dr2 = Context->Dr2;
626 TrapFrame->Dr3 = Context->Dr3;
627 TrapFrame->Dr6 = Context->Dr6;
628 TrapFrame->Dr7 = Context->Dr7;
629 }
630
631 /* Handle FPU and Extended Registers */
632 return KiContextToFxSaveArea((PFX_SAVE_AREA)(TrapFrame + 1), Context);
633 }
634
635 VOID
636 KeTrapFrameToContext(PKTRAP_FRAME TrapFrame,
637 PCONTEXT Context)
638 {
639 if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
640 {
641 Context->SegSs = TrapFrame->Ss;
642 Context->Esp = TrapFrame->Esp;
643 Context->SegCs = TrapFrame->Cs;
644 Context->Eip = TrapFrame->Eip;
645 Context->EFlags = TrapFrame->Eflags;
646 Context->Ebp = TrapFrame->Ebp;
647 }
648 if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
649 {
650 Context->Eax = TrapFrame->Eax;
651 Context->Ebx = TrapFrame->Ebx;
652 Context->Ecx = TrapFrame->Ecx;
653 /*
654 * NOTE: In the trap frame which is built on entry to a system
655 * call TrapFrame->Edx will actually hold the address of the
656 * previous TrapFrame. I don't believe leaking this information
657 * has security implications. Also EDX holds the address of the
658 * arguments to the system call in progress so it isn't of much
659 * interest to the debugger.
660 */
661 Context->Edx = TrapFrame->Edx;
662 Context->Esi = TrapFrame->Esi;
663 Context->Edi = TrapFrame->Edi;
664 }
665 if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS)
666 {
667 Context->SegDs = TrapFrame->Ds;
668 Context->SegEs = TrapFrame->Es;
669 Context->SegFs = TrapFrame->Fs;
670 Context->SegGs = TrapFrame->Gs;
671 }
672 if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS)
673 {
674 /*
675 * FIXME: Implement this case
676 */
677 Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386;
678 }
679 if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
680 {
681 /*
682 * FIXME: Implement this case
683 *
684 * I think this should only be filled for FPU exceptions, otherwise I
685 * would not know where to get it from as it can be the current state
686 * of the FPU or already saved in the thread's FPU save area.
687 * -blight
688 */
689 Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
690 }
691 #if 0
692 if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS)
693 {
694 /*
695 * FIXME: Investigate this
696 *
697 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
698 * This should only be filled in case of a SIMD exception I think, so
699 * this is not the right place (like for FPU the state could already be
700 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
701 * -blight
702 */
703 Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS;
704 }
705 #endif
706 }
707
708 VOID
709 KeDumpStackFrames(PULONG Frame)
710 {
711 PULONG StackBase, StackEnd;
712 MEMORY_BASIC_INFORMATION mbi;
713 ULONG ResultLength = sizeof(mbi);
714 NTSTATUS Status;
715
716 DbgPrint("Frames:\n");
717 _SEH_TRY
718 {
719 Status = MiQueryVirtualMemory (
720 (HANDLE)-1,
721 Frame,
722 MemoryBasicInformation,
723 &mbi,
724 sizeof(mbi),
725 &ResultLength );
726 if ( !NT_SUCCESS(Status) )
727 {
728 DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
729 return;
730 }
731
732 StackBase = Frame;
733 StackEnd = mbi.BaseAddress + mbi.RegionSize;
734
735 while ( Frame >= StackBase && Frame < StackEnd )
736 {
737 ULONG Addr = Frame[1];
738 if (!KeRosPrintAddress((PVOID)Addr))
739 DbgPrint("<%X>", Addr);
740 if ( Addr == 0 || Addr == 0xDEADBEEF )
741 break;
742 StackBase = Frame;
743 Frame = (PULONG)Frame[0];
744 DbgPrint("\n");
745 }
746 }
747 _SEH_HANDLE
748 {
749 }
750 _SEH_END;
751 DbgPrint("\n");
752 }
753
754 VOID STDCALL
755 KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
756 {
757 ULONG i=0;
758 PULONG StackBase, StackEnd;
759 MEMORY_BASIC_INFORMATION mbi;
760 ULONG ResultLength = sizeof(mbi);
761 NTSTATUS Status;
762
763 DbgPrint("Frames: ");
764 _SEH_TRY
765 {
766 if ( !Frame )
767 {
768 #if defined __GNUC__
769 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
770 #elif defined(_MSC_VER)
771 __asm mov [Frame], ebp
772 #endif
773 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
774 }
775
776 Status = MiQueryVirtualMemory (
777 (HANDLE)-1,
778 Frame,
779 MemoryBasicInformation,
780 &mbi,
781 sizeof(mbi),
782 &ResultLength );
783 if ( !NT_SUCCESS(Status) )
784 {
785 DPRINT1("Can't dump stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
786 return;
787 }
788
789 StackBase = Frame;
790 StackEnd = mbi.BaseAddress + mbi.RegionSize;
791
792 while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
793 {
794 ULONG Addr = Frame[1];
795 if (!KeRosPrintAddress((PVOID)Addr))
796 DbgPrint("<%X>", Addr);
797 if ( Addr == 0 || Addr == 0xDEADBEEF )
798 break;
799 StackBase = Frame;
800 Frame = (PULONG)Frame[0];
801 DbgPrint(" ");
802 }
803 }
804 _SEH_HANDLE
805 {
806 }
807 _SEH_END;
808 DbgPrint("\n");
809 }
810
811 ULONG STDCALL
812 KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
813 {
814 ULONG Count = 0;
815 PULONG StackBase, StackEnd, Frame;
816 MEMORY_BASIC_INFORMATION mbi;
817 ULONG ResultLength = sizeof(mbi);
818 NTSTATUS Status;
819
820 _SEH_TRY
821 {
822 #if defined __GNUC__
823 __asm__("mov %%ebp, %%ebx" : "=b" (Frame) : );
824 #elif defined(_MSC_VER)
825 __asm mov [Frame], ebp
826 #endif
827
828 Status = MiQueryVirtualMemory (
829 (HANDLE)-1,
830 Frame,
831 MemoryBasicInformation,
832 &mbi,
833 sizeof(mbi),
834 &ResultLength );
835 if ( !NT_SUCCESS(Status) )
836 {
837 DPRINT1("Can't get stack frames: NtQueryVirtualMemory() failed: %x\n", Status );
838 return 0;
839 }
840
841 StackBase = Frame;
842 StackEnd = mbi.BaseAddress + mbi.RegionSize;
843
844 while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
845 {
846 Frames[Count++] = Frame[1];
847 StackBase = Frame;
848 Frame = (PULONG)Frame[0];
849 }
850 }
851 _SEH_HANDLE
852 {
853 }
854 _SEH_END;
855 return Count;
856 }
857
858 static void
859 set_system_call_gate(unsigned int sel, unsigned int func)
860 {
861 DPRINT("sel %x %d\n",sel,sel);
862 KiIdt[sel].a = (((int)func)&0xffff) +
863 (KERNEL_CS << 16);
864 KiIdt[sel].b = 0xef00 + (((int)func)&0xffff0000);
865 DPRINT("idt[sel].b %x\n",KiIdt[sel].b);
866 }
867
868 static void set_interrupt_gate(unsigned int sel, unsigned int func)
869 {
870 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel,func);
871 KiIdt[sel].a = (((int)func)&0xffff) +
872 (KERNEL_CS << 16);
873 KiIdt[sel].b = 0x8e00 + (((int)func)&0xffff0000);
874 }
875
876 static void set_trap_gate(unsigned int sel, unsigned int func, unsigned int dpl)
877 {
878 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel, func, dpl);
879 ASSERT(dpl <= 3);
880 KiIdt[sel].a = (((int)func)&0xffff) +
881 (KERNEL_CS << 16);
882 KiIdt[sel].b = 0x8f00 + (dpl << 13) + (((int)func)&0xffff0000);
883 }
884
885 static void
886 set_task_gate(unsigned int sel, unsigned task_sel)
887 {
888 KiIdt[sel].a = task_sel << 16;
889 KiIdt[sel].b = 0x8500;
890 }
891
892 VOID INIT_FUNCTION
893 KeInitExceptions(VOID)
894 /*
895 * FUNCTION: Initalize CPU exception handling
896 */
897 {
898 int i;
899
900 DPRINT("KeInitExceptions()\n");
901
902 /*
903 * Set up the other gates
904 */
905 set_trap_gate(0, (ULONG)KiTrap0, 0);
906 set_trap_gate(1, (ULONG)KiTrap1, 0);
907 set_trap_gate(2, (ULONG)KiTrap2, 0);
908 set_trap_gate(3, (ULONG)KiTrap3, 3);
909 set_trap_gate(4, (ULONG)KiTrap4, 0);
910 set_trap_gate(5, (ULONG)KiTrap5, 0);
911 set_trap_gate(6, (ULONG)KiTrap6, 0);
912 set_trap_gate(7, (ULONG)KiTrap7, 0);
913 set_task_gate(8, TRAP_TSS_SELECTOR);
914 set_trap_gate(9, (ULONG)KiTrap9, 0);
915 set_trap_gate(10, (ULONG)KiTrap10, 0);
916 set_trap_gate(11, (ULONG)KiTrap11, 0);
917 set_trap_gate(12, (ULONG)KiTrap12, 0);
918 set_trap_gate(13, (ULONG)KiTrap13, 0);
919 set_interrupt_gate(14, (ULONG)KiTrap14);
920 set_trap_gate(15, (ULONG)KiTrap15, 0);
921 set_trap_gate(16, (ULONG)KiTrap16, 0);
922 set_trap_gate(17, (ULONG)KiTrap17, 0);
923 set_trap_gate(18, (ULONG)KiTrap18, 0);
924 set_trap_gate(19, (ULONG)KiTrap19, 0);
925
926 for (i = 20; i < 256; i++)
927 {
928 set_trap_gate(i,(int)KiTrapUnknown, 0);
929 }
930
931 set_system_call_gate(0x2d,(int)KiDebugService);
932 set_system_call_gate(0x2e,(int)KiSystemService);
933 }
934
935 /*
936 * @implemented
937 */
938 NTSTATUS STDCALL
939 KeRaiseUserException(IN NTSTATUS ExceptionCode)
940 {
941 ULONG OldEip;
942 PKTHREAD Thread = KeGetCurrentThread();
943
944 _SEH_TRY {
945 Thread->Teb->ExceptionCode = ExceptionCode;
946 } _SEH_HANDLE {
947 return(ExceptionCode);
948 } _SEH_END;
949
950 OldEip = Thread->TrapFrame->Eip;
951 Thread->TrapFrame->Eip = (ULONG_PTR)LdrpGetSystemDllRaiseExceptionDispatcher();
952 return((NTSTATUS)OldEip);
953 }
954
955 /*
956 * @implemented
957 */
958 NTSTATUS
959 STDCALL
960 NtRaiseException (
961 IN PEXCEPTION_RECORD ExceptionRecord,
962 IN PCONTEXT Context,
963 IN BOOLEAN SearchFrames)
964 {
965 PKTHREAD Thread = KeGetCurrentThread();
966 PKTRAP_FRAME TrapFrame = Thread->TrapFrame;
967 PKTRAP_FRAME PrevTrapFrame = (PKTRAP_FRAME)TrapFrame->Edx;
968
969 KeGetCurrentKPCR()->Tib.ExceptionList = TrapFrame->ExceptionList;
970
971 KiDispatchException(ExceptionRecord,
972 Context,
973 TrapFrame,
974 KeGetPreviousMode(),
975 SearchFrames);
976
977 /* Restore the user context */
978 Thread->TrapFrame = PrevTrapFrame;
979 __asm__("mov %%ebx, %%esp;\n" "jmp _KiServiceExit": : "b" (TrapFrame));
980
981 /* We never get here */
982 return(STATUS_SUCCESS);
983 }