[CLT2012]
[reactos.git] / ntoskrnl / ke / amd64 / except.c
1 /*
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)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 extern ULONG64 InterruptDispatchTable[256];
17
18 /* GLOBALS *******************************************************************/
19
20 KIDT_INIT KiInterruptInitTable[] =
21 {
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},
47 {0, 0, 0, 0}
48 };
49
50 KIDTENTRY64 KiIdt[256];
51 KDESCRIPTOR KiIdtDescriptor = {{0}, sizeof(KiIdt) - 1, KiIdt};
52
53
54 /* FUNCTIONS *****************************************************************/
55
56 VOID
57 INIT_FUNCTION
58 NTAPI
59 KeInitExceptions(VOID)
60 {
61 int i, j;
62
63 /* Initialize the Idt */
64 for (j = i = 0; i < 256; i++)
65 {
66 ULONG64 Offset;
67
68 if (KiInterruptInitTable[j].InterruptId == i)
69 {
70 Offset = (ULONG64)KiInterruptInitTable[j].ServiceRoutine;
71 KiIdt[i].Dpl = KiInterruptInitTable[j].Dpl;
72 KiIdt[i].IstIndex = KiInterruptInitTable[j].IstIndex;
73 j++;
74 }
75 else
76 {
77 Offset = (ULONG64)&InterruptDispatchTable[i];
78 KiIdt[i].Dpl = 0;
79 KiIdt[i].IstIndex = 0;
80 }
81 KiIdt[i].OffsetLow = Offset & 0xffff;
82 KiIdt[i].Selector = KGDT64_R0_CODE;
83 KiIdt[i].Type = 0x0e;
84 KiIdt[i].Reserved0 = 0;
85 KiIdt[i].Present = 1;
86 KiIdt[i].OffsetMiddle = (Offset >> 16) & 0xffff;
87 KiIdt[i].OffsetHigh = (Offset >> 32);
88 KiIdt[i].Reserved1 = 0;
89 }
90
91 KeGetPcr()->IdtBase = KiIdt;
92 __lidt(&KiIdtDescriptor.Limit);
93 }
94
95 VOID
96 NTAPI
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)
102 {
103 CONTEXT Context;
104
105 // FrLdrDbgPrint("KiDispatchException(%p, %p, %p, %d, %d)\n",
106 // ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);
107
108 /* Increase number of Exception Dispatches */
109 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
110
111 /* Set the context flags */
112 Context.ContextFlags = CONTEXT_ALL;
113
114 /* Get a Context */
115 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
116
117 /* Look at our exception code */
118 switch (ExceptionRecord->ExceptionCode)
119 {
120 /* Breakpoint */
121 case STATUS_BREAKPOINT:
122
123 /* Decrement RIP by one */
124 Context.Rip--;
125 break;
126
127 /* Internal exception */
128 case KI_EXCEPTION_ACCESS_VIOLATION:
129
130 /* Set correct code */
131 ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
132 if (PreviousMode == UserMode)
133 {
134 /* FIXME: Handle no execute */
135 }
136 break;
137 }
138
139 /* Handle kernel-mode first, it's simpler */
140 if (PreviousMode == KernelMode)
141 {
142 /* Check if this is a first-chance exception */
143 if (FirstChance == TRUE)
144 {
145 /* Break into the debugger for the first time */
146 if (KiDebugRoutine(TrapFrame,
147 ExceptionFrame,
148 ExceptionRecord,
149 &Context,
150 PreviousMode,
151 FALSE))
152 {
153 /* Exception was handled */
154 goto Handled;
155 }
156
157 /* If the Debugger couldn't handle it, dispatch the exception */
158 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
159 }
160
161 /* This is a second-chance exception, only for the debugger */
162 if (KiDebugRoutine(TrapFrame,
163 ExceptionFrame,
164 ExceptionRecord,
165 &Context,
166 PreviousMode,
167 TRUE))
168 {
169 /* Exception was handled */
170 goto Handled;
171 }
172
173 /* Third strike; you're out */
174 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
175 ExceptionRecord->ExceptionCode,
176 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
177 (ULONG_PTR)TrapFrame,
178 0);
179 }
180 else
181 {
182 /* FIXME: user-mode exception handling unimplemented */
183 ASSERT(FALSE);
184 }
185
186 Handled:
187 /* Convert the context back into Trap/Exception Frames */
188 KeContextToTrapFrame(&Context,
189 ExceptionFrame,
190 TrapFrame,
191 Context.ContextFlags,
192 PreviousMode);
193 return;
194 }
195
196 NTSTATUS
197 NTAPI
198 KeRaiseUserException(IN NTSTATUS ExceptionCode)
199 {
200 UNIMPLEMENTED;
201 return STATUS_UNSUCCESSFUL;
202 }
203
204
205 VOID
206 DECLSPEC_NORETURN
207 KiSystemFatalException(IN ULONG ExceptionCode,
208 IN PKTRAP_FRAME TrapFrame)
209 {
210 /* Bugcheck the system */
211 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
212 ExceptionCode,
213 0,
214 0,
215 0,
216 TrapFrame);
217 }
218
219 NTSTATUS
220 NTAPI
221 KiNpxNotAvailableFaultHandler(
222 IN PKTRAP_FRAME TrapFrame)
223 {
224 UNIMPLEMENTED;
225 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
226 return -1;
227 }
228
229
230 NTSTATUS
231 NTAPI
232 KiGeneralProtectionFaultHandler(
233 IN PKTRAP_FRAME TrapFrame)
234 {
235 PUCHAR Instructions;
236
237 /* Check for user-mode GPF */
238 if (TrapFrame->SegCs & 3)
239 {
240 UNIMPLEMENTED;
241 ASSERT(FALSE);
242 }
243
244 /* Check for lazy segment load */
245 if (TrapFrame->SegDs != (KGDT64_R3_DATA | RPL_MASK))
246 {
247 /* Fix it */
248 TrapFrame->SegDs = (KGDT64_R3_DATA | RPL_MASK);
249 return STATUS_SUCCESS;
250 }
251 else if (TrapFrame->SegEs != (KGDT64_R3_DATA | RPL_MASK))
252 {
253 /* Fix it */
254 TrapFrame->SegEs = (KGDT64_R3_DATA | RPL_MASK);
255 return STATUS_SUCCESS;
256 }
257
258 /* Check for nested exception */
259 if ((TrapFrame->Rip >= (ULONG64)KiGeneralProtectionFaultHandler) &&
260 (TrapFrame->Rip < (ULONG64)KiGeneralProtectionFaultHandler))
261 {
262 /* Not implemented */
263 UNIMPLEMENTED;
264 ASSERT(FALSE);
265 }
266
267 /* Get Instruction Pointer */
268 Instructions = (PUCHAR)TrapFrame->Rip;
269
270 /* Check for IRET */
271 if (Instructions[0] == 0x48 && Instructions[1] == 0xCF)
272 {
273 /* Not implemented */
274 UNIMPLEMENTED;
275 ASSERT(FALSE);
276 }
277
278 /* Check for RDMSR/WRMSR */
279 if ((Instructions[0] == 0xF) && // 2-byte opcode
280 ((Instructions[1] == 0x30) || // RDMSR
281 (Instructions[1] == 0x32))) // WRMSR
282 {
283 /* Unknown CPU MSR, so raise an access violation */
284 return STATUS_ACCESS_VIOLATION;
285 }
286
287 ASSERT(FALSE);
288 return STATUS_UNSUCCESSFUL;
289 }
290
291 NTSTATUS
292 NTAPI
293 KiXmmExceptionHandler(
294 IN PKTRAP_FRAME TrapFrame)
295 {
296 UNIMPLEMENTED;
297 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
298 return -1;
299 }