xref: /reactos/ntoskrnl/ke/except.c (revision 5c3b1c78)
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