Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenusercall.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ke/i386/usercall.c 00005 * PURPOSE: User-mode Callout Mechanisms (APC and Win32K Callbacks) 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Timo Kreuzer (timo.kreuzer@reactos.org) 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 extern PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch; 00017 00018 /* PRIVATE FUNCTIONS *********************************************************/ 00019 00020 /*++ 00021 * @name KiInitializeUserApc 00022 * 00023 * Prepares the Context for a User-Mode APC called through NTDLL.DLL 00024 * 00025 * @param Reserved 00026 * Pointer to the Exception Frame on non-i386 builds. 00027 * 00028 * @param TrapFrame 00029 * Pointer to the Trap Frame. 00030 * 00031 * @param NormalRoutine 00032 * Pointer to the NormalRoutine to call. 00033 * 00034 * @param NormalContext 00035 * Pointer to the context to send to the Normal Routine. 00036 * 00037 * @param SystemArgument[1-2] 00038 * Pointer to a set of two parameters that contain untyped data. 00039 * 00040 * @return None. 00041 * 00042 * @remarks None. 00043 * 00044 *--*/ 00045 VOID 00046 NTAPI 00047 KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame, 00048 IN PKTRAP_FRAME TrapFrame, 00049 IN PKNORMAL_ROUTINE NormalRoutine, 00050 IN PVOID NormalContext, 00051 IN PVOID SystemArgument1, 00052 IN PVOID SystemArgument2) 00053 { 00054 CONTEXT Context; 00055 ULONG_PTR Stack, AlignedEsp; 00056 ULONG ContextLength; 00057 EXCEPTION_RECORD SehExceptRecord; 00058 00059 /* Don't deliver APCs in V86 mode */ 00060 if (TrapFrame->EFlags & EFLAGS_V86_MASK) return; 00061 00062 /* Save the full context */ 00063 Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; 00064 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context); 00065 00066 /* Protect with SEH */ 00067 _SEH2_TRY 00068 { 00069 /* Sanity check */ 00070 ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode); 00071 00072 /* Get the aligned size */ 00073 AlignedEsp = Context.Esp & ~3; 00074 ContextLength = CONTEXT_ALIGNED_SIZE + (4 * sizeof(ULONG_PTR)); 00075 Stack = ((AlignedEsp - 8) & ~3) - ContextLength; 00076 00077 /* Probe the stack */ 00078 ProbeForWrite((PVOID)Stack, AlignedEsp - Stack, 1); 00079 ASSERT(!(Stack & 3)); 00080 00081 /* Copy data into it */ 00082 RtlCopyMemory((PVOID)(Stack + (4 * sizeof(ULONG_PTR))), 00083 &Context, 00084 sizeof(CONTEXT)); 00085 00086 /* Run at APC dispatcher */ 00087 TrapFrame->Eip = (ULONG)KeUserApcDispatcher; 00088 TrapFrame->HardwareEsp = Stack; 00089 00090 /* Setup Ring 3 state */ 00091 TrapFrame->SegCs = Ke386SanitizeSeg(KGDT_R3_CODE, UserMode); 00092 TrapFrame->HardwareSegSs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode); 00093 TrapFrame->SegDs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode); 00094 TrapFrame->SegEs = Ke386SanitizeSeg(KGDT_R3_DATA, UserMode); 00095 TrapFrame->SegFs = Ke386SanitizeSeg(KGDT_R3_TEB, UserMode); 00096 TrapFrame->SegGs = 0; 00097 TrapFrame->ErrCode = 0; 00098 00099 /* Sanitize EFLAGS */ 00100 TrapFrame->EFlags = Ke386SanitizeFlags(Context.EFlags, UserMode); 00101 00102 /* Check if thread has IOPL and force it enabled if so */ 00103 if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL; 00104 00105 /* Setup the stack */ 00106 *(PULONG_PTR)(Stack + 0 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalRoutine; 00107 *(PULONG_PTR)(Stack + 1 * sizeof(ULONG_PTR)) = (ULONG_PTR)NormalContext; 00108 *(PULONG_PTR)(Stack + 2 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument1; 00109 *(PULONG_PTR)(Stack + 3 * sizeof(ULONG_PTR)) = (ULONG_PTR)SystemArgument2; 00110 } 00111 _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER)) 00112 { 00113 /* Dispatch the exception */ 00114 SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Eip; 00115 KiDispatchException(&SehExceptRecord, 00116 ExceptionFrame, 00117 TrapFrame, 00118 UserMode, 00119 TRUE); 00120 } 00121 _SEH2_END; 00122 } 00123 00124 /* PUBLIC FUNCTIONS **********************************************************/ 00125 00126 /* 00127 * @implemented 00128 */ 00129 NTSTATUS 00130 NTAPI 00131 KeUserModeCallback(IN ULONG RoutineIndex, 00132 IN PVOID Argument, 00133 IN ULONG ArgumentLength, 00134 OUT PVOID *Result, 00135 OUT PULONG ResultLength) 00136 { 00137 ULONG_PTR NewStack, OldStack; 00138 PULONG UserEsp; 00139 NTSTATUS CallbackStatus; 00140 PEXCEPTION_REGISTRATION_RECORD ExceptionList; 00141 PTEB Teb; 00142 ULONG GdiBatchCount = 0; 00143 ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE); 00144 ASSERT(KeGetPreviousMode() == UserMode); 00145 00146 /* Get the current user-mode stack */ 00147 UserEsp = KiGetUserModeStackAddress(); 00148 OldStack = *UserEsp; 00149 00150 /* Enter a SEH Block */ 00151 _SEH2_TRY 00152 { 00153 /* Calculate and align the stack size */ 00154 NewStack = (OldStack - ArgumentLength) & ~3; 00155 00156 /* Make sure it's writable */ 00157 ProbeForWrite((PVOID)(NewStack - 6 * sizeof(ULONG_PTR)), 00158 ArgumentLength + 6 * sizeof(ULONG_PTR), 00159 sizeof(CHAR)); 00160 00161 /* Copy the buffer into the stack */ 00162 RtlCopyMemory((PVOID)NewStack, Argument, ArgumentLength); 00163 00164 /* Write the arguments */ 00165 NewStack -= 24; 00166 *(PULONG)NewStack = 0; 00167 *(PULONG)(NewStack + 4) = RoutineIndex; 00168 *(PULONG)(NewStack + 8) = (NewStack + 24); 00169 *(PULONG)(NewStack + 12) = ArgumentLength; 00170 00171 /* Save the exception list */ 00172 Teb = KeGetCurrentThread()->Teb; 00173 ExceptionList = Teb->NtTib.ExceptionList; 00174 00175 /* Jump to user mode */ 00176 *UserEsp = NewStack; 00177 CallbackStatus = KiCallUserMode(Result, ResultLength); 00178 if (CallbackStatus != STATUS_CALLBACK_POP_STACK) 00179 { 00180 /* Only restore the exception list if we didn't crash in ring 3 */ 00181 Teb->NtTib.ExceptionList = ExceptionList; 00182 CallbackStatus = STATUS_SUCCESS; 00183 } 00184 else 00185 { 00186 /* Otherwise, pop the stack */ 00187 OldStack = *UserEsp; 00188 } 00189 00190 /* Read the GDI Batch count */ 00191 GdiBatchCount = Teb->GdiBatchCount; 00192 } 00193 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00194 { 00195 /* Get the SEH exception */ 00196 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00197 } 00198 _SEH2_END; 00199 00200 /* Check if we have GDI Batch operations */ 00201 if (GdiBatchCount) 00202 { 00203 *UserEsp -= 256; 00204 KeGdiFlushUserBatch(); 00205 } 00206 00207 /* Restore stack and return */ 00208 *UserEsp = OldStack; 00209 return CallbackStatus; 00210 } 00211 00212 00213 /* 00214 * Stack layout for KiUserModeCallout: 00215 * ---------------------------------- 00216 * KCALLOUT_FRAME.ResultLength <= 2nd Parameter to KiCallUserMode 00217 * KCALLOUT_FRAME.Result <= 1st Parameter to KiCallUserMode 00218 * KCALLOUT_FRAME.ReturnAddress <= Return address of KiCallUserMode 00219 * KCALLOUT_FRAME.Ebp \ 00220 * KCALLOUT_FRAME.Ebx | = non-volatile registers, pushed 00221 * KCALLOUT_FRAME.Esi | by KiCallUserMode 00222 * KCALLOUT_FRAME.Edi / 00223 * KCALLOUT_FRAME.CallbackStack 00224 * KCALLOUT_FRAME.TrapFrame 00225 * KCALLOUT_FRAME.InitialStack <= CalloutFrame points here 00226 * ---------------------------------- 00227 * ~~ optional alignment ~~ 00228 * ---------------------------------- 00229 * FX_SAVE_AREA 00230 * ---------------------------------- 00231 * KTRAP_FRAME 00232 * ---------------------------------- 00233 * ~~ begin of stack frame for KiUserModeCallout ~~ 00234 * 00235 */ 00236 00237 NTSTATUS 00238 FASTCALL 00239 KiUserModeCallout(PKCALLOUT_FRAME CalloutFrame) 00240 { 00241 PKTHREAD CurrentThread; 00242 PKTRAP_FRAME TrapFrame, CallbackTrapFrame; 00243 PFX_SAVE_AREA FxSaveArea, OldFxSaveArea; 00244 PKPCR Pcr; 00245 PKTSS Tss; 00246 ULONG_PTR InitialStack; 00247 NTSTATUS Status; 00248 00249 /* Get the current thread */ 00250 CurrentThread = KeGetCurrentThread(); 00251 00252 #if DBG 00253 /* Check if we are at pasive level */ 00254 if (KeGetCurrentIrql() != PASSIVE_LEVEL) 00255 { 00256 /* We're not, bugcheck */ 00257 KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE, 00258 0, 00259 KeGetCurrentIrql(), 00260 0, 00261 0); 00262 } 00263 00264 /* Check if we are attached or APCs are disabled */ 00265 if ((CurrentThread->ApcStateIndex != OriginalApcEnvironment) || 00266 (CurrentThread->CombinedApcDisable > 0)) 00267 { 00268 KeBugCheckEx(APC_INDEX_MISMATCH, 00269 0, 00270 CurrentThread->ApcStateIndex, 00271 CurrentThread->CombinedApcDisable, 00272 0); 00273 } 00274 #endif 00275 00276 /* Align stack on a 16-byte boundary */ 00277 InitialStack = ALIGN_DOWN_BY(CalloutFrame, 16); 00278 00279 /* Check if we have enough space on the stack */ 00280 if ((InitialStack - KERNEL_STACK_SIZE) < CurrentThread->StackLimit) 00281 { 00282 /* We don't, we'll have to grow our stack */ 00283 Status = MmGrowKernelStack((PVOID)InitialStack); 00284 00285 /* Quit if we failed */ 00286 if (!NT_SUCCESS(Status)) return Status; 00287 } 00288 00289 /* Save the current callback stack and initial stack */ 00290 CalloutFrame->CallbackStack = (ULONG_PTR)CurrentThread->CallbackStack; 00291 CalloutFrame->InitialStack = (ULONG_PTR)CurrentThread->InitialStack; 00292 00293 /* Get and save the trap frame */ 00294 TrapFrame = CurrentThread->TrapFrame; 00295 CalloutFrame->TrapFrame = (ULONG_PTR)TrapFrame; 00296 00297 /* Set the new callback stack */ 00298 CurrentThread->CallbackStack = CalloutFrame; 00299 00300 /* Set destination and origin NPX Areas */ 00301 OldFxSaveArea = (PVOID)(CalloutFrame->InitialStack - sizeof(FX_SAVE_AREA)); 00302 FxSaveArea = (PVOID)(InitialStack - sizeof(FX_SAVE_AREA)); 00303 00304 /* Disable interrupts so we can fill the NPX State */ 00305 _disable(); 00306 00307 /* Now copy the NPX State */ 00308 FxSaveArea->U.FnArea.ControlWord = OldFxSaveArea->U.FnArea.ControlWord; 00309 FxSaveArea->U.FnArea.StatusWord = OldFxSaveArea->U.FnArea.StatusWord; 00310 FxSaveArea->U.FnArea.TagWord = OldFxSaveArea->U.FnArea.TagWord; 00311 FxSaveArea->U.FnArea.DataSelector = OldFxSaveArea->U.FnArea.DataSelector; 00312 FxSaveArea->Cr0NpxState = OldFxSaveArea->Cr0NpxState; 00313 00314 /* Set the stack address */ 00315 CurrentThread->InitialStack = (PVOID)InitialStack; 00316 00317 /* Locate the trap frame on the callback stack */ 00318 CallbackTrapFrame = (PVOID)((ULONG_PTR)FxSaveArea - sizeof(KTRAP_FRAME)); 00319 00320 /* Copy the trap frame to the new location */ 00321 *CallbackTrapFrame = *TrapFrame; 00322 00323 /* Get PCR */ 00324 Pcr = KeGetPcr(); 00325 00326 /* Update the exception list */ 00327 CallbackTrapFrame->ExceptionList = Pcr->NtTib.ExceptionList; 00328 00329 /* Get TSS */ 00330 Tss = Pcr->TSS; 00331 00332 /* Check for V86 mode */ 00333 if (CallbackTrapFrame->EFlags & EFLAGS_V86_MASK) 00334 { 00335 /* Set new stack address in TSS (full trap frame) */ 00336 Tss->Esp0 = (ULONG_PTR)(CallbackTrapFrame + 1); 00337 } 00338 else 00339 { 00340 /* Set new stack address in TSS (non-V86 trap frame) */ 00341 Tss->Esp0 = (ULONG_PTR)&CallbackTrapFrame->V86Es; 00342 } 00343 00344 /* Set user-mode dispatcher address as EIP */ 00345 CallbackTrapFrame->Eip = (ULONG_PTR)KeUserCallbackDispatcher; 00346 00347 /* Bring interrupts back */ 00348 _enable(); 00349 00350 /* Exit to user-mode */ 00351 KiServiceExit(CallbackTrapFrame, 0); 00352 } 00353 00354 00355 /* EOF */ Generated on Sun May 27 2012 04:37:31 for ReactOS by
1.7.6.1
|