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