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>
22 * - Sanitize some context fields.
23 * - Add PSEH handler when an exception occurs in an exception (KiCopyExceptionRecord).
24 * - Implement official stack trace functions (exported) and remove stuff here.
25 * - Forward exceptions to user-mode debugger.
30 Ki386AdjustEsp0(IN PKTRAP_FRAME TrapFrame
);
32 /* GLOBALS *****************************************************************/
34 #define FLAG_IF (1<<9)
37 #define STR(x) _STR(x)
40 # define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
43 extern void KiSystemService(void);
44 extern void KiDebugService(void);
46 extern VOID
KiTrap0(VOID
);
47 extern VOID
KiTrap1(VOID
);
48 extern VOID
KiTrap2(VOID
);
49 extern VOID
KiTrap3(VOID
);
50 extern VOID
KiTrap4(VOID
);
51 extern VOID
KiTrap5(VOID
);
52 extern VOID
KiTrap6(VOID
);
53 extern VOID
KiTrap7(VOID
);
54 extern VOID
KiTrap8(VOID
);
55 extern VOID
KiTrap9(VOID
);
56 extern VOID
KiTrap10(VOID
);
57 extern VOID
KiTrap11(VOID
);
58 extern VOID
KiTrap12(VOID
);
59 extern VOID
KiTrap13(VOID
);
60 extern VOID
KiTrap14(VOID
);
61 extern VOID
KiTrap15(VOID
);
62 extern VOID
KiTrap16(VOID
);
63 extern VOID
KiTrap17(VOID
);
64 extern VOID
KiTrap18(VOID
);
65 extern VOID
KiTrap19(VOID
);
66 extern VOID
KiTrapUnknown(VOID
);
68 extern ULONG init_stack
;
69 extern ULONG init_stack_top
;
71 extern BOOLEAN Ke386NoExecute
;
73 static char *ExceptionTypeStrings
[] =
80 "BOUND range exceeded",
82 "No Math Coprocessor",
86 "Segment Not Present",
87 "Stack Segment Fault",
97 NTSTATUS ExceptionToNtStatus
[] =
99 STATUS_INTEGER_DIVIDE_BY_ZERO
,
101 STATUS_ACCESS_VIOLATION
,
103 STATUS_INTEGER_OVERFLOW
,
104 STATUS_ARRAY_BOUNDS_EXCEEDED
,
105 STATUS_ILLEGAL_INSTRUCTION
,
106 STATUS_FLOAT_INVALID_OPERATION
,
107 STATUS_ACCESS_VIOLATION
,
108 STATUS_ACCESS_VIOLATION
,
109 STATUS_ACCESS_VIOLATION
,
110 STATUS_ACCESS_VIOLATION
,
111 STATUS_STACK_OVERFLOW
,
112 STATUS_ACCESS_VIOLATION
,
113 STATUS_ACCESS_VIOLATION
,
114 STATUS_ACCESS_VIOLATION
, /* RESERVED */
115 STATUS_FLOAT_INVALID_OPERATION
, /* Should not be used, the FPU can give more specific info */
116 STATUS_DATATYPE_MISALIGNMENT
,
117 STATUS_ACCESS_VIOLATION
,
118 STATUS_FLOAT_MULTIPLE_TRAPS
,
121 /* FUNCTIONS ****************************************************************/
124 KiRosPrintAddress(PVOID address
)
126 PLIST_ENTRY current_entry
;
127 PLDR_DATA_TABLE_ENTRY current
;
128 extern LIST_ENTRY ModuleListHead
;
129 ULONG_PTR RelativeAddress
;
134 current_entry
= ModuleListHead
.Flink
;
136 while (current_entry
!= &ModuleListHead
)
139 CONTAINING_RECORD(current_entry
, LDR_DATA_TABLE_ENTRY
, InLoadOrderModuleList
);
141 if (address
>= (PVOID
)current
->DllBase
&&
142 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+ current
->SizeOfImage
))
144 RelativeAddress
= (ULONG_PTR
) address
- (ULONG_PTR
) current
->DllBase
;
145 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
148 current_entry
= current_entry
->Flink
;
151 address
= (PVOID
)((ULONG_PTR
)address
& ~(ULONG_PTR
)MmSystemRangeStart
);
158 KiKernelTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
, PVOID Cr2
)
162 Er
.ExceptionFlags
= 0;
163 Er
.ExceptionRecord
= NULL
;
164 Er
.ExceptionAddress
= (PVOID
)Tf
->Eip
;
166 if (ExceptionNr
== 14)
168 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
169 Er
.NumberParameters
= 2;
170 Er
.ExceptionInformation
[0] = Tf
->ErrorCode
& 0x1;
171 Er
.ExceptionInformation
[1] = (ULONG
)Cr2
;
175 if (ExceptionNr
< ARRAY_SIZE(ExceptionToNtStatus
))
177 Er
.ExceptionCode
= ExceptionToNtStatus
[ExceptionNr
];
181 Er
.ExceptionCode
= STATUS_ACCESS_VIOLATION
;
183 Er
.NumberParameters
= 0;
186 /* FIXME: Which exceptions are noncontinuable? */
187 Er
.ExceptionFlags
= 0;
189 KiDispatchException(&Er
, NULL
, Tf
, KernelMode
, TRUE
);
195 KiDoubleFaultHandler(VOID
)
201 ULONG ExceptionNr
= 8;
207 static PVOID StackTrace
[MM_STACK_SIZE
/ sizeof(PVOID
)];
208 static ULONG StackRepeatCount
[MM_STACK_SIZE
/ sizeof(PVOID
)];
209 static ULONG StackRepeatLength
[MM_STACK_SIZE
/ sizeof(PVOID
)];
214 OldTss
= KeGetCurrentKPCR()->TSS
;
219 if (PsGetCurrentThread() != NULL
&&
220 PsGetCurrentThread()->ThreadsProcess
!= NULL
)
223 PsGetCurrentThread()->ThreadsProcess
->Pcb
.DirectoryTableBase
.QuadPart
;
231 * Check for stack underflow
233 if (PsGetCurrentThread() != NULL
&&
234 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
236 DbgPrint("Stack underflow (tf->esp %x Limit %x)\n",
237 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
);
242 * Print out the CPU registers
244 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
246 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
251 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, 0);
253 DbgPrint("CS:EIP %x:%x ", OldTss
->Cs
, OldTss
->Eip
);
254 KeRosPrintAddress((PVOID
)OldTss
->Eip
);
256 DbgPrint("cr2 %x cr3 %x ", cr2
, OldCr3
);
257 DbgPrint("Proc: %x ",PsGetCurrentProcess());
258 if (PsGetCurrentProcess() != NULL
)
260 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
261 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
263 if (PsGetCurrentThread() != NULL
)
265 DbgPrint("Thrd: %x Tid: %x",
266 PsGetCurrentThread(),
267 PsGetCurrentThread()->Cid
.UniqueThread
);
270 DbgPrint("DS %x ES %x FS %x GS %x\n", OldTss
->Ds
, OldTss
->Es
,
271 OldTss
->Fs
, OldTss
->Gs
);
272 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", OldTss
->Eax
, OldTss
->Ebx
,
274 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x\nESP: %.8x ", OldTss
->Edx
,
275 OldTss
->Ebp
, OldTss
->Esi
, Esp0
);
276 DbgPrint("EDI: %.8x EFLAGS: %.8x ", OldTss
->Edi
, OldTss
->Eflags
);
277 if (OldTss
->Cs
== KERNEL_CS
)
279 DbgPrint("kESP %.8x ", Esp0
);
280 if (PsGetCurrentThread() != NULL
)
282 DbgPrint("kernel stack base %x\n",
283 PsGetCurrentThread()->Tcb
.StackLimit
);
289 DbgPrint("User ESP %.8x\n", OldTss
->Esp
);
291 if ((OldTss
->Cs
& 0xffff) == KERNEL_CS
)
293 if (PsGetCurrentThread() != NULL
)
295 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
296 StackBase
= (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
;
300 StackLimit
= (ULONG
)init_stack_top
;
301 StackBase
= (ULONG
)init_stack
;
305 Change to an #if 0 to reduce the amount of information printed on
306 a recursive stack trace.
309 DbgPrint("Frames: ");
310 Frame
= (PULONG
)OldTss
->Ebp
;
311 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
313 KeRosPrintAddress((PVOID
)Frame
[1]);
314 Frame
= (PULONG
)Frame
[0];
318 DbgPrint("Frames: ");
320 Frame
= (PULONG
)OldTss
->Ebp
;
321 while (Frame
!= NULL
&& (ULONG
)Frame
>= StackBase
)
323 StackTrace
[i
] = (PVOID
)Frame
[1];
324 Frame
= (PULONG
)Frame
[0];
330 while (i
< TraceLength
)
332 StackRepeatCount
[i
] = 0;
335 while ((j
- i
) <= (TraceLength
- j
) && FoundRepeat
== FALSE
)
337 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
338 (j
- i
) * sizeof(PVOID
)) == 0)
340 StackRepeatCount
[i
] = 2;
341 StackRepeatLength
[i
] = j
- i
;
349 if (FoundRepeat
== FALSE
)
354 j
= j
+ StackRepeatLength
[i
];
355 while ((TraceLength
- j
) >= StackRepeatLength
[i
] &&
358 if (memcmp(&StackTrace
[i
], &StackTrace
[j
],
359 StackRepeatLength
[i
] * sizeof(PVOID
)) == 0)
361 StackRepeatCount
[i
]++;
362 j
= j
+ StackRepeatLength
[i
];
373 while (i
< TraceLength
)
375 if (StackRepeatCount
[i
] == 0)
377 KeRosPrintAddress(StackTrace
[i
]);
383 if (StackRepeatLength
[i
] == 0)
387 for (j
= 0; j
< StackRepeatLength
[i
]; j
++)
389 KeRosPrintAddress(StackTrace
[i
+ j
]);
391 DbgPrint("}*%d", StackRepeatCount
[i
]);
392 i
= i
+ StackRepeatLength
[i
] * StackRepeatCount
[i
];
404 KiDumpTrapFrame(PKTRAP_FRAME Tf
, ULONG Parameter1
, ULONG Parameter2
)
409 ULONG ExceptionNr
= (ULONG
)Tf
->DebugArgMark
;
410 ULONG cr2
= (ULONG
)Tf
->DebugPointer
;
415 * Print out the CPU registers
417 if (ExceptionNr
< ARRAY_SIZE(ExceptionTypeStrings
))
419 DbgPrint("%s Exception: %d(%x)\n", ExceptionTypeStrings
[ExceptionNr
],
420 ExceptionNr
, Tf
->ErrorCode
&0xffff);
424 DbgPrint("Exception: %d(%x)\n", ExceptionNr
, Tf
->ErrorCode
&0xffff);
426 DbgPrint("Processor: %d CS:EIP %x:%x ", KeGetCurrentProcessorNumber(),
427 Tf
->Cs
&0xffff, Tf
->Eip
);
428 KeRosPrintAddress((PVOID
)Tf
->Eip
);
430 Ke386GetPageTableDirectory(cr3_
);
431 DbgPrint("cr2 %x cr3 %x ", cr2
, cr3_
);
432 DbgPrint("Proc: %x ",PsGetCurrentProcess());
433 if (PsGetCurrentProcess() != NULL
)
435 DbgPrint("Pid: %x <", PsGetCurrentProcess()->UniqueProcessId
);
436 DbgPrint("%.16s> ", PsGetCurrentProcess()->ImageFileName
);
438 if (PsGetCurrentThread() != NULL
)
440 DbgPrint("Thrd: %x Tid: %x",
441 PsGetCurrentThread(),
442 PsGetCurrentThread()->Cid
.UniqueThread
);
445 DbgPrint("DS %x ES %x FS %x GS %x\n", Tf
->Ds
&0xffff, Tf
->Es
&0xffff,
446 Tf
->Fs
&0xffff, Tf
->Gs
&0xfff);
447 DbgPrint("EAX: %.8x EBX: %.8x ECX: %.8x\n", Tf
->Eax
, Tf
->Ebx
, Tf
->Ecx
);
448 DbgPrint("EDX: %.8x EBP: %.8x ESI: %.8x ESP: %.8x\n", Tf
->Edx
,
449 Tf
->Ebp
, Tf
->Esi
, Esp0
);
450 DbgPrint("EDI: %.8x EFLAGS: %.8x ", Tf
->Edi
, Tf
->Eflags
);
451 if ((Tf
->Cs
&0xffff) == KERNEL_CS
)
453 DbgPrint("kESP %.8x ", Esp0
);
454 if (PsGetCurrentThread() != NULL
)
456 DbgPrint("kernel stack base %x\n",
457 PsGetCurrentThread()->Tcb
.StackLimit
);
462 if (PsGetCurrentThread() != NULL
)
464 StackLimit
= (ULONG
)PsGetCurrentThread()->Tcb
.StackBase
;
468 StackLimit
= (ULONG
)init_stack_top
;
472 * Dump the stack frames
474 KeDumpStackFrames((PULONG
)Tf
->Ebp
);
478 KiTrapHandler(PKTRAP_FRAME Tf
, ULONG ExceptionNr
)
480 * FUNCTION: Called by the lowlevel execption handlers to print an amusing
481 * message and halt the computer
483 * Complete CPU context
490 ASSERT(ExceptionNr
!= 14);
492 /* Store the exception number in an unused field in the trap frame. */
493 Tf
->DebugArgMark
= ExceptionNr
;
495 /* Use the address of the trap frame as approximation to the ring0 esp */
496 Esp0
= (ULONG
)&Tf
->Eip
;
500 Tf
->DebugPointer
= cr2
;
503 * If this was a V86 mode exception then handle it specially
505 if (Tf
->Eflags
& (1 << 17))
507 DPRINT("Tf->Eflags, %x, Tf->Eip %x, ExceptionNr: %d\n", Tf
->Eflags
, Tf
->Eip
, ExceptionNr
);
508 return(KeV86Exception(ExceptionNr
, Tf
, cr2
));
512 * Check for stack underflow, this may be obsolete
514 if (PsGetCurrentThread() != NULL
&&
515 Esp0
< (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
)
517 DPRINT1("Stack underflow (tf->esp %x Limit %x Eip %x)\n",
518 Esp0
, (ULONG
)PsGetCurrentThread()->Tcb
.StackLimit
, Tf
->Eip
);
522 if (ExceptionNr
== 15)
526 * This exception should never occur. The P6 has a bug, which does sometimes deliver
527 * the apic spurious interrupt as exception 15. On an athlon64, I get one exception
528 * in the early boot phase in apic mode (using the smp build). I've looked to the linux
529 * sources. Linux does ignore this exception.
533 DPRINT1("Ignoring P6 Local APIC Spurious Interrupt Bug...\n");
538 * Check for a breakpoint that was only for the attention of the debugger.
540 if (ExceptionNr
== 3 && Tf
->Eip
== ((ULONG
)DbgBreakPointNoBugCheck
) + 1)
543 EIP is already adjusted by the processor to point to the instruction
544 after the breakpoint.
550 * Try to handle device-not-present, math-fault and xmm-fault exceptions.
552 if (ExceptionNr
== 7 || ExceptionNr
== 16 || ExceptionNr
== 19)
554 Status
= KiHandleFpuFault(Tf
, ExceptionNr
);
555 if (NT_SUCCESS(Status
))
562 * Handle user exceptions differently
564 if ((Tf
->Cs
& 0xFFFF) == USER_CS
)
566 return(KiUserTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
570 return(KiKernelTrapHandler(Tf
, ExceptionNr
, (PVOID
)cr2
));
576 KiEspFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
578 /* Check if this is user-mode or V86 */
579 if ((TrapFrame
->Cs
& 1) || (TrapFrame
->Eflags
& X86_EFLAGS_VM
))
581 /* Return it directly */
582 return TrapFrame
->Esp
;
587 if (!(TrapFrame
->Cs
& FRAME_EDITED
))
589 /* Return edited value */
590 return TrapFrame
->TempEsp
;
594 /* Virgin frame, calculate */
595 return (ULONG
)&TrapFrame
->Esp
;
602 KiEspToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
605 ULONG Previous
= KiEspFromTrapFrame(TrapFrame
);
607 /* Check if this is user-mode or V86 */
608 if ((TrapFrame
->Cs
& 1) || (TrapFrame
->Eflags
& X86_EFLAGS_VM
))
610 /* Write it directly */
611 TrapFrame
->Esp
= Esp
;
615 /* Don't allow ESP to be lowered, this is illegal */
618 KeBugCheck(SET_OF_INVALID_CONTEXT
);
621 /* Create an edit frame, check if it was alrady */
622 if (!(TrapFrame
->Cs
& FRAME_EDITED
))
624 /* Update the value */
625 TrapFrame
->TempEsp
= Esp
;
629 /* Check if ESP changed */
633 TrapFrame
->TempCs
= TrapFrame
->Cs
;
634 TrapFrame
->Cs
&= ~FRAME_EDITED
;
637 TrapFrame
->TempEsp
= Esp
;
645 KiSsFromTrapFrame(IN PKTRAP_FRAME TrapFrame
)
647 /* If this was V86 Mode */
648 if (TrapFrame
->Eflags
& X86_EFLAGS_VM
)
651 return TrapFrame
->Ss
;
653 else if (TrapFrame
->Cs
& 1)
655 /* Usermode, return the User SS */
656 return TrapFrame
->Ss
| 3;
667 KiSsToTrapFrame(IN PKTRAP_FRAME TrapFrame
,
670 /* Remove the high-bits */
673 /* If this was V86 Mode */
674 if (TrapFrame
->Eflags
& X86_EFLAGS_VM
)
679 else if (TrapFrame
->Cs
& 1)
681 /* Usermode, save the User SS */
682 TrapFrame
->Ss
= Ss
| 3;
688 KeContextToTrapFrame(IN PCONTEXT Context
,
689 IN OUT PKEXCEPTION_FRAME ExceptionFrame
,
690 IN OUT PKTRAP_FRAME TrapFrame
,
691 IN KPROCESSOR_MODE PreviousMode
)
693 BOOLEAN V86Switch
= FALSE
;
695 /* Start with the basic Registers */
696 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
698 /* Check if we went through a V86 switch */
699 if ((Context
->EFlags
& X86_EFLAGS_VM
) !=
700 (TrapFrame
->Eflags
& X86_EFLAGS_VM
))
702 /* We did, remember this for later */
706 /* Copy EFLAGS. FIXME: Needs to be sanitized */
707 TrapFrame
->Eflags
= Context
->EFlags
;
709 /* Copy EBP and EIP */
710 TrapFrame
->Ebp
= Context
->Ebp
;
711 TrapFrame
->Eip
= Context
->Eip
;
713 /* Check if we were in V86 Mode */
714 if (TrapFrame
->Eflags
& X86_EFLAGS_VM
)
716 /* Simply copy the CS value */
717 TrapFrame
->Cs
= Context
->SegCs
;
721 /* We weren't in V86, so sanitize the CS (FIXME!) */
722 TrapFrame
->Cs
= Context
->SegCs
;
724 /* Don't let it under 8, that's invalid */
725 if ((PreviousMode
!=KernelMode
) && (TrapFrame
->Cs
< 8))
727 /* Force it to User CS */
728 TrapFrame
->Cs
= USER_CS
;
732 /* Handle SS Specially for validation */
733 KiSsToTrapFrame(TrapFrame
, Context
->SegSs
);
735 /* Write ESP back; take into account Edited Trap Frames */
736 KiEspToTrapFrame(TrapFrame
, Context
->Esp
);
738 /* Handle our V86 Bias if we went through a switch */
739 if (V86Switch
) Ki386AdjustEsp0(TrapFrame
);
742 /* Process the Integer Registers */
743 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
745 TrapFrame
->Eax
= Context
->Eax
;
746 TrapFrame
->Ebx
= Context
->Ebx
;
747 TrapFrame
->Ecx
= Context
->Ecx
;
748 TrapFrame
->Edx
= Context
->Edx
;
749 TrapFrame
->Esi
= Context
->Esi
;
750 TrapFrame
->Edi
= Context
->Edi
;
753 /* Process the Context Segments */
754 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
756 /* Check if we were in V86 Mode */
757 if (TrapFrame
->Eflags
& X86_EFLAGS_VM
)
759 /* Copy the V86 Segments directlry */
760 TrapFrame
->V86_Ds
= Context
->SegDs
;
761 TrapFrame
->V86_Es
= Context
->SegEs
;
762 TrapFrame
->V86_Fs
= Context
->SegFs
;
763 TrapFrame
->V86_Gs
= Context
->SegGs
;
765 else if (!(TrapFrame
->Cs
& 1))
767 /* For user mode, write the values directly */
768 TrapFrame
->Ds
= USER_DS
;
769 TrapFrame
->Es
= USER_DS
;
770 TrapFrame
->Fs
= Context
->SegFs
;
775 /* For kernel-mode, return the values */
776 TrapFrame
->Ds
= Context
->SegDs
;
777 TrapFrame
->Es
= Context
->SegEs
;
778 TrapFrame
->Fs
= Context
->SegFs
;
780 /* Handle GS specially */
781 if (TrapFrame
->Cs
== USER_CS
)
783 /* Don't use it, if user */
788 /* Copy it if kernel */
789 TrapFrame
->Gs
= Context
->SegGs
;
794 /* Handle the Debug Registers */
795 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
797 /* FIXME: All these should be sanitized */
798 TrapFrame
->Dr0
= Context
->Dr0
;
799 TrapFrame
->Dr1
= Context
->Dr1
;
800 TrapFrame
->Dr2
= Context
->Dr2
;
801 TrapFrame
->Dr3
= Context
->Dr3
;
802 TrapFrame
->Dr6
= Context
->Dr6
;
803 TrapFrame
->Dr7
= Context
->Dr7
;
805 /* Check if usermode */
806 if (PreviousMode
!= KernelMode
)
808 /* Set the Debug Flag */
809 KeGetCurrentThread()->DebugActive
= (Context
->Dr7
& DR7_ACTIVE
);
813 /* Handle FPU and Extended Registers */
814 return KiContextToFxSaveArea((PFX_SAVE_AREA
)(TrapFrame
+ 1), Context
);
819 KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame
,
820 IN PKEXCEPTION_FRAME ExceptionFrame
,
821 IN OUT PCONTEXT Context
)
823 /* Start with the Control flags */
824 if ((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
)
826 /* EBP, EIP and EFLAGS */
827 Context
->Ebp
= TrapFrame
->Ebp
;
828 Context
->Eip
= TrapFrame
->Eip
;
829 Context
->EFlags
= TrapFrame
->Eflags
;
831 /* Return the correct CS */
832 if (!(TrapFrame
->Cs
& FRAME_EDITED
) &&
833 !(TrapFrame
->Eflags
& X86_EFLAGS_VM
))
835 /* Get it from the Temp location */
836 Context
->SegCs
= TrapFrame
->TempCs
& 0xFFFF;
840 /* Return it directly */
841 Context
->SegCs
= TrapFrame
->Cs
& 0xFFFF;
844 /* Get the Ss and ESP */
845 Context
->SegSs
= KiSsFromTrapFrame(TrapFrame
);
846 Context
->Esp
= KiEspFromTrapFrame(TrapFrame
);
849 /* Handle the Segments */
850 if ((Context
->ContextFlags
& CONTEXT_SEGMENTS
) == CONTEXT_SEGMENTS
)
852 /* Do V86 Mode first */
853 if (TrapFrame
->Eflags
& X86_EFLAGS_VM
)
855 /* Return from the V86 location */
856 Context
->SegGs
= TrapFrame
->V86_Gs
& 0xFFFF;
857 Context
->SegFs
= TrapFrame
->V86_Fs
& 0xFFFF;
858 Context
->SegEs
= TrapFrame
->V86_Es
& 0xFFFF;
859 Context
->SegDs
= TrapFrame
->V86_Ds
& 0xFFFF;
863 /* Check if this was a Kernel Trap */
864 if (TrapFrame
->Cs
== KERNEL_CS
)
866 /* Set valid selectors */
868 TrapFrame
->Fs
= PCR_SELECTOR
;
869 TrapFrame
->Es
= USER_DS
;
870 TrapFrame
->Ds
= USER_DS
;
873 /* Return the segments */
874 Context
->SegGs
= TrapFrame
->Gs
& 0xFFFF;
875 Context
->SegFs
= TrapFrame
->Fs
& 0xFFFF;
876 Context
->SegEs
= TrapFrame
->Es
& 0xFFFF;
877 Context
->SegDs
= TrapFrame
->Ds
& 0xFFFF;
881 /* Handle the simple registers */
882 if ((Context
->ContextFlags
& CONTEXT_INTEGER
) == CONTEXT_INTEGER
)
884 /* Return them directly */
885 Context
->Eax
= TrapFrame
->Eax
;
886 Context
->Ebx
= TrapFrame
->Ebx
;
887 Context
->Ecx
= TrapFrame
->Ecx
;
888 Context
->Edx
= TrapFrame
->Edx
;
889 Context
->Esi
= TrapFrame
->Esi
;
890 Context
->Edi
= TrapFrame
->Edi
;
893 if ((Context
->ContextFlags
& CONTEXT_DEBUG_REGISTERS
) == CONTEXT_DEBUG_REGISTERS
)
896 * FIXME: Implement this case
898 Context
->ContextFlags
&= (~CONTEXT_DEBUG_REGISTERS
) | CONTEXT_i386
;
900 if ((Context
->ContextFlags
& CONTEXT_FLOATING_POINT
) == CONTEXT_FLOATING_POINT
)
903 * FIXME: Implement this case
905 * I think this should only be filled for FPU exceptions, otherwise I
906 * would not know where to get it from as it can be the current state
907 * of the FPU or already saved in the thread's FPU save area.
910 Context
->ContextFlags
&= (~CONTEXT_FLOATING_POINT
) | CONTEXT_i386
;
913 if ((Context
->ContextFlags
& CONTEXT_EXTENDED_REGISTERS
) == CONTEXT_EXTENDED_REGISTERS
)
916 * FIXME: Investigate this
918 * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA)
919 * This should only be filled in case of a SIMD exception I think, so
920 * this is not the right place (like for FPU the state could already be
921 * saved in the thread's FX_SAVE_AREA or still be in the CPU)
924 Context
->ContextFlags
&= ~CONTEXT_EXTENDED_REGISTERS
;
931 KeDumpStackFrames(PULONG Frame
)
933 PULONG StackBase
, StackEnd
;
934 MEMORY_BASIC_INFORMATION mbi
;
935 ULONG ResultLength
= sizeof(mbi
);
938 DbgPrint("Frames:\n");
941 Status
= MiQueryVirtualMemory (
944 MemoryBasicInformation
,
948 if ( !NT_SUCCESS(Status
) )
950 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
955 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
957 while ( Frame
>= StackBase
&& Frame
< StackEnd
)
959 ULONG Addr
= Frame
[1];
960 if (!KeRosPrintAddress((PVOID
)Addr
))
961 DbgPrint("<%X>", Addr
);
962 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
965 Frame
= (PULONG
)Frame
[0];
977 KeRosDumpStackFrames ( PULONG Frame
, ULONG FrameCount
)
980 PULONG StackBase
, StackEnd
;
981 MEMORY_BASIC_INFORMATION mbi
;
982 ULONG ResultLength
= sizeof(mbi
);
985 DbgPrint("Frames: ");
991 __asm__("mov %%ebp, %%ebx" : "=b" (Frame
) : );
992 #elif defined(_MSC_VER)
993 __asm mov
[Frame
], ebp
995 //Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
998 Status
= MiQueryVirtualMemory (
1001 MemoryBasicInformation
,
1005 if ( !NT_SUCCESS(Status
) )
1007 DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1012 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1014 while ( Frame
>= StackBase
&& Frame
< StackEnd
&& i
++ < FrameCount
)
1016 ULONG Addr
= Frame
[1];
1017 if (!KeRosPrintAddress((PVOID
)Addr
))
1018 DbgPrint("<%X>", Addr
);
1019 if ( Addr
== 0 || Addr
== 0xDEADBEEF )
1022 Frame
= (PULONG
)Frame
[0];
1034 KeRosGetStackFrames ( PULONG Frames
, ULONG FrameCount
)
1037 PULONG StackBase
, StackEnd
, Frame
;
1038 MEMORY_BASIC_INFORMATION mbi
;
1039 ULONG ResultLength
= sizeof(mbi
);
1044 #if defined __GNUC__
1045 __asm__("mov %%ebp, %%ebx" : "=b" (Frame
) : );
1046 #elif defined(_MSC_VER)
1047 __asm mov
[Frame
], ebp
1050 Status
= MiQueryVirtualMemory (
1053 MemoryBasicInformation
,
1057 if ( !NT_SUCCESS(Status
) )
1059 DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status
);
1064 StackEnd
= (PULONG
)((ULONG_PTR
)mbi
.BaseAddress
+ mbi
.RegionSize
);
1066 while ( Count
< FrameCount
&& Frame
>= StackBase
&& Frame
< StackEnd
)
1068 Frames
[Count
++] = Frame
[1];
1070 Frame
= (PULONG
)Frame
[0];
1081 set_system_call_gate(unsigned int sel
, unsigned int func
)
1083 DPRINT("sel %x %d\n",sel
,sel
);
1084 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
1086 KiIdt
[sel
].b
= 0xef00 + (((int)func
)&0xffff0000);
1087 DPRINT("idt[sel].b %x\n",KiIdt
[sel
].b
);
1090 static void set_interrupt_gate(unsigned int sel
, unsigned int func
)
1092 DPRINT("set_interrupt_gate(sel %d, func %x)\n",sel
,func
);
1093 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
1095 KiIdt
[sel
].b
= 0x8e00 + (((int)func
)&0xffff0000);
1098 static void set_trap_gate(unsigned int sel
, unsigned int func
, unsigned int dpl
)
1100 DPRINT("set_trap_gate(sel %d, func %x, dpl %d)\n",sel
, func
, dpl
);
1102 KiIdt
[sel
].a
= (((int)func
)&0xffff) +
1104 KiIdt
[sel
].b
= 0x8f00 + (dpl
<< 13) + (((int)func
)&0xffff0000);
1108 set_task_gate(unsigned int sel
, unsigned task_sel
)
1110 KiIdt
[sel
].a
= task_sel
<< 16;
1111 KiIdt
[sel
].b
= 0x8500;
1117 KeInitExceptions(VOID
)
1119 * FUNCTION: Initalize CPU exception handling
1124 DPRINT("KeInitExceptions()\n");
1127 * Set up the other gates
1129 set_trap_gate(0, (ULONG
)KiTrap0
, 0);
1130 set_trap_gate(1, (ULONG
)KiTrap1
, 0);
1131 set_trap_gate(2, (ULONG
)KiTrap2
, 0);
1132 set_trap_gate(3, (ULONG
)KiTrap3
, 3);
1133 set_trap_gate(4, (ULONG
)KiTrap4
, 0);
1134 set_trap_gate(5, (ULONG
)KiTrap5
, 0);
1135 set_trap_gate(6, (ULONG
)KiTrap6
, 0);
1136 set_trap_gate(7, (ULONG
)KiTrap7
, 0);
1137 set_task_gate(8, TRAP_TSS_SELECTOR
);
1138 set_trap_gate(9, (ULONG
)KiTrap9
, 0);
1139 set_trap_gate(10, (ULONG
)KiTrap10
, 0);
1140 set_trap_gate(11, (ULONG
)KiTrap11
, 0);
1141 set_trap_gate(12, (ULONG
)KiTrap12
, 0);
1142 set_trap_gate(13, (ULONG
)KiTrap13
, 0);
1143 set_interrupt_gate(14, (ULONG
)KiTrap14
);
1144 set_trap_gate(15, (ULONG
)KiTrap15
, 0);
1145 set_trap_gate(16, (ULONG
)KiTrap16
, 0);
1146 set_trap_gate(17, (ULONG
)KiTrap17
, 0);
1147 set_trap_gate(18, (ULONG
)KiTrap18
, 0);
1148 set_trap_gate(19, (ULONG
)KiTrap19
, 0);
1150 for (i
= 20; i
< 256; i
++)
1152 set_trap_gate(i
,(int)KiTrapUnknown
, 0);
1155 set_system_call_gate(0x2d,(int)KiDebugService
);
1156 set_system_call_gate(0x2e,(int)KiSystemService
);
1161 KiDispatchException(PEXCEPTION_RECORD ExceptionRecord
,
1162 PKEXCEPTION_FRAME ExceptionFrame
,
1163 PKTRAP_FRAME TrapFrame
,
1164 KPROCESSOR_MODE PreviousMode
,
1165 BOOLEAN FirstChance
)
1168 KD_CONTINUE_TYPE Action
;
1169 ULONG_PTR Stack
, NewStack
;
1171 BOOLEAN UserDispatch
= FALSE
;
1172 DPRINT("KiDispatchException() called\n");
1174 /* Increase number of Exception Dispatches */
1175 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
1177 /* Set the context flags */
1178 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
1180 /* Check if User Mode */
1181 if (PreviousMode
== UserMode
)
1183 /* Add the FPU Flag */
1184 Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
1188 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
1190 /* Handle kernel-mode first, it's simpler */
1191 if (PreviousMode
== KernelMode
)
1193 /* Check if this is a first-chance exception */
1194 if (FirstChance
== TRUE
)
1196 /* Break into the debugger for the first time */
1197 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1204 /* If the debugger said continue, then continue */
1205 if (Action
== kdContinue
) goto Handled
;
1207 /* If the Debugger couldn't handle it, dispatch the exception */
1208 if (RtlDispatchException(ExceptionRecord
, &Context
))
1210 /* It was handled by an exception handler, continue */
1215 /* This is a second-chance exception, only for the debugger */
1216 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1223 /* If the debugger said continue, then continue */
1224 if (Action
== kdContinue
) goto Handled
;
1226 /* Third strike; you're out */
1227 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1228 ExceptionRecord
->ExceptionCode
,
1229 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1230 ExceptionRecord
->ExceptionInformation
[0],
1231 ExceptionRecord
->ExceptionInformation
[1],
1236 /* User mode exception, was it first-chance? */
1239 /* Enter Debugger if available */
1240 Action
= KdpEnterDebuggerException(ExceptionRecord
,
1247 /* Exit if we're continuing */
1248 if (Action
== kdContinue
) goto Handled
;
1250 /* FIXME: Forward exception to user mode debugger */
1252 /* Set up the user-stack */
1255 /* Align context size and get stack pointer */
1256 Size
= (sizeof(CONTEXT
) + 3) & ~3;
1257 Stack
= (Context
.Esp
& ~3) - Size
;
1258 DPRINT("Stack: %lx\n", Stack
);
1260 /* Probe stack and copy Context */
1261 ProbeForWrite((PVOID
)Stack
, Size
, sizeof(ULONG
));
1262 RtlMoveMemory((PVOID
)Stack
, &Context
, sizeof(CONTEXT
));
1264 /* Align exception record size and get stack pointer */
1265 Size
= (sizeof(EXCEPTION_RECORD
) -
1266 (EXCEPTION_MAXIMUM_PARAMETERS
- ExceptionRecord
->NumberParameters
) *
1267 sizeof(ULONG
) + 3) & ~3;
1268 NewStack
= Stack
- Size
;
1269 DPRINT("NewStack: %lx\n", NewStack
);
1271 /* Probe stack and copy exception record. Don't forget to add the two params */
1272 ProbeForWrite((PVOID
)(NewStack
- 2 * sizeof(ULONG_PTR
)),
1273 Size
+ 2 * sizeof(ULONG_PTR
),
1275 RtlMoveMemory((PVOID
)NewStack
, ExceptionRecord
, Size
);
1277 /* Now write the two params for the user-mode dispatcher */
1278 *(PULONG_PTR
)(NewStack
- 1 * sizeof(ULONG_PTR
)) = Stack
;
1279 *(PULONG_PTR
)(NewStack
- 2 * sizeof(ULONG_PTR
)) = NewStack
;
1281 /* Set new Stack Pointer */
1282 KiEspToTrapFrame(TrapFrame
, NewStack
- 2 * sizeof(ULONG_PTR
));
1284 /* Set EIP to the User-mode Dispathcer */
1285 TrapFrame
->Eip
= (ULONG
)KeUserExceptionDispatcher
;
1286 UserDispatch
= TRUE
;
1291 /* Do second-chance */
1296 /* If we dispatch to user, return now */
1297 if (UserDispatch
) return;
1299 /* FIXME: Forward the exception to the debugger for 2nd chance */
1301 /* 3rd strike, kill the thread */
1302 DPRINT1("Unhandled UserMode exception, terminating thread\n");
1303 ZwTerminateThread(NtCurrentThread(), ExceptionRecord
->ExceptionCode
);
1304 KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED
,
1305 ExceptionRecord
->ExceptionCode
,
1306 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
1307 ExceptionRecord
->ExceptionInformation
[0],
1308 ExceptionRecord
->ExceptionInformation
[1],
1313 /* Convert the context back into Trap/Exception Frames */
1314 KeContextToTrapFrame(&Context
, NULL
, TrapFrame
, PreviousMode
);
1322 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
1325 PKTHREAD Thread
= KeGetCurrentThread();
1328 Thread
->Teb
->ExceptionCode
= ExceptionCode
;
1330 return(ExceptionCode
);
1333 OldEip
= Thread
->TrapFrame
->Eip
;
1334 Thread
->TrapFrame
->Eip
= (ULONG_PTR
)KeRaiseUserExceptionDispatcher
;
1335 return((NTSTATUS
)OldEip
);