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