ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

usercall.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.