2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/i386/usercall.c
5 * PURPOSE: User-mode Callout Mechanisms (APC and Win32K Callbacks)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 extern PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch
;
17 /* PRIVATE FUNCTIONS *********************************************************/
20 * @name KiInitializeUserApc
22 * Prepares the Context for a User-Mode APC called through NTDLL.DLL
25 * Pointer to the Exception Frame on non-i386 builds.
28 * Pointer to the Trap Frame.
30 * @param NormalRoutine
31 * Pointer to the NormalRoutine to call.
33 * @param NormalContext
34 * Pointer to the context to send to the Normal Routine.
36 * @param SystemArgument[1-2]
37 * Pointer to a set of two parameters that contain untyped data.
46 KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame
,
47 IN PKTRAP_FRAME TrapFrame
,
48 IN PKNORMAL_ROUTINE NormalRoutine
,
49 IN PVOID NormalContext
,
50 IN PVOID SystemArgument1
,
51 IN PVOID SystemArgument2
)
54 ULONG_PTR Stack
, AlignedEsp
;
56 EXCEPTION_RECORD SehExceptRecord
;
58 /* Don't deliver APCs in V86 mode */
59 if (TrapFrame
->EFlags
& EFLAGS_V86_MASK
) return;
61 /* Save the full context */
62 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
63 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
65 /* Protect with SEH */
69 ASSERT((TrapFrame
->SegCs
& MODE_MASK
) != KernelMode
);
71 /* Get the aligned size */
72 AlignedEsp
= Context
.Esp
& ~3;
73 ContextLength
= CONTEXT_ALIGNED_SIZE
+ (4 * sizeof(ULONG_PTR
));
74 Stack
= ((AlignedEsp
- 8) & ~3) - ContextLength
;
77 ProbeForWrite((PVOID
)Stack
, AlignedEsp
- Stack
, 1);
80 /* Copy data into it */
81 RtlCopyMemory((PVOID
)(Stack
+ (4 * sizeof(ULONG_PTR
))),
85 /* Run at APC dispatcher */
86 TrapFrame
->Eip
= (ULONG
)KeUserApcDispatcher
;
87 TrapFrame
->HardwareEsp
= Stack
;
89 /* Setup Ring 3 state */
90 TrapFrame
->SegCs
= Ke386SanitizeSeg(KGDT_R3_CODE
, UserMode
);
91 TrapFrame
->HardwareSegSs
= Ke386SanitizeSeg(KGDT_R3_DATA
, UserMode
);
92 TrapFrame
->SegDs
= Ke386SanitizeSeg(KGDT_R3_DATA
, UserMode
);
93 TrapFrame
->SegEs
= Ke386SanitizeSeg(KGDT_R3_DATA
, UserMode
);
94 TrapFrame
->SegFs
= Ke386SanitizeSeg(KGDT_R3_TEB
, UserMode
);
96 TrapFrame
->ErrCode
= 0;
99 TrapFrame
->EFlags
= Ke386SanitizeFlags(Context
.EFlags
, UserMode
);
101 /* Check if thread has IOPL and force it enabled if so */
102 if (KeGetCurrentThread()->Iopl
) TrapFrame
->EFlags
|= EFLAGS_IOPL
;
104 /* Setup the stack */
105 *(PULONG_PTR
)(Stack
+ 0 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)NormalRoutine
;
106 *(PULONG_PTR
)(Stack
+ 1 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)NormalContext
;
107 *(PULONG_PTR
)(Stack
+ 2 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)SystemArgument1
;
108 *(PULONG_PTR
)(Stack
+ 3 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)SystemArgument2
;
110 _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord
, _SEH2_GetExceptionInformation()->ExceptionRecord
, sizeof(EXCEPTION_RECORD
)), EXCEPTION_EXECUTE_HANDLER
))
112 /* Dispatch the exception */
113 SehExceptRecord
.ExceptionAddress
= (PVOID
)TrapFrame
->Eip
;
114 KiDispatchException(&SehExceptRecord
,
123 /* PUBLIC FUNCTIONS **********************************************************/
130 KeUserModeCallback(IN ULONG RoutineIndex
,
132 IN ULONG ArgumentLength
,
134 OUT PULONG ResultLength
)
136 ULONG_PTR NewStack
, OldStack
;
138 NTSTATUS CallbackStatus
;
139 PEXCEPTION_REGISTRATION_RECORD ExceptionList
;
141 ULONG GdiBatchCount
= 0;
142 ASSERT(KeGetCurrentThread()->ApcState
.KernelApcInProgress
== FALSE
);
143 ASSERT(KeGetPreviousMode() == UserMode
);
145 /* Get the current user-mode stack */
146 UserEsp
= KiGetUserModeStackAddress();
149 /* Enter a SEH Block */
152 /* Calculate and align the stack size */
153 NewStack
= (OldStack
- ArgumentLength
) & ~3;
155 /* Make sure it's writable */
156 ProbeForWrite((PVOID
)(NewStack
- 6 * sizeof(ULONG_PTR
)),
157 ArgumentLength
+ 6 * sizeof(ULONG_PTR
),
160 /* Copy the buffer into the stack */
161 RtlCopyMemory((PVOID
)NewStack
, Argument
, ArgumentLength
);
163 /* Write the arguments */
165 *(PULONG
)NewStack
= 0;
166 *(PULONG
)(NewStack
+ 4) = RoutineIndex
;
167 *(PULONG
)(NewStack
+ 8) = (NewStack
+ 24);
168 *(PULONG
)(NewStack
+ 12) = ArgumentLength
;
170 /* Save the exception list */
171 Teb
= KeGetCurrentThread()->Teb
;
172 ExceptionList
= Teb
->Tib
.ExceptionList
;
174 /* Jump to user mode */
176 CallbackStatus
= KiCallUserMode(Result
, ResultLength
);
177 if (CallbackStatus
!= STATUS_CALLBACK_POP_STACK
)
179 /* Only restore the exception list if we didn't crash in ring 3 */
180 Teb
->Tib
.ExceptionList
= ExceptionList
;
181 CallbackStatus
= STATUS_SUCCESS
;
185 /* Otherwise, pop the stack */
189 /* Read the GDI Batch count */
190 GdiBatchCount
= Teb
->GdiBatchCount
;
192 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
194 /* Get the SEH exception */
195 _SEH2_YIELD(return _SEH2_GetExceptionCode());
199 /* Check if we have GDI Batch operations */
203 KeGdiFlushUserBatch();
206 /* Restore stack and return */
208 return CallbackStatus
;