xref: /reactos/ntoskrnl/ke/except.c (revision 53221834)
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 
142             /* Return the exception code */
143             _SEH2_YIELD(return _SEH2_GetExceptionCode());
144         }
145         _SEH2_END;
146     }
147 
148     /* Convert the context record */
149     KeContextToTrapFrame(Context,
150                          ExceptionFrame,
151                          TrapFrame,
152                          Context->ContextFlags,
153                          PreviousMode);
154 
155     /* Dispatch the exception */
156     ExceptionRecord->ExceptionCode &= ~KI_EXCEPTION_INTERNAL;
157     KiDispatchException(ExceptionRecord,
158                         ExceptionFrame,
159                         TrapFrame,
160                         PreviousMode,
161                         SearchFrames);
162 
163     /* We are done */
164     return STATUS_SUCCESS;
165 }
166 
167 /* SYSTEM CALLS ***************************************************************/
168 
169 NTSTATUS
170 NTAPI
171 NtRaiseException(IN PEXCEPTION_RECORD ExceptionRecord,
172                  IN PCONTEXT Context,
173                  IN BOOLEAN FirstChance)
174 {
175     NTSTATUS Status;
176     PKTHREAD Thread;
177     PKTRAP_FRAME TrapFrame;
178 
179     /* Get trap frame and link previous one*/
180     Thread = KeGetCurrentThread();
181     TrapFrame = Thread->TrapFrame;
182     Thread->TrapFrame = KiGetLinkedTrapFrame(TrapFrame);
183 
184     /* Set exception list */
185 #ifdef _M_IX86
186     KeGetPcr()->NtTib.ExceptionList = TrapFrame->ExceptionList;
187 #endif
188 
189     /* Raise the exception */
190     Status = KiRaiseException(ExceptionRecord,
191                               Context,
192                               NULL,
193                               TrapFrame,
194                               FirstChance);
195     if (NT_SUCCESS(Status))
196     {
197         /* It was handled, so exit restoring all state */
198         KiServiceExit2(TrapFrame);
199     }
200     else
201     {
202         /* Exit with error */
203         KiServiceExit(TrapFrame, Status);
204     }
205 
206     /* We don't actually make it here */
207     return Status;
208 }
209 
210 NTSTATUS
211 NTAPI
212 NtContinue(IN PCONTEXT Context,
213            IN BOOLEAN TestAlert)
214 {
215     PKTHREAD Thread;
216     NTSTATUS Status;
217     PKTRAP_FRAME TrapFrame;
218 
219     /* Get trap frame and link previous one*/
220     Thread = KeGetCurrentThread();
221     TrapFrame = Thread->TrapFrame;
222     Thread->TrapFrame = KiGetLinkedTrapFrame(TrapFrame);
223 
224     /* Continue from this point on */
225     Status = KiContinue(Context, NULL, TrapFrame);
226     if (NT_SUCCESS(Status))
227     {
228         /* Check if alert was requested */
229         if (TestAlert) KeTestAlertThread(Thread->PreviousMode);
230 
231         /* Exit to new trap frame */
232         KiServiceExit2(TrapFrame);
233     }
234     else
235     {
236         /* Exit with an error */
237         KiServiceExit(TrapFrame, Status);
238     }
239 
240     /* We don't actually make it here */
241     return Status;
242 }
243 
244 /* EOF */
245