Reactos
at master 253 lines 7.4 kB view raw
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 18VOID 19NTAPI 20KiContinuePreviousModeUser( 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 40NTSTATUS 41NTAPI 42KiContinue(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 88NTSTATUS 89NTAPI 90KiRaiseException( 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 171NTSTATUS 172NTAPI 173NtRaiseException( 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 214NTSTATUS 215NTAPI 216NtContinue( 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 */