2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/i386/exp.c
5 * PURPOSE: Handling exceptions
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 * Skywing (skywing@valhallalegends.com)
11 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 #if defined (ALLOC_PRAGMA)
19 #pragma alloc_text(INIT, KeInitExceptions)
27 * - Sanitize some context fields.
28 * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
29 * - Implement official stack trace functions (exported) and remove stuff here.
30 * - Forward exceptions to user-mode debugger.
35 Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame
);
37 /* GLOBALS *****************************************************************/
39 #define FLAG_IF (1<<9)
42 #define STR(x) _STR(x)
45 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
48 extern void KiSystemService(void);
49 extern void KiDebugService(void);
51 extern VOID
KiTrap0(VOID
);
52 extern VOID
KiTrap1(VOID
);
53 extern VOID
KiTrap2(VOID
);
54 extern VOID
KiTrap3(VOID
);
55 extern VOID
KiTrap4(VOID
);
56 extern VOID
KiTrap5(VOID
);
57 extern VOID
KiTrap6(VOID
);
58 extern VOID
KiTrap7(VOID
);
59 extern VOID
KiTrap8(VOID
);
60 extern VOID
KiTrap9(VOID
);
61 extern VOID
KiTrap10(VOID
);
62 extern VOID
KiTrap11(VOID
);
63 extern VOID
KiTrap12(VOID
);
64 extern VOID
KiTrap13(VOID
);
65 extern VOID
KiTrap14(VOID
);
66 extern VOID
KiTrap15(VOID
);
67 extern VOID
KiTrap16(VOID
);
68 extern VOID
KiTrap17(VOID
);
69 extern VOID
KiTrap18(VOID
);
70 extern VOID
KiTrap19(VOID
);
71 extern VOID
KiTrapUnknown(VOID
);
73 extern ULONG init_stack
;
74 extern ULONG init_stack_top
;
76 extern BOOLEAN Ke386NoExecute
;
78 static char *ExceptionTypeStrings
[] =
85 "BOUND range exceeded",
87 "No Math Coprocessor",
91 "Segment Not Present",
92 "Stack Segment Fault",
102 NTSTATUS ExceptionToNtStatus
[] =
104 STATUS_INTEGER_DIVIDE_BY_ZERO
,
106 STATUS_ACCESS_VIOLATION
,
108 STATUS_INTEGER_OVERFLOW
,
109 STATUS_ARRAY_BOUNDS_EXCEEDED
,
110 STATUS_ILLEGAL_INSTRUCTION
,
111 STATUS_FLOAT_INVALID_OPERATION
,
112 STATUS_ACCESS_VIOLATION
,
113 STATUS_ACCESS_VIOLATION
,
114 STATUS_ACCESS_VIOLATION
,
115 STATUS_ACCESS_VIOLATION
,
116 STATUS_STACK_OVERFLOW
,
117 STATUS_ACCESS_VIOLATION
,
118 STATUS_ACCESS_VIOLATION
,
119 STATUS_ACCESS_VIOLATION
, /* RESERVED */
120 STATUS_FLOAT_INVALID_OPERATION
, /* Should not be used, the FPU can give more specific info */
121 STATUS_DATATYPE_MISALIGNMENT
,
122 STATUS_ACCESS_VIOLATION
,
123 STATUS_FLOAT_MULTIPLE_TRAPS
,
126 /* FUNCTIONS ****************************************************************/
129 KiRosPrintAddress(PVOID address
)
131 PLIST_ENTRY current_entry
;
132 PLDR_DATA_TABLE_ENTRY current
;
133 extern LIST_ENTRY ModuleListHead
;
134 ULONG_PTR RelativeAddress
;
139 current_entry
= ModuleListHead
.Flink
;
141 while (current_entry
!= &ModuleListHead
)
144 CONTAINING_RECORD(current_entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderModuleList
);
146 if (address
>= (PVOID
)current
->DllBase
&&
147 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+ current
->SizeOfImage
))
149 RelativeAddress
= (ULONG_PTR
) address
- (ULONG_PTR
) current
->DllBase
;
150 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
153 current_entry
= current_entry
->Flink
;
156 address
= (PVOID
)((ULONG_PTR
)address
& ~(ULONG_PTR
)MmSystemRangeStart
);
163 KiKernelTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
167 Er
.ExceptionFlags
= 0;
168 Er
.ExceptionRecord
= NULL
;
169 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
171 if (ExceptionNr
== 14)
173 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
174 Er
.NumberParameters
= 2;
175 Er
.ExceptionInformation
[0] = Tf
->ErrCode
& 0x1;
176 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
180 if (ExceptionNr
< ARRAY_SIZE(ExceptionToNtStatus
))
182 Er
.ExceptionCode
= ExceptionToNtStatus
[ExceptionNr
];
186 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
188 Er
.NumberParameters
= 0;
191 /* FIXME: Which exceptions are noncontinuable? */
192 Er
.ExceptionFlags
= 0;
194 KiDispatchException(&Er
, NULL
, Tf
, KernelMode
, TRUE
);
200 KiDoubleFaultHandler(VOID
)
207 ULONG ExceptionNr
= 8;
213 static PVOID StackTrace
[MM_STACK_SIZE
/ sizeof(PVOID
)];
214 static ULONG StackRepeatCount
[MM_STACK_SIZE
/ sizeof(PVOID
)];
215 static ULONG StackRepeatLength
[MM_STACK_SIZE
/ sizeof(PVOID
)];
220 OldTss
= KeGetCurrentKPCR()->TSS
;
225 if (PsGetCurrentThread() != NULL
&&
226 PsGetCurrentThread()->ThreadsProcess
!= NULL
)
229 PsGetCurrentThread()->ThreadsProcess
->Pcb
.DirectoryTableBase
.QuadPart
;
237 * Check for stack underflow
239 if (PsGetCurrentThread() != NULL
&&
240 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
242 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
243 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
248 * Print out the CPU registers
250 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
252 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
257 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
259 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
260 KeRosPrintAddress((PVOID
)OldTss
->Eip
);
262 DbgPrint("cr2 %x cr3 %x ", cr2
, OldCr3
);
263 DbgPrint("Proc: %x ",PsGetCurrentProcess());
264 if (PsGetCurrentProcess() != NULL
)
266 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
267 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
269 if (PsGetCurrentThread() != NULL
)
271 DbgPrint("Thrd: %x Tid: %x",
272 PsGetCurrentThread(),
273 PsGetCurrentThread()->Cid
.UniqueThread
);
276 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
277 OldTss
->Fs
, OldTss
->Gs
);
278 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
280 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss
->Edx
,
281 OldTss
->Ebp
, OldTss
->Esi
, Esp0
);
282 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
283 if (OldTss
->Cs
== KGDT_R0_CODE
)
285 DbgPrint("kESP %.8x ", Esp0
);
286 if (PsGetCurrentThread() != NULL
)
288 DbgPrint("kernel stack base %x\n",
289 PsGetCurrentThread()->Tcb
.StackLimit
);
295 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
297 if ((OldTss
->Cs
& 0xffff) == KGDT_R0_CODE
)
299 if (PsGetCurrentThread() != NULL
)
301 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
302 StackBase
= (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
;
306 StackLimit
= (ULONG
)init_stack_top
;
307 StackBase
= (ULONG
)init_stack
;
311 Change to an #if 0 to reduce the amount of information printed on
312 a recursive stack trace.
315 DbgPrint("Frames: ");
316 Frame
= (PULONG
)OldTss
->Ebp
;
317 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
319 KeRosPrintAddress((PVOID
)Frame
[1]);
320 Frame
= (PULONG
)Frame
[0];
324 DbgPrint("Frames: ");
326 Frame
= (PULONG
)OldTss
->Ebp
;
327 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
329 StackTrace
[i
] = (PVOID
)Frame
[1];
330 Frame
= (PULONG
)Frame
[0];
336 while (i
< TraceLength
)
338 StackRepeatCount
[i
] = 0;
341 while ((j
- i
) <= (TraceLength
- j
) && FoundRepeat
== FALSE
)
343 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
344 (j
- i
) * sizeof(PVOID
)) == 0)
346 StackRepeatCount
[i
] = 2;
347 StackRepeatLength
[i
] = j
- i
;
355 if (FoundRepeat
== FALSE
)
360 j
= j
+ StackRepeatLength
[i
];
361 while ((TraceLength
- j
) >= StackRepeatLength
[i
] &&
364 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
365 StackRepeatLength
[i
] * sizeof(PVOID
)) == 0)
367 StackRepeatCount
[i
]++;
368 j
= j
+ StackRepeatLength
[i
];
379 while (i
< TraceLength
)
381 if (StackRepeatCount
[i
] == 0)
383 KeRosPrintAddress(StackTrace
[i
]);
389 if (StackRepeatLength
[i
] == 0)
393 for (j
= 0; j
< StackRepeatLength
[i
]; j
++)
395 KeRosPrintAddress(StackTrace
[i
+ j
]);
397 DbgPrint("}*%d", StackRepeatCount
[i
]);
398 i
= i
+ StackRepeatLength
[i
] * StackRepeatCount
[i
];
410 KiDumpTrapFrame(PKTRAP_FRAME Tf
, ULONG Parameter1
, ULONG Parameter2
)
415 ULONG ExceptionNr
= (ULONG
)Tf
->DbgArgMark
;
416 ULONG cr2
= (ULONG
)Tf
->DbgArgPointer
;
421 * Print out the CPU registers
423 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
425 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
426 ExceptionNr
, Tf
->ErrCode
&0xffff);
430 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrCode
&0xffff);
432 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
433 Tf
->SegCs
&0xffff, Tf
->Eip
);
434 KeRosPrintAddress((PVOID
)Tf
->Eip
);
436 Ke386GetPageTableDirectory(cr3_
);
437 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3_
);
438 DbgPrint("Proc: %x ",PsGetCurrentProcess());
439 if (PsGetCurrentProcess() != NULL
)
441 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
442 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
444 if (PsGetCurrentThread() != NULL
)
446 DbgPrint("Thrd: %x Tid: %x",
447 PsGetCurrentThread(),
448 PsGetCurrentThread()->Cid
.UniqueThread
);
451 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->SegDs
&0xffff, Tf
->SegEs
&0xffff,
452 Tf
->SegFs
&0xffff, Tf
->SegGs
&0xfff);
453 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
454 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf
->Edx
,
455 Tf
->Ebp
, Tf
->Esi
, Esp0
);
456 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->EFlags
);
457 if ((Tf
->SegCs
&0xffff) == KGDT_R0_CODE
)
459 DbgPrint("kESP %.8x ", Esp0
);
460 if (PsGetCurrentThread() != NULL
)
462 DbgPrint("kernel stack base %x\n",
463 PsGetCurrentThread()->Tcb
.StackLimit
);
468 if (PsGetCurrentThread() != NULL
)
470 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
474 StackLimit
= (ULONG
)init_stack_top
;
478 * Dump the stack frames
480 KeDumpStackFrames((PULONG
)Tf
->Ebp
);
484 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
486 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
487 * message and halt the computer
489 * Complete CPU context
496 ASSERT(ExceptionNr
!= 14);
498 /* Store the exception number in an unused field in the trap frame. */
499 Tf
->DbgArgMark
= ExceptionNr
;
501 /* Use the address of the trap frame as approximation to the ring0 esp */
502 Esp0
= (ULONG
)&Tf
->Eip
;
506 Tf
->DbgArgPointer
= cr2
;
509 * If this was a V86 mode exception then handle it specially
511 if (Tf
->EFlags
& (1 << 17))
513 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf
->EFlags
, Tf
->Eip
, ExceptionNr
);
514 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
518 * Check for stack underflow, this may be obsolete
520 if (PsGetCurrentThread() != NULL
&&
521 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
523 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
524 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
, Tf
->Eip
);
528 if (ExceptionNr
== 15)
532 * This exception should never occur. The P6 has a bug, which does sometimes deliver
533 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
534 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
535 * sources. Linux does ignore this exception.
539 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
544 * Check for a breakpoint that was only for the attention of the debugger.
546 if (ExceptionNr
== 3 && Tf
->Eip
== ((ULONG
)DbgBreakPointNoBugCheck
) + 1)
549 EIP is already adjusted by the processor to point to the instruction
550 after the breakpoint.
556 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
558 if (ExceptionNr
== 7 || ExceptionNr
== 16 || ExceptionNr
== 19)
560 Status
= KiHandleFpuFault(Tf
, ExceptionNr
);
561 if (NT_SUCCESS(Status
))
568 * Handle user exceptions differently
570 if ((Tf
->SegCs
& 0xFFFF) == (KGDT_R3_CODE
| RPL_MASK
))
572 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
576 return(KiKernelTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
582 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
584 /* Check if this is user-mode or V86 */
585 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& X86_EFLAGS_VM
))
587 /* Return it directly */
588 return TrapFrame
->HardwareEsp
;
593 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
595 /* Return edited value */
596 return TrapFrame
->TempEsp
;
600 /* Virgin frame, calculate */
601 return (ULONG
)&TrapFrame
->HardwareEsp
;
608 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
611 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
613 /* Check if this is user-mode or V86 */
614 if ((TrapFrame
->SegCs
& MODE_MASK
) || (TrapFrame
->EFlags
& X86_EFLAGS_VM
))
616 /* Write it directly */
617 TrapFrame
->HardwareEsp
= Esp
;
621 /* Don't allow ESP to be lowered, this is illegal */
624 KeBugCheck(SET_OF_INVALID_CONTEXT
);
627 /* Create an edit frame, check if it was alrady */
628 if (!(TrapFrame
->SegCs
& FRAME_EDITED
))
630 /* Update the value */
631 TrapFrame
->TempEsp
= Esp
;
635 /* Check if ESP changed */
639 TrapFrame
->TempSegCs
= TrapFrame
->SegCs
;
640 TrapFrame
->SegCs
&= ~FRAME_EDITED
;
643 TrapFrame
->TempEsp
= Esp
;
651 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
653 /* If this was V86 Mode */
654 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
657 return TrapFrame
->HardwareSegSs
;
659 else if (TrapFrame
->SegCs
& MODE_MASK
)
661 /* Usermode, return the User SS */
662 return TrapFrame
->HardwareSegSs
| RPL_MASK
;
673 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
676 /* Remove the high-bits */
679 /* If this was V86 Mode */
680 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
683 TrapFrame
->HardwareSegSs
= Ss
;
685 else if (TrapFrame
->SegCs
& MODE_MASK
)
687 /* Usermode, save the User SS */
688 TrapFrame
->HardwareSegSs
= Ss
| RPL_MASK
;
694 KeContextToTrapFrame(IN PCONTEXT Context
,
695 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
696 IN OUT PKTRAP_FRAME TrapFrame
,
697 IN KPROCESSOR_MODE PreviousMode
)
699 BOOLEAN V86Switch
= FALSE
;
701 /* Start with the basic Registers */
702 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
704 /* Check if we went through a V86 switch */
705 if ((Context
->EFlags
& X86_EFLAGS_VM
) !=
706 (TrapFrame
->EFlags
& X86_EFLAGS_VM
))
708 /* We did, remember this for later */
712 /* Copy EFLAGS. FIXME: Needs to be sanitized */
713 TrapFrame
->EFlags
= Context
->EFlags
;
715 /* Copy EBP and EIP */
716 TrapFrame
->Ebp
= Context
->Ebp
;
717 TrapFrame
->Eip
= Context
->Eip
;
719 /* Check if we were in V86 Mode */
720 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
722 /* Simply copy the CS value */
723 TrapFrame
->SegCs
= Context
->SegCs
;
727 /* We weren't in V86, so sanitize the CS (FIXME!) */
728 TrapFrame
->SegCs
= Context
->SegCs
;
730 /* Don't let it under 8, that's invalid */
731 if ((PreviousMode
!= KernelMode
) && (TrapFrame
->SegCs
< 8))
733 /* Force it to User CS */
734 TrapFrame
->SegCs
= (KGDT_R3_CODE
| RPL_MASK
);
738 /* Handle SS Specially for validation */
739 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
741 /* Write ESP back; take into account Edited Trap Frames */
742 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
744 /* Handle our V86 Bias if we went through a switch */
745 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
748 /* Process the Integer Registers */
749 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
751 TrapFrame
->Eax
= Context
->Eax
;
752 TrapFrame
->Ebx
= Context
->Ebx
;
753 TrapFrame
->Ecx
= Context
->Ecx
;
754 TrapFrame
->Edx
= Context
->Edx
;
755 TrapFrame
->Esi
= Context
->Esi
;
756 TrapFrame
->Edi
= Context
->Edi
;
759 /* Process the Context Segments */
760 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
762 /* Check if we were in V86 Mode */
763 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
765 /* Copy the V86 Segments directlry */
766 TrapFrame
->V86Ds
= Context
->SegDs
;
767 TrapFrame
->V86Es
= Context
->SegEs
;
768 TrapFrame
->V86Fs
= Context
->SegFs
;
769 TrapFrame
->V86Gs
= Context
->SegGs
;
771 else if (!(TrapFrame
->SegCs
& MODE_MASK
))
773 /* For user mode, write the values directly */
774 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
775 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
776 TrapFrame
->SegFs
= Context
->SegFs
;
777 TrapFrame
->SegGs
= 0;
781 /* For kernel-mode, return the values */
782 TrapFrame
->SegDs
= Context
->SegDs
;
783 TrapFrame
->SegEs
= Context
->SegEs
;
784 TrapFrame
->SegFs
= Context
->SegFs
;
786 /* Handle GS specially */
787 if (TrapFrame
->SegCs
== (KGDT_R3_CODE
| RPL_MASK
))
789 /* Don't use it, if user */
790 TrapFrame
->SegGs
= 0;
794 /* Copy it if kernel */
795 TrapFrame
->SegGs
= Context
->SegGs
;
800 /* Handle the Debug Registers */
801 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
803 /* FIXME: All these should be sanitized */
804 TrapFrame
->Dr0
= Context
->Dr0
;
805 TrapFrame
->Dr1
= Context
->Dr1
;
806 TrapFrame
->Dr2
= Context
->Dr2
;
807 TrapFrame
->Dr3
= Context
->Dr3
;
808 TrapFrame
->Dr6
= Context
->Dr6
;
809 TrapFrame
->Dr7
= Context
->Dr7
;
811 /* Check if usermode */
812 if (PreviousMode
!= KernelMode
)
814 /* Set the Debug Flag */
815 KeGetCurrentThread()->DispatcherHeader
.DebugActive
= (Context
->Dr7
& DR7_ACTIVE
);
819 /* Handle FPU and Extended Registers */
820 return KiContextToFxSaveArea((PFX_SAVE_AREA
)(TrapFrame
+ 1), Context
);
825 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
826 IN PKEXCEPTION_FRAME ExceptionFrame
,
827 IN OUT PCONTEXT Context
)
829 PFX_SAVE_AREA FxSaveArea
= NULL
;
831 /* Start with the Control flags */
832 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
834 /* EBP, EIP and EFLAGS */
835 Context
->Ebp
= TrapFrame
->Ebp
;
836 Context
->Eip
= TrapFrame
->Eip
;
837 Context
->EFlags
= TrapFrame
->EFlags
;
839 /* Return the correct CS */
840 if (!(TrapFrame
->SegCs
& FRAME_EDITED
) &&
841 !(TrapFrame
->EFlags
& X86_EFLAGS_VM
))
843 /* Get it from the Temp location */
844 Context
->SegCs
= TrapFrame
->TempSegCs
& 0xFFFF;
848 /* Return it directly */
849 Context
->SegCs
= TrapFrame
->SegCs
& 0xFFFF;
852 /* Get the Ss and ESP */
853 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
854 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
857 /* Handle the Segments */
858 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
860 /* Do V86 Mode first */
861 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
)
863 /* Return from the V86 location */
864 Context
->SegGs
= TrapFrame
->V86Gs
& 0xFFFF;
865 Context
->SegFs
= TrapFrame
->V86Fs
& 0xFFFF;
866 Context
->SegEs
= TrapFrame
->V86Es
& 0xFFFF;
867 Context
->SegDs
= TrapFrame
->V86Ds
& 0xFFFF;
871 /* Check if this was a Kernel Trap */
872 if (TrapFrame
->SegCs
== KGDT_R0_CODE
)
874 /* Set valid selectors */
875 TrapFrame
->SegGs
= 0;
876 TrapFrame
->SegFs
= KGDT_R0_PCR
;
877 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
878 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
881 /* Return the segments */
882 Context
->SegGs
= TrapFrame
->SegGs
& 0xFFFF;
883 Context
->SegFs
= TrapFrame
->SegFs
& 0xFFFF;
884 Context
->SegEs
= TrapFrame
->SegEs
& 0xFFFF;
885 Context
->SegDs
= TrapFrame
->SegDs
& 0xFFFF;
889 /* Handle the simple registers */
890 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
892 /* Return them directly */
893 Context
->Eax
= TrapFrame
->Eax
;
894 Context
->Ebx
= TrapFrame
->Ebx
;
895 Context
->Ecx
= TrapFrame
->Ecx
;
896 Context
->Edx
= TrapFrame
->Edx
;
897 Context
->Esi
= TrapFrame
->Esi
;
898 Context
->Edi
= TrapFrame
->Edi
;
901 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
904 * FIXME: Implement this case
906 Context
->ContextFlags
&= (~CONTEXT_DEBUG_REGISTERS
) | CONTEXT_i386
;
908 if ((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) == CONTEXT_FLOATING_POINT
)
910 FxSaveArea
= KiGetFpuState(KeGetCurrentThread());
911 if (FxSaveArea
!= NULL
)
913 KiFxSaveAreaToFloatingSaveArea(&Context
->FloatSave
, FxSaveArea
);
917 Context
->ContextFlags
&= (~CONTEXT_FLOATING_POINT
) | CONTEXT_i386
;
920 if ((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) == CONTEXT_EXTENDED_REGISTERS
)
922 if (FxSaveArea
== NULL
)
923 FxSaveArea
= KiGetFpuState(KeGetCurrentThread());
924 if (FxSaveArea
!= NULL
)
926 memcpy(Context
->ExtendedRegisters
, &FxSaveArea
->U
.FxArea
,
927 min(sizeof (Context
->ExtendedRegisters
), sizeof (FxSaveArea
->U
.FxArea
)) );
931 Context
->ContextFlags
&= (~CONTEXT_EXTENDED_REGISTERS
) | CONTEXT_i386
;
938 KeDumpStackFrames(PULONG Frame
)
940 PULONG StackBase
, StackEnd
;
941 MEMORY_BASIC_INFORMATION mbi
;
942 ULONG ResultLength
= sizeof(mbi
);
945 DbgPrint("Frames:\n");
948 Status
= MiQueryVirtualMemory (
951 MemoryBasicInformation
,
955 if ( !NT_SUCCESS(Status
) )
957 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
962 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
964 while ( Frame
>= StackBase
&& Frame
< StackEnd
)
966 ULONG Addr
= Frame
[1];
967 if (!KeRosPrintAddress((PVOID
)Addr
))
968 DbgPrint("<%X>", Addr
);
969 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
972 Frame
= (PULONG
)Frame
[0];
984 KeRosDumpStackFrames ( PULONG Frame
, ULONG FrameCount
)
987 PULONG StackBase
, StackEnd
;
988 MEMORY_BASIC_INFORMATION mbi
;
989 ULONG ResultLength
= sizeof(mbi
);
992 DbgPrint("Frames: ");
998 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
999 #elif defined(_MSC_VER)
1000 __asm mov
[Frame
], ebp
1002 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
1005 Status
= MiQueryVirtualMemory (
1008 MemoryBasicInformation
,
1012 if ( !NT_SUCCESS(Status
) )
1014 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1019 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1021 while ( Frame
>= StackBase
&& Frame
< StackEnd
&& i
++ < FrameCount
)
1023 ULONG Addr
= Frame
[1];
1024 if (!KeRosPrintAddress((PVOID
)Addr
))
1025 DbgPrint("<%X>", Addr
);
1026 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
1029 Frame
= (PULONG
)Frame
[0];
1041 KeRosGetStackFrames ( PULONG Frames
, ULONG FrameCount
)
1044 PULONG StackBase
, StackEnd
, Frame
;
1045 MEMORY_BASIC_INFORMATION mbi
;
1046 ULONG ResultLength
= sizeof(mbi
);
1051 #if defined __GNUC__
1052 __asm__("mov %%ebp, %0" : "=r" (Frame
) : );
1053 #elif defined(_MSC_VER)
1054 __asm mov
[Frame
], ebp
1057 Status
= MiQueryVirtualMemory (
1060 MemoryBasicInformation
,
1064 if ( !NT_SUCCESS(Status
) )
1066 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1071 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1073 while ( Count
< FrameCount
&& Frame
>= StackBase
&& Frame
< StackEnd
)
1075 Frames
[Count
++] = Frame
[1];
1077 Frame
= (PULONG
)Frame
[0];
1088 set_system_call_gate(unsigned int sel
, unsigned int func
)
1090 DPRINT("sel %x %d\n",sel
,sel
);
1091 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
1092 (KGDT_R0_CODE
<< 16);
1093 KiIdt
[sel
].b
= 0xef00 + (((int)func
)&0xffff0000);
1094 DPRINT("idt[sel].b %x\n",KiIdt
[sel
].b
);
1097 static void set_interrupt_gate(unsigned int sel
, unsigned int func
)
1099 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel
,func
);
1100 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
1101 (KGDT_R0_CODE
<< 16);
1102 KiIdt
[sel
].b
= 0x8e00 + (((int)func
)&0xffff0000);
1105 static void set_trap_gate(unsigned int sel
, unsigned int func
, unsigned int dpl
)
1107 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel
, func
, dpl
);
1109 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
1110 (KGDT_R0_CODE
<< 16);
1111 KiIdt
[sel
].b
= 0x8f00 + (dpl
<< 13) + (((int)func
)&0xffff0000);
1115 set_task_gate(unsigned int sel
, unsigned task_sel
)
1117 KiIdt
[sel
].a
= task_sel
<< 16;
1118 KiIdt
[sel
].b
= 0x8500;
1124 KeInitExceptions(VOID
)
1126 * FUNCTION: Initalize CPU exception handling
1131 DPRINT("KeInitExceptions()\n");
1134 * Set up the other gates
1136 set_trap_gate(0, (ULONG
)KiTrap0
, 0);
1137 set_trap_gate(1, (ULONG
)KiTrap1
, 0);
1138 set_trap_gate(2, (ULONG
)KiTrap2
, 0);
1139 set_trap_gate(3, (ULONG
)KiTrap3
, 3);
1140 set_trap_gate(4, (ULONG
)KiTrap4
, 0);
1141 set_trap_gate(5, (ULONG
)KiTrap5
, 0);
1142 set_trap_gate(6, (ULONG
)KiTrap6
, 0);
1143 set_trap_gate(7, (ULONG
)KiTrap7
, 0);
1144 set_task_gate(8, KGDT_DF_TSS
);
1145 set_trap_gate(9, (ULONG
)KiTrap9
, 0);
1146 set_trap_gate(10, (ULONG
)KiTrap10
, 0);
1147 set_trap_gate(11, (ULONG
)KiTrap11
, 0);
1148 set_trap_gate(12, (ULONG
)KiTrap12
, 0);
1149 set_trap_gate(13, (ULONG
)KiTrap13
, 0);
1150 set_interrupt_gate(14, (ULONG
)KiTrap14
);
1151 set_trap_gate(15, (ULONG
)KiTrap15
, 0);
1152 set_trap_gate(16, (ULONG
)KiTrap16
, 0);
1153 set_trap_gate(17, (ULONG
)KiTrap17
, 0);
1154 set_trap_gate(18, (ULONG
)KiTrap18
, 0);
1155 set_trap_gate(19, (ULONG
)KiTrap19
, 0);
1157 for (i
= 20; i
< 256; i
++)
1159 set_trap_gate(i
,(int)KiTrapUnknown
, 0);
1162 set_system_call_gate(0x2d,(int)KiDebugService
);
1163 set_system_call_gate(0x2e,(int)KiSystemService
);
1168 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord
,
1169 PKEXCEPTION_FRAME ExceptionFrame
,
1170 PKTRAP_FRAME TrapFrame
,
1171 KPROCESSOR_MODE PreviousMode
,
1172 BOOLEAN FirstChance
)
1175 KD_CONTINUE_TYPE Action
;
1176 ULONG_PTR Stack
, NewStack
;
1178 BOOLEAN UserDispatch
= FALSE
;
1179 DPRINT("KiDispatchException() called\n");
1181 /* Increase number of Exception Dispatches */
1182 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
1184 /* Set the context flags */
1185 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
1187 /* Check if User Mode */
1188 if (PreviousMode
== UserMode
)
1190 extern ULONG FxsrSupport
;
1191 /* Add the FPU Flag */
1192 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
1194 Context
.ContextFlags
|= CONTEXT_EXTENDED_REGISTERS
;
1198 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
1200 /* Handle kernel-mode first, it's simpler */
1201 if (PreviousMode
== KernelMode
)
1203 /* Check if this is a first-chance exception */
1204 if (FirstChance
== TRUE
)
1206 /* Break into the debugger for the first time */
1207 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1214 /* If the debugger said continue, then continue */
1215 if (Action
== kdContinue
) goto Handled
;
1217 /* If the Debugger couldn't handle it, dispatch the exception */
1218 if (RtlDispatchException(ExceptionRecord
, &Context
))
1220 /* It was handled by an exception handler, continue */
1225 /* This is a second-chance exception, only for the debugger */
1226 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1233 /* If the debugger said continue, then continue */
1234 if (Action
== kdContinue
) goto Handled
;
1236 /* Third strike; you're out */
1237 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1238 ExceptionRecord
->ExceptionCode
,
1239 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1240 ExceptionRecord
->ExceptionInformation
[0],
1241 ExceptionRecord
->ExceptionInformation
[1],
1246 /* User mode exception, was it first-chance? */
1249 /* Enter Debugger if available */
1250 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1257 /* Exit if we're continuing */
1258 if (Action
== kdContinue
) goto Handled
;
1260 /* FIXME: Forward exception to user mode debugger */
1262 /* Set up the user-stack */
1265 /* Align context size and get stack pointer */
1266 Size
= (sizeof(CONTEXT
) + 3) & ~3;
1267 Stack
= (Context
.Esp
& ~3) - Size
;
1268 DPRINT("Stack: %lx\n", Stack
);
1270 /* Probe stack and copy Context */
1271 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
1272 RtlCopyMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
1274 /* Align exception record size and get stack pointer */
1275 Size
= (sizeof(EXCEPTION_RECORD
) -
1276 (EXCEPTION_MAXIMUM_PARAMETERS
- ExceptionRecord
->NumberParameters
) *
1277 sizeof(ULONG
) + 3) & ~3;
1278 NewStack
= Stack
- Size
;
1279 DPRINT("NewStack: %lx\n", NewStack
);
1281 /* Probe stack and copy exception record. Don't forget to add the two params */
1282 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1283 Size
+ 2 * sizeof(ULONG_PTR
),
1285 RtlCopyMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1287 /* Now write the two params for the user-mode dispatcher */
1288 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1289 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1291 /* Set new Stack Pointer */
1292 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
1294 /* Set EIP to the User-mode Dispathcer */
1295 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1296 UserDispatch
= TRUE
;
1301 /* Do second-chance */
1306 /* If we dispatch to user, return now */
1307 if (UserDispatch
) return;
1309 /* FIXME: Forward the exception to the debugger for 2nd chance */
1311 /* 3rd strike, kill the thread */
1312 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1313 ZwTerminateThread(NtCurrentThread(), ExceptionRecord
->ExceptionCode
);
1314 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1315 ExceptionRecord
->ExceptionCode
,
1316 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1317 ExceptionRecord
->ExceptionInformation
[0],
1318 ExceptionRecord
->ExceptionInformation
[1],
1323 /* Convert the context back into Trap/Exception Frames */
1324 KeContextToTrapFrame(&Context
, NULL
, TrapFrame
, PreviousMode
);
1332 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1335 PKTHREAD Thread
= KeGetCurrentThread();
1338 Thread
->Teb
->ExceptionCode
= ExceptionCode
;
1340 return(ExceptionCode
);
1343 OldEip
= Thread
->TrapFrame
->Eip
;
1344 Thread
->TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1345 return((NTSTATUS
)OldEip
);