[NTOS]
[reactos.git] / reactos / 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 /* GLOBALS *******************************************************************/
17
18 KIDT_INIT KiInterruptInitTable[] =
19 {
20 /* Id, Dpl, IST, ServiceRoutine */
21 {0x00, 0x00, 0x00, KiDivideErrorFault},
22 {0x01, 0x00, 0x00, KiDebugTrapOrFault},
23 {0x02, 0x00, 0x03, KiNmiInterrupt},
24 {0x03, 0x03, 0x00, KiBreakpointTrap},
25 {0x04, 0x03, 0x00, KiOverflowTrap},
26 {0x05, 0x00, 0x00, KiBoundFault},
27 {0x06, 0x00, 0x00, KiInvalidOpcodeFault},
28 {0x07, 0x00, 0x00, KiNpxNotAvailableFault},
29 {0x08, 0x00, 0x01, KiDoubleFaultAbort},
30 {0x09, 0x00, 0x00, KiNpxSegmentOverrunAbort},
31 {0x0A, 0x00, 0x00, KiInvalidTssFault},
32 {0x0B, 0x00, 0x00, KiSegmentNotPresentFault},
33 {0x0C, 0x00, 0x00, KiStackFault},
34 {0x0D, 0x00, 0x00, KiGeneralProtectionFault},
35 {0x0E, 0x00, 0x00, KiPageFault},
36 {0x10, 0x00, 0x00, KiFloatingErrorFault},
37 {0x11, 0x00, 0x00, KiAlignmentFault},
38 {0x12, 0x00, 0x02, KiMcheckAbort},
39 {0x13, 0x00, 0x00, KiXmmException},
40 {0x1F, 0x00, 0x00, KiApcInterrupt},
41 {0x2C, 0x03, 0x00, KiRaiseAssertion},
42 {0x2D, 0x03, 0x00, KiDebugServiceTrap},
43 {0x2F, 0x00, 0x00, KiDpcInterrupt},
44 {0xE1, 0x00, 0x00, KiIpiInterrupt},
45 {0, 0, 0, 0}
46 };
47
48 KIDTENTRY64 KiIdt[256];
49 KDESCRIPTOR KiIdtDescriptor = {{0}, sizeof(KiIdt) - 1, KiIdt};
50
51 /* FUNCTIONS *****************************************************************/
52
53
54
55 VOID
56 INIT_FUNCTION
57 NTAPI
58 KeInitExceptions(VOID)
59 {
60 int i, j;
61
62 /* Initialize the Idt */
63 for (j = i = 0; i < 256; i++)
64 {
65 ULONG64 Offset;
66
67 if (KiInterruptInitTable[j].InterruptId == i)
68 {
69 Offset = (ULONG64)KiInterruptInitTable[j].ServiceRoutine;
70 KiIdt[i].Dpl = KiInterruptInitTable[j].Dpl;
71 KiIdt[i].IstIndex = KiInterruptInitTable[j].IstIndex;
72 j++;
73 }
74 else
75 {
76 Offset = (ULONG64)KiUnexpectedInterrupt;
77 KiIdt[i].Dpl = 0;
78 KiIdt[i].IstIndex = 0;
79 }
80 KiIdt[i].OffsetLow = Offset & 0xffff;
81 KiIdt[i].Selector = KGDT_64_R0_CODE;
82 KiIdt[i].Type = 0x0e;
83 KiIdt[i].Reserved0 = 0;
84 KiIdt[i].Present = 1;
85 KiIdt[i].OffsetMiddle = (Offset >> 16) & 0xffff;
86 KiIdt[i].OffsetHigh = (Offset >> 32);
87 KiIdt[i].Reserved1 = 0;
88 }
89
90 KeGetPcr()->IdtBase = KiIdt;
91 __lidt(&KiIdtDescriptor.Limit);
92 }
93
94 VOID
95 NTAPI
96 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
97 IN PKEXCEPTION_FRAME ExceptionFrame,
98 IN PKTRAP_FRAME TrapFrame,
99 IN KPROCESSOR_MODE PreviousMode,
100 IN BOOLEAN FirstChance)
101 {
102 CONTEXT Context;
103
104 // FrLdrDbgPrint("KiDispatchException(%p, %p, %p, %d, %d)\n",
105 // ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);
106
107 /* Increase number of Exception Dispatches */
108 KeGetCurrentPrcb()->KeExceptionDispatchCount++;
109
110 /* Set the context flags */
111 Context.ContextFlags = CONTEXT_ALL;
112
113 /* Get a Context */
114 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
115
116 /* Look at our exception code */
117 switch (ExceptionRecord->ExceptionCode)
118 {
119 /* Breakpoint */
120 case STATUS_BREAKPOINT:
121
122 /* Decrement RIP by one */
123 Context.Rip--;
124 break;
125
126 /* Internal exception */
127 case KI_EXCEPTION_ACCESS_VIOLATION:
128
129 /* Set correct code */
130 ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
131 if (PreviousMode == UserMode)
132 {
133 /* FIXME: Handle no execute */
134 }
135 break;
136 }
137
138 /* Handle kernel-mode first, it's simpler */
139 if (PreviousMode == KernelMode)
140 {
141 /* Check if this is a first-chance exception */
142 if (FirstChance == TRUE)
143 {
144 /* Break into the debugger for the first time */
145 if (KiDebugRoutine(TrapFrame,
146 ExceptionFrame,
147 ExceptionRecord,
148 &Context,
149 PreviousMode,
150 FALSE))
151 {
152 /* Exception was handled */
153 goto Handled;
154 }
155
156 /* If the Debugger couldn't handle it, dispatch the exception */
157 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
158 }
159
160 /* This is a second-chance exception, only for the debugger */
161 if (KiDebugRoutine(TrapFrame,
162 ExceptionFrame,
163 ExceptionRecord,
164 &Context,
165 PreviousMode,
166 TRUE))
167 {
168 /* Exception was handled */
169 goto Handled;
170 }
171
172 /* Third strike; you're out */
173 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
174 ExceptionRecord->ExceptionCode,
175 (ULONG_PTR)ExceptionRecord->ExceptionAddress,
176 (ULONG_PTR)TrapFrame,
177 0);
178 }
179 else
180 {
181 /* FIXME: user-mode exception handling unimplemented */
182 ASSERT(FALSE);
183 }
184
185 Handled:
186 /* Convert the context back into Trap/Exception Frames */
187 KeContextToTrapFrame(&Context,
188 ExceptionFrame,
189 TrapFrame,
190 Context.ContextFlags,
191 PreviousMode);
192 return;
193 }
194
195 NTSTATUS
196 NTAPI
197 KeRaiseUserException(IN NTSTATUS ExceptionCode)
198 {
199 UNIMPLEMENTED;
200 return STATUS_UNSUCCESSFUL;
201 }
202