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 ******************************************************************/
13 #include <internal/debug.h>
15 /* PRIVATE FUNCTIONS *********************************************************/
17 _SEH_DEFINE_LOCALS(KiCopyInfo
)
19 volatile EXCEPTION_RECORD SehExceptRecord
;
22 _SEH_FILTER(KiCopyInformation2
)
24 _SEH_ACCESS_LOCALS(KiCopyInfo
);
26 /* Copy the exception records and return to the handler */
27 RtlMoveMemory((PVOID
)&_SEH_VAR(SehExceptRecord
),
28 _SEH_GetExceptionPointers()->ExceptionRecord
,
29 sizeof(EXCEPTION_RECORD
));
30 return EXCEPTION_EXECUTE_HANDLER
;
34 * @name KiInitializeUserApc
36 * Prepares the Context for a User-Mode APC called through NTDLL.DLL
39 * Pointer to the Exception Frame on non-i386 builds.
42 * Pointer to the Trap Frame.
44 * @param NormalRoutine
45 * Pointer to the NormalRoutine to call.
47 * @param NormalContext
48 * Pointer to the context to send to the Normal Routine.
50 * @param SystemArgument[1-2]
51 * Pointer to a set of two parameters that contain untyped data.
60 KiInitializeUserApc(IN PKEXCEPTION_FRAME ExceptionFrame
,
61 IN PKTRAP_FRAME TrapFrame
,
62 IN PKNORMAL_ROUTINE NormalRoutine
,
63 IN PVOID NormalContext
,
64 IN PVOID SystemArgument1
,
65 IN PVOID SystemArgument2
)
70 EXCEPTION_RECORD SehExceptRecord
;
71 _SEH_DECLARE_LOCALS(KiCopyInfo
);
73 /* Don't deliver APCs in V86 mode */
74 if (TrapFrame
->EFlags
& X86_EFLAGS_VM
) return;
76 /* Save the full context */
77 Context
.ContextFlags
= CONTEXT_FULL
| CONTEXT_DEBUG_REGISTERS
;
78 KeTrapFrameToContext(TrapFrame
, ExceptionFrame
, &Context
);
80 /* Protect with SEH */
84 ASSERT((TrapFrame
->SegCs
& MODE_MASK
) != KernelMode
);
86 /* Get the aligned size */
87 Size
= ((sizeof(CONTEXT
) + 3) & ~3) + 4 * sizeof(ULONG_PTR
);
88 Stack
= (Context
.Esp
& ~3) - Size
;
91 ProbeForWrite((PVOID
)Stack
, Size
, 4);
92 RtlMoveMemory((PVOID
)(Stack
+ (4 * sizeof(ULONG_PTR
))),
96 /* Run at APC dispatcher */
97 TrapFrame
->Eip
= (ULONG
)KeUserApcDispatcher
;
98 TrapFrame
->HardwareEsp
= Stack
;
100 /* Setup Ring 3 state */
101 TrapFrame
->SegCs
= KGDT_R3_CODE
| RPL_MASK
;
102 TrapFrame
->HardwareSegSs
= KGDT_R3_DATA
| RPL_MASK
;
103 TrapFrame
->SegDs
= KGDT_R3_DATA
| RPL_MASK
;
104 TrapFrame
->SegEs
= KGDT_R3_DATA
| RPL_MASK
;
105 TrapFrame
->SegGs
= 0;
107 /* Sanitize EFLAGS */
108 TrapFrame
->EFlags
= Context
.EFlags
& EFLAGS_USER_SANITIZE
;
109 TrapFrame
->EFlags
|= EFLAGS_INTERRUPT_MASK
;
111 /* Check if user-mode has IO privileges */
112 if (KeGetCurrentThread()->Iopl
)
115 TrapFrame
->EFlags
|= (0x3000);
118 /* Setup the stack */
119 *(PULONG_PTR
)(Stack
+ 0 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)NormalRoutine
;
120 *(PULONG_PTR
)(Stack
+ 1 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)NormalContext
;
121 *(PULONG_PTR
)(Stack
+ 2 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)SystemArgument1
;
122 *(PULONG_PTR
)(Stack
+ 3 * sizeof(ULONG_PTR
)) = (ULONG_PTR
)SystemArgument2
;
124 _SEH_EXCEPT(KiCopyInformation2
)
126 /* Dispatch the exception */
127 _SEH_VAR(SehExceptRecord
).ExceptionAddress
= (PVOID
)TrapFrame
->Eip
;
128 KiDispatchException(&SehExceptRecord
,
137 /* PUBLIC FUNCTIONS **********************************************************/
144 KeUserModeCallback(IN ULONG RoutineIndex
,
146 IN ULONG ArgumentLength
,
148 OUT PULONG ResultLength
)
150 ULONG_PTR NewStack
, OldStack
;
152 NTSTATUS CallbackStatus
= STATUS_SUCCESS
;
153 PEXCEPTION_REGISTRATION_RECORD ExceptionList
;
155 ULONG GdiBatchCount
= 0;
156 ASSERT(KeGetCurrentThread()->ApcState
.KernelApcInProgress
== FALSE
);
157 ASSERT(KeGetPreviousMode() == UserMode
);
159 /* Get the current user-mode stack */
160 UserEsp
= KiGetUserModeStackAddress();
163 /* Enter a SEH Block */
166 /* Calculate and align the stack size */
167 NewStack
= (OldStack
- ArgumentLength
) & ~3;
169 /* Make sure it's writable */
170 ProbeForWrite((PVOID
)(NewStack
- 6 * sizeof(ULONG_PTR
)),
171 ArgumentLength
+ 6 * sizeof(ULONG_PTR
),
174 /* Copy the buffer into the stack */
175 RtlCopyMemory((PVOID
)NewStack
, Argument
, ArgumentLength
);
177 /* Write the arguments */
179 *(PULONG
)NewStack
= 0;
180 *(PULONG
)(NewStack
+ 4) = RoutineIndex
;
181 *(PULONG
)(NewStack
+ 8) = (NewStack
+ 24);
182 *(PULONG
)(NewStack
+ 12) = ArgumentLength
;
184 /* Save the exception list */
185 Teb
= KeGetCurrentThread()->Teb
;
186 ExceptionList
= Teb
->Tib
.ExceptionList
;
188 /* Jump to user mode */
190 CallbackStatus
= KiCallUserMode(Result
, ResultLength
);
191 if (CallbackStatus
!= STATUS_CALLBACK_POP_STACK
)
193 /* Only restore the exception list if we didn't crash in ring 3 */
194 Teb
->Tib
.ExceptionList
= ExceptionList
;
195 CallbackStatus
= STATUS_SUCCESS
;
199 /* Otherwise, pop the stack */
203 /* Read the GDI Batch count */
204 GdiBatchCount
= Teb
->GdiBatchCount
;
208 /* Get the SEH exception */
209 CallbackStatus
= _SEH_GetExceptionCode();
212 if (!NT_SUCCESS(CallbackStatus
)) return CallbackStatus
;
214 /* Check if we have GDI Batch operations */
217 /* Shouldn't happen in ROS yet */
221 /* Restore stack and return */
223 return CallbackStatus
;