1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/except.c
5 * PURPOSE: Platform independent exception handling
6 * PROGRAMMERS: ReactOS Portable Systems Group
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 /* FUNCTIONS *****************************************************************/
17
18 VOID
19 NTAPI
KiContinuePreviousModeUser(_In_ PCONTEXT Context,_Out_ PKEXCEPTION_FRAME ExceptionFrame,_Out_ PKTRAP_FRAME TrapFrame)20 KiContinuePreviousModeUser(
21 _In_ PCONTEXT Context,
22 _Out_ PKEXCEPTION_FRAME ExceptionFrame,
23 _Out_ PKTRAP_FRAME TrapFrame)
24 {
25 CONTEXT LocalContext;
26
27 /* We'll have to make a copy and probe it */
28 ProbeForRead(Context, sizeof(CONTEXT), sizeof(ULONG));
29 RtlCopyMemory(&LocalContext, Context, sizeof(CONTEXT));
30 Context = &LocalContext;
31
32 /* Convert the context into Exception/Trap Frames */
33 KeContextToTrapFrame(&LocalContext,
34 ExceptionFrame,
35 TrapFrame,
36 LocalContext.ContextFlags,
37 UserMode);
38 }
39
40 NTSTATUS
41 NTAPI
KiContinue(IN PCONTEXT Context,IN PKEXCEPTION_FRAME ExceptionFrame,IN PKTRAP_FRAME TrapFrame)42 KiContinue(IN PCONTEXT Context,
43 IN PKEXCEPTION_FRAME ExceptionFrame,
44 IN PKTRAP_FRAME TrapFrame)
45 {
46 NTSTATUS Status = STATUS_SUCCESS;
47 KIRQL OldIrql = APC_LEVEL;
48 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
49
50 /* Raise to APC_LEVEL, only if needed */
51 if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);
52
53 /* Set up SEH to validate the context */
54 _SEH2_TRY
55 {
56 /* Check the previous mode */
57 if (PreviousMode != KernelMode)
58 {
59 /* Validate from user-mode */
60 KiContinuePreviousModeUser(Context,
61 ExceptionFrame,
62 TrapFrame);
63 }
64 else
65 {
66 /* Convert the context into Exception/Trap Frames */
67 KeContextToTrapFrame(Context,
68 ExceptionFrame,
69 TrapFrame,
70 Context->ContextFlags,
71 KernelMode);
72 }
73 }
74 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
75 {
76 /* Save the exception code */
77 Status = _SEH2_GetExceptionCode();
78 }
79 _SEH2_END;
80
81 /* Lower the IRQL if needed */
82 if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);
83
84 /* Return status */
85 return Status;
86 }
87
88 NTSTATUS
89 NTAPI
KiRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord,_In_ PCONTEXT Context,_Out_ PKEXCEPTION_FRAME ExceptionFrame,_Out_ PKTRAP_FRAME TrapFrame,_In_ BOOLEAN SearchFrames)90 KiRaiseException(
91 _In_ PEXCEPTION_RECORD ExceptionRecord,
92 _In_ PCONTEXT Context,
93 _Out_ PKEXCEPTION_FRAME ExceptionFrame,
94 _Out_ PKTRAP_FRAME TrapFrame,
95 _In_ BOOLEAN SearchFrames)
96 {
97 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
98 CONTEXT LocalContext;
99 EXCEPTION_RECORD LocalExceptionRecord;
100 ULONG ParameterCount, Size;
101
102 /* Check if we need to probe */
103 if (PreviousMode != KernelMode)
104 {
105 /* Set up SEH */
106 _SEH2_TRY
107 {
108 /* Probe the context */
109 ProbeForRead(Context, sizeof(CONTEXT), sizeof(ULONG));
110
111 /* Probe the Exception Record */
112 ProbeForRead(ExceptionRecord,
113 FIELD_OFFSET(EXCEPTION_RECORD, NumberParameters) +
114 sizeof(ULONG),
115 sizeof(ULONG));
116
117 /* Validate the maximum parameters */
118 if ((ParameterCount = ExceptionRecord->NumberParameters) >
119 EXCEPTION_MAXIMUM_PARAMETERS)
120 {
121 /* Too large */
122 _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
123 }
124
125 /* Probe the entire parameters now*/
126 Size = (sizeof(EXCEPTION_RECORD) -
127 ((EXCEPTION_MAXIMUM_PARAMETERS - ParameterCount) * sizeof(ULONG)));
128 ProbeForRead(ExceptionRecord, Size, sizeof(ULONG));
129
130 /* Now make copies in the stack */
131 RtlCopyMemory(&LocalContext, Context, sizeof(CONTEXT));
132 RtlCopyMemory(&LocalExceptionRecord, ExceptionRecord, Size);
133 Context = &LocalContext;
134 ExceptionRecord = &LocalExceptionRecord;
135
136 /* Update the parameter count */
137 ExceptionRecord->NumberParameters = ParameterCount;
138 }
139 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
140 {
141 /* Don't fail silently */
142 DPRINT1("KiRaiseException: Failed to Probe\n");
143
144 /* Return the exception code */
145 _SEH2_YIELD(return _SEH2_GetExceptionCode());
146 }
147 _SEH2_END;
148 }
149
150 /* Convert the context record */
151 KeContextToTrapFrame(Context,
152 ExceptionFrame,
153 TrapFrame,
154 Context->ContextFlags,
155 PreviousMode);
156
157 /* Dispatch the exception */
158 ExceptionRecord->ExceptionCode &= ~KI_EXCEPTION_INTERNAL;
159 KiDispatchException(ExceptionRecord,
160 ExceptionFrame,
161 TrapFrame,
162 PreviousMode,
163 SearchFrames);
164
165 /* We are done */
166 return STATUS_SUCCESS;
167 }
168
169 /* SYSTEM CALLS ***************************************************************/
170
171 NTSTATUS
172 NTAPI
NtRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord,_In_ PCONTEXT Context,_In_ BOOLEAN FirstChance)173 NtRaiseException(
174 _In_ PEXCEPTION_RECORD ExceptionRecord,
175 _In_ PCONTEXT Context,
176 _In_ BOOLEAN FirstChance)
177 {
178 NTSTATUS Status;
179 PKTHREAD Thread;
180 PKTRAP_FRAME TrapFrame;
181 #ifdef _M_IX86
182 PKEXCEPTION_FRAME ExceptionFrame = NULL;
183 #else
184 KEXCEPTION_FRAME LocalExceptionFrame;
185 PKEXCEPTION_FRAME ExceptionFrame = &LocalExceptionFrame;
186 #endif
187
188 /* Get trap frame and link previous one */
189 Thread = KeGetCurrentThread();
190 TrapFrame = Thread->TrapFrame;
191 Thread->TrapFrame = KiGetLinkedTrapFrame(TrapFrame);
192
193 /* Set exception list */
194 #ifdef _M_IX86
195 KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
196 #endif
197
198 /* Raise the exception */
199 Status = KiRaiseException(ExceptionRecord,
200 Context,
201 ExceptionFrame,
202 TrapFrame,
203 FirstChance);
204 if (!NT_SUCCESS(Status))
205 {
206 DPRINT1("KiRaiseException failed. Status = 0x%lx\n", Status);
207 return Status;
208 }
209
210 /* It was handled, so exit restoring all state */
211 KiExceptionExit(TrapFrame, ExceptionFrame);
212 }
213
214 NTSTATUS
215 NTAPI
NtContinue(_In_ PCONTEXT Context,_In_ BOOLEAN TestAlert)216 NtContinue(
217 _In_ PCONTEXT Context,
218 _In_ BOOLEAN TestAlert)
219 {
220 PKTHREAD Thread;
221 NTSTATUS Status;
222 PKTRAP_FRAME TrapFrame;
223 #ifdef _M_IX86
224 PKEXCEPTION_FRAME ExceptionFrame = NULL;
225 #else
226 KEXCEPTION_FRAME LocalExceptionFrame;
227 PKEXCEPTION_FRAME ExceptionFrame = &LocalExceptionFrame;
228 #endif
229
230 /* Get trap frame and link previous one*/
231 Thread = KeGetCurrentThread();
232 TrapFrame = Thread->TrapFrame;
233 Thread->TrapFrame = KiGetLinkedTrapFrame(TrapFrame);
234
235 /* Continue from this point on */
236 Status = KiContinue(Context, ExceptionFrame, TrapFrame);
237 if (!NT_SUCCESS(Status))
238 {
239 DPRINT1("KiContinue failed. Status = 0x%lx\n", Status);
240 return Status;
241 }
242
243 /* Check if alert was requested */
244 if (TestAlert)
245 {
246 KeTestAlertThread(Thread->PreviousMode);
247 }
248
249 /* Exit to new context */
250 KiExceptionExit(TrapFrame, ExceptionFrame);
251 }
252
253 /* EOF */
254