2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/amd64/except.c
5 * PURPOSE: Exception Dispatching for amd64
6 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES ******************************************************************/
16 extern ULONG64 InterruptDispatchTable
[256];
18 /* GLOBALS *******************************************************************/
20 KIDT_INIT KiInterruptInitTable
[] =
22 /* Id, Dpl, IST, ServiceRoutine */
23 {0x00, 0x00, 0x00, KiDivideErrorFault
},
24 {0x01, 0x00, 0x00, KiDebugTrapOrFault
},
25 {0x02, 0x00, 0x03, KiNmiInterrupt
},
26 {0x03, 0x03, 0x00, KiBreakpointTrap
},
27 {0x04, 0x03, 0x00, KiOverflowTrap
},
28 {0x05, 0x00, 0x00, KiBoundFault
},
29 {0x06, 0x00, 0x00, KiInvalidOpcodeFault
},
30 {0x07, 0x00, 0x00, KiNpxNotAvailableFault
},
31 {0x08, 0x00, 0x01, KiDoubleFaultAbort
},
32 {0x09, 0x00, 0x00, KiNpxSegmentOverrunAbort
},
33 {0x0A, 0x00, 0x00, KiInvalidTssFault
},
34 {0x0B, 0x00, 0x00, KiSegmentNotPresentFault
},
35 {0x0C, 0x00, 0x00, KiStackFault
},
36 {0x0D, 0x00, 0x00, KiGeneralProtectionFault
},
37 {0x0E, 0x00, 0x00, KiPageFault
},
38 {0x10, 0x00, 0x00, KiFloatingErrorFault
},
39 {0x11, 0x00, 0x00, KiAlignmentFault
},
40 {0x12, 0x00, 0x02, KiMcheckAbort
},
41 {0x13, 0x00, 0x00, KiXmmException
},
42 {0x1F, 0x00, 0x00, KiApcInterrupt
},
43 {0x2C, 0x03, 0x00, KiRaiseAssertion
},
44 {0x2D, 0x03, 0x00, KiDebugServiceTrap
},
45 {0x2F, 0x00, 0x00, KiDpcInterrupt
},
46 {0xE1, 0x00, 0x00, KiIpiInterrupt
},
50 KIDTENTRY64 KiIdt
[256];
51 KDESCRIPTOR KiIdtDescriptor
= {{0}, sizeof(KiIdt
) - 1, KiIdt
};
54 /* FUNCTIONS *****************************************************************/
59 KeInitExceptions(VOID
)
63 /* Initialize the Idt */
64 for (j
= i
= 0; i
< 256; i
++)
68 if (KiInterruptInitTable
[j
].InterruptId
== i
)
70 Offset
= (ULONG64
)KiInterruptInitTable
[j
].ServiceRoutine
;
71 KiIdt
[i
].Dpl
= KiInterruptInitTable
[j
].Dpl
;
72 KiIdt
[i
].IstIndex
= KiInterruptInitTable
[j
].IstIndex
;
77 Offset
= (ULONG64
)&InterruptDispatchTable
[i
];
79 KiIdt
[i
].IstIndex
= 0;
81 KiIdt
[i
].OffsetLow
= Offset
& 0xffff;
82 KiIdt
[i
].Selector
= KGDT64_R0_CODE
;
84 KiIdt
[i
].Reserved0
= 0;
86 KiIdt
[i
].OffsetMiddle
= (Offset
>> 16) & 0xffff;
87 KiIdt
[i
].OffsetHigh
= (Offset
>> 32);
88 KiIdt
[i
].Reserved1
= 0;
91 KeGetPcr()->IdtBase
= KiIdt
;
92 __lidt(&KiIdtDescriptor
.Limit
);
97 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord
,
98 IN PKEXCEPTION_FRAME ExceptionFrame
,
99 IN PKTRAP_FRAME TrapFrame
,
100 IN KPROCESSOR_MODE PreviousMode
,
101 IN BOOLEAN FirstChance
)
105 // FrLdrDbgPrint("KiDispatchException(%p, %p, %p, %d, %d)\n",
106 // ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);
108 /* Increase number of Exception Dispatches */
109 KeGetCurrentPrcb()->KeExceptionDispatchCount
++;
111 /* Set the context flags */
112 Context
.ContextFlags
= CONTEXT_ALL
;
115 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
117 /* Look at our exception code */
118 switch (ExceptionRecord
->ExceptionCode
)
121 case STATUS_BREAKPOINT
:
123 /* Decrement RIP by one */
127 /* Internal exception */
128 case KI_EXCEPTION_ACCESS_VIOLATION
:
130 /* Set correct code */
131 ExceptionRecord
->ExceptionCode
= STATUS_ACCESS_VIOLATION
;
132 if (PreviousMode
== UserMode
)
134 /* FIXME: Handle no execute */
139 /* Handle kernel-mode first, it's simpler */
140 if (PreviousMode
== KernelMode
)
142 /* Check if this is a first-chance exception */
143 if (FirstChance
== TRUE
)
145 /* Break into the debugger for the first time */
146 if (KiDebugRoutine(TrapFrame
,
153 /* Exception was handled */
157 /* If the Debugger couldn't handle it, dispatch the exception */
158 if (RtlDispatchException(ExceptionRecord
, &Context
)) goto Handled
;
161 /* This is a second-chance exception, only for the debugger */
162 if (KiDebugRoutine(TrapFrame
,
169 /* Exception was handled */
173 /* Third strike; you're out */
174 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED
,
175 ExceptionRecord
->ExceptionCode
,
176 (ULONG_PTR
)ExceptionRecord
->ExceptionAddress
,
177 (ULONG_PTR
)TrapFrame
,
182 /* FIXME: user-mode exception handling unimplemented */
187 /* Convert the context back into Trap/Exception Frames */
188 KeContextToTrapFrame(&Context
,
191 Context
.ContextFlags
,
198 KeRaiseUserException(IN NTSTATUS ExceptionCode
)
201 return STATUS_UNSUCCESSFUL
;
207 KiSystemFatalException(IN ULONG ExceptionCode
,
208 IN PKTRAP_FRAME TrapFrame
)
210 /* Bugcheck the system */
211 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP
,
221 KiNpxNotAvailableFaultHandler(
222 IN PKTRAP_FRAME TrapFrame
)
225 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);
232 KiGeneralProtectionFaultHandler(
233 IN PKTRAP_FRAME TrapFrame
)
237 /* Check for user-mode GPF */
238 if (TrapFrame
->SegCs
& 3)
244 /* Check for lazy segment load */
245 if (TrapFrame
->SegDs
!= (KGDT64_R3_DATA
| RPL_MASK
))
248 TrapFrame
->SegDs
= (KGDT64_R3_DATA
| RPL_MASK
);
249 return STATUS_SUCCESS
;
251 else if (TrapFrame
->SegEs
!= (KGDT64_R3_DATA
| RPL_MASK
))
254 TrapFrame
->SegEs
= (KGDT64_R3_DATA
| RPL_MASK
);
255 return STATUS_SUCCESS
;
258 /* Check for nested exception */
259 if ((TrapFrame
->Rip
>= (ULONG64
)KiGeneralProtectionFaultHandler
) &&
260 (TrapFrame
->Rip
< (ULONG64
)KiGeneralProtectionFaultHandler
))
262 /* Not implemented */
267 /* Get Instruction Pointer */
268 Instructions
= (PUCHAR
)TrapFrame
->Rip
;
271 if (Instructions
[0] == 0x48 && Instructions
[1] == 0xCF)
273 /* Not implemented */
278 /* Check for RDMSR/WRMSR */
279 if ((Instructions
[0] == 0xF) && // 2-byte opcode
280 (((Instructions
[1] >> 8) == 0x30) || // RDMSR
281 ((Instructions
[2] >> 8) == 0x32))) // WRMSR
283 /* Unknown CPU MSR, so raise an access violation */
284 return STATUS_ACCESS_VIOLATION
;
288 return STATUS_UNSUCCESSFUL
;
293 KiXmmExceptionHandler(
294 IN PKTRAP_FRAME TrapFrame
)
297 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN
, 13, 0, 0, 1, TrapFrame
);