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