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