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( 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 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 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 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 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