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)
10 /* INCLUDES ******************************************************************/
16 /* FUNCTIONS *****************************************************************/
20 KiContinuePreviousModeUser(IN PCONTEXT Context
,
21 IN PKEXCEPTION_FRAME ExceptionFrame
,
22 IN PKTRAP_FRAME TrapFrame
)
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
;
31 /* Convert the context into Exception/Trap Frames */
32 KeContextToTrapFrame(&LocalContext
,
35 LocalContext
.ContextFlags
,
41 KiContinue(IN PCONTEXT Context
,
42 IN PKEXCEPTION_FRAME ExceptionFrame
,
43 IN PKTRAP_FRAME TrapFrame
)
45 NTSTATUS Status
= STATUS_SUCCESS
;
46 KIRQL OldIrql
= APC_LEVEL
;
47 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
49 /* Raise to APC_LEVEL, only if needed */
50 if (KeGetCurrentIrql() < APC_LEVEL
) KeRaiseIrql(APC_LEVEL
, &OldIrql
);
52 /* Set up SEH to validate the context */
55 /* Check the previous mode */
56 if (PreviousMode
!= KernelMode
)
58 /* Validate from user-mode */
59 KiContinuePreviousModeUser(Context
,
65 /* Convert the context into Exception/Trap Frames */
66 KeContextToTrapFrame(Context
,
69 Context
->ContextFlags
,
73 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
75 /* Save the exception code */
76 Status
= _SEH2_GetExceptionCode();
80 /* Lower the IRQL if needed */
81 if (OldIrql
< APC_LEVEL
) KeLowerIrql(OldIrql
);
89 KiRaiseException(IN PEXCEPTION_RECORD ExceptionRecord
,
91 IN PKEXCEPTION_FRAME ExceptionFrame
,
92 IN PKTRAP_FRAME TrapFrame
,
93 IN BOOLEAN SearchFrames
)
95 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
97 EXCEPTION_RECORD LocalExceptionRecord
;
98 ULONG ParameterCount
, Size
;
100 /* Check if we need to probe */
101 if (PreviousMode
!= KernelMode
)
106 /* Probe the context */
107 ProbeForRead(Context
, sizeof(CONTEXT
), sizeof(ULONG
));
109 /* Probe the Exception Record */
110 ProbeForRead(ExceptionRecord
,
111 FIELD_OFFSET(EXCEPTION_RECORD
, NumberParameters
) +
115 /* Validate the maximum parameters */
116 if ((ParameterCount
= ExceptionRecord
->NumberParameters
) >
117 EXCEPTION_MAXIMUM_PARAMETERS
)
120 _SEH2_YIELD(return STATUS_INVALID_PARAMETER
);
123 /* Probe the entire parameters now*/
124 Size
= (sizeof(EXCEPTION_RECORD
) -
125 ((EXCEPTION_MAXIMUM_PARAMETERS
- ParameterCount
) * sizeof(ULONG
)));
126 ProbeForRead(ExceptionRecord
, Size
, sizeof(ULONG
));
128 /* Now make copies in the stack */
129 RtlCopyMemory(&LocalContext
, Context
, sizeof(CONTEXT
));
130 RtlCopyMemory(&LocalExceptionRecord
, ExceptionRecord
, Size
);
131 Context
= &LocalContext
;
132 ExceptionRecord
= &LocalExceptionRecord
;
134 /* Update the parameter count */
135 ExceptionRecord
->NumberParameters
= ParameterCount
;
137 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
139 /* Don't fail silently */
140 DPRINT1("KiRaiseException: Failed to Probe\n");
143 /* Return the exception code */
144 _SEH2_YIELD(return _SEH2_GetExceptionCode());
149 /* Convert the context record */
150 KeContextToTrapFrame(Context
,
153 Context
->ContextFlags
,
156 /* Dispatch the exception */
157 ExceptionRecord
->ExceptionCode
&= ~KI_EXCEPTION_INTERNAL
;
158 KiDispatchException(ExceptionRecord
,
165 return STATUS_SUCCESS
;
168 /* SYSTEM CALLS ***************************************************************/
174 NtRaiseException(IN PEXCEPTION_RECORD ExceptionRecord
,
176 IN BOOLEAN FirstChance
)
180 PKTRAP_FRAME TrapFrame
;
182 /* Get trap frame and link previous one*/
183 Thread
= KeGetCurrentThread();
184 TrapFrame
= Thread
->TrapFrame
;
185 Thread
->TrapFrame
= KiGetLinkedTrapFrame(TrapFrame
);
187 /* Set exception list */
189 KeGetPcr()->NtTib
.ExceptionList
= TrapFrame
->ExceptionList
;
192 /* Raise the exception */
193 Status
= KiRaiseException(ExceptionRecord
,
198 if (NT_SUCCESS(Status
))
200 /* It was handled, so exit restoring all state */
201 KiServiceExit2(TrapFrame
);
205 /* Exit with error */
206 KiServiceExit(TrapFrame
, Status
);
209 /* We don't actually make it here */
215 NtContinue(IN PCONTEXT Context
,
216 IN BOOLEAN TestAlert
)
220 PKTRAP_FRAME TrapFrame
;
222 /* Get trap frame and link previous one*/
223 Thread
= KeGetCurrentThread();
224 TrapFrame
= Thread
->TrapFrame
;
225 Thread
->TrapFrame
= KiGetLinkedTrapFrame(TrapFrame
);
227 /* Continue from this point on */
228 Status
= KiContinue(Context
, NULL
, TrapFrame
);
229 if (NT_SUCCESS(Status
))
231 /* Check if alert was requested */
232 if (TestAlert
) KeTestAlertThread(Thread
->PreviousMode
);
234 /* Exit to new trap frame */
235 KiServiceExit2(TrapFrame
);
239 /* Exit with an error */
240 KiServiceExit(TrapFrame
, Status
);
243 /* We don't actually make it here */