ReactOS 0.4.16-dev-980-g00983aa
usercall.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - 2.0 + (https ://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: AMD64 User-mode Callout Mechanisms (APC and Win32K Callbacks)
5 * COPYRIGHT: Timo Kreuzer(timo.kreuzer@reactos.org)
6 */
7
8/* INCLUDES ******************************************************************/
9
10#include <ntoskrnl.h>
11#define NDEBUG
12#include <debug.h>
13
46VOID
49 _In_ PKEXCEPTION_FRAME ExceptionFrame,
50 _Inout_ PKTRAP_FRAME TrapFrame,
51 _In_ PKNORMAL_ROUTINE NormalRoutine,
52 _In_ PVOID NormalContext,
55{
56 PUAPC_FRAME ApcFrame;
58 EXCEPTION_RECORD ExceptionRecord;
59
60 /* Sanity check, that the trap frame is from user mode */
61 ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
62
63 /* Allocate a 16 byte aligned UAPC_FRAME structure on the user stack */
64 ApcFrame = (PUAPC_FRAME)ALIGN_DOWN_POINTER_BY(TrapFrame->Rsp - sizeof(*ApcFrame), 16);
65 Context = &ApcFrame->Context;
66
67 /* Protect with SEH */
69 {
70 /* Probe the user mode APC frame */
71 ProbeForWrite(ApcFrame, sizeof(*ApcFrame), 16);
72
73 /* Convert the current trap frame to a context */
75 KeTrapFrameToContext(TrapFrame, ExceptionFrame, Context);
76
77 /* Set parameters for KiUserApcDispatcher */
78 Context->P1Home = (ULONG64)NormalContext;
81 Context->P4Home = (ULONG64)NormalRoutine;
82
83 /* Set up the machine frame for unwinding */
84 ApcFrame->MachineFrame.Rip = TrapFrame->Rip;
85 ApcFrame->MachineFrame.Rsp = TrapFrame->Rsp;
86 }
87 _SEH2_EXCEPT(ExceptionRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord, EXCEPTION_EXECUTE_HANDLER)
88 {
89 /* Dispatch the exception */
90 ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
91 KiDispatchException(&ExceptionRecord,
92 ExceptionFrame,
93 TrapFrame,
95 TRUE);
96 }
98
99 /* Set the stack pointer to the context record */
100 TrapFrame->Rsp = (ULONG64)Context;
101
102 /* We jump to KiUserApcDispatcher in ntdll */
103 TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
104
105 /* Setup Ring 3 segments */
106 TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
107 TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
108 TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
109 TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
110
111 /* Sanitize EFLAGS, enable interrupts */
112 TrapFrame->EFlags &= EFLAGS_USER_SANITIZE;
113 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
114}
115
116/*
117 * Stack layout for KiUserModeCallout:
118 * ----------------------------------
119 * KCALLOUT_FRAME.ResultLength <= 2nd Parameter to KiCallUserMode
120 * KCALLOUT_FRAME.Result <= 1st Parameter to KiCallUserMode
121 * KCALLOUT_FRAME.ReturnAddress <= Return address of KiCallUserMode
122 * KCALLOUT_FRAME.Ebp \
123 * KCALLOUT_FRAME.Ebx | = non-volatile registers, pushed
124 * KCALLOUT_FRAME.Esi | by KiCallUserMode
125 * KCALLOUT_FRAME.Edi /
126 * KCALLOUT_FRAME.CallbackStack
127 * KCALLOUT_FRAME.TrapFrame
128 * KCALLOUT_FRAME.InitialStack <= CalloutFrame points here
129 * ----------------------------------
130 * ~~ optional alignment ~~
131 * ----------------------------------
132 * FX_SAVE_AREA
133 * ----------------------------------
134 * KTRAP_FRAME
135 * ----------------------------------
136 * ~~ begin of stack frame for KiUserModeCallout ~~
137 *
138 */
142 _Out_ PKCALLOUT_FRAME CalloutFrame)
143{
144 PKTHREAD CurrentThread;
145 PKTRAP_FRAME TrapFrame;
146 KTRAP_FRAME CallbackTrapFrame;
147 PKIPCR Pcr;
148 ULONG_PTR InitialStack;
150
151 /* Get the current thread */
152 CurrentThread = KeGetCurrentThread();
153
154 /* Check if we are at pasive level */
156
157 /* Check if we are attached or APCs are disabled */
158 ASSERT((CurrentThread->ApcStateIndex == OriginalApcEnvironment) &&
159 (CurrentThread->CombinedApcDisable == 0));
160
161 /* Align stack on a 16-byte boundary */
162 InitialStack = (ULONG_PTR)ALIGN_DOWN_POINTER_BY(CalloutFrame, 16);
163
164 /* Check if we have enough space on the stack */
165 if ((InitialStack - KERNEL_STACK_SIZE) < CurrentThread->StackLimit)
166 {
167 /* We don't, we'll have to grow our stack */
168 Status = MmGrowKernelStack((PVOID)InitialStack);
169
170 /* Quit if we failed */
171 if (!NT_SUCCESS(Status)) return Status;
172 }
173
174 /* Save the current callback stack and initial stack */
175 CalloutFrame->CallbackStack = (ULONG_PTR)CurrentThread->CallbackStack;
176 CalloutFrame->InitialStack = (ULONG_PTR)CurrentThread->InitialStack;
177
178 /* Get and save the trap frame */
179 TrapFrame = CurrentThread->TrapFrame;
180 CalloutFrame->TrapFrame = (ULONG_PTR)TrapFrame;
181
182 /* Set the new callback stack */
183 CurrentThread->CallbackStack = CalloutFrame;
184
185 /* Disable interrupts so we can fill the NPX State */
186 _disable();
187
188 /* Set the stack address */
189 CurrentThread->InitialStack = (PVOID)InitialStack;
190
191 /* Copy the trap frame to the new location */
192 CallbackTrapFrame = *TrapFrame;
193
194 /* Get PCR */
195 Pcr = (PKIPCR)KeGetPcr();
196
197 /* Set user-mode dispatcher address as EIP */
198 Pcr->TssBase->Rsp0 = InitialStack;
199 Pcr->Prcb.RspBase = InitialStack;
200 CallbackTrapFrame.Rip = (ULONG_PTR)KeUserCallbackDispatcher;
201
202 /* Bring interrupts back */
203 _enable();
204
205 /* Exit to user-mode */
206 KiUserCallbackExit(&CallbackTrapFrame);
207}
208
209VOID
211 _Out_ PUCALLOUT_FRAME UserCalloutFrame,
212 _In_ PKTRAP_FRAME TrapFrame,
213 _In_ ULONG ApiNumber,
216{
217#ifdef _M_IX86
218 CalloutFrame->Reserved = 0;
219 CalloutFrame->ApiNumber = ApiNumber;
220 CalloutFrame->Buffer = (ULONG_PTR)NewStack;
221 CalloutFrame->Length = ArgumentLength;
222#elif defined(_M_AMD64)
223 UserCalloutFrame->Buffer = (PVOID)(UserCalloutFrame + 1);
224 UserCalloutFrame->Length = BufferLength;
225 UserCalloutFrame->ApiNumber = ApiNumber;
226 UserCalloutFrame->MachineFrame.Rip = TrapFrame->Rip;
227 UserCalloutFrame->MachineFrame.Rsp = TrapFrame->Rsp;
228#else
229#error "KiSetupUserCalloutFrame not implemented!"
230#endif
231}
232
234NTAPI
236 IN ULONG RoutineIndex,
237 IN PVOID Argument,
238 IN ULONG ArgumentLength,
241{
242 ULONG_PTR OldStack;
243 PUCHAR UserArguments;
244 PUCALLOUT_FRAME CalloutFrame;
245 PULONG_PTR UserStackPointer;
247#ifdef _M_IX86
248 PEXCEPTION_REGISTRATION_RECORD ExceptionList;
249#endif // _M_IX86
250 PTEB Teb;
251 ULONG GdiBatchCount = 0;
252 ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
254
255 /* Get the current user-mode stack */
256 UserStackPointer = KiGetUserModeStackAddress();
257 OldStack = *UserStackPointer;
258
259 /* Enter a SEH Block */
261 {
262 /* Calculate and align the stack. This is unaligned by 8 bytes, since the following
263 UCALLOUT_FRAME compensates for that and on entry we already have a full stack
264 frame with home space for the next call, i.e. we are already inside the function
265 body and the stack needs to be 16 byte aligned. */
266 UserArguments = (PUCHAR)ALIGN_DOWN_POINTER_BY(OldStack - ArgumentLength, 16) - 8;
267
268 /* The callout frame is below the arguments */
269 CalloutFrame = ((PUCALLOUT_FRAME)UserArguments) - 1;
270
271 /* Make sure it's all writable */
272 ProbeForWrite(CalloutFrame,
273 sizeof(PUCALLOUT_FRAME) + ArgumentLength,
274 sizeof(PVOID));
275
276 /* Copy the buffer into the stack */
277 RtlCopyMemory(UserArguments, Argument, ArgumentLength);
278
279 /* Write the arguments */
280 KiSetupUserCalloutFrame(CalloutFrame,
281 KeGetCurrentThread()->TrapFrame,
282 RoutineIndex,
283 UserArguments,
284 ArgumentLength);
285
286 /* Save the exception list */
287 Teb = KeGetCurrentThread()->Teb;
288#ifdef _M_IX86
289 ExceptionList = Teb->NtTib.ExceptionList;
290#endif // _M_IX86
291
292 /* Jump to user mode */
293 *UserStackPointer = (ULONG_PTR)CalloutFrame;
296 {
297#ifdef _M_IX86
298 /* Only restore the exception list if we didn't crash in ring 3 */
299 Teb->NtTib.ExceptionList = ExceptionList;
300#endif // _M_IX86
301 }
302 else
303 {
304 /* Otherwise, pop the stack */
305 OldStack = *UserStackPointer;
306 }
307
308 /* Read the GDI Batch count */
309 GdiBatchCount = Teb->GdiBatchCount;
310 }
312 {
313 /* Get the SEH exception */
315 }
316 _SEH2_END;
317
318 /* Check if we have GDI Batch operations */
319 if (GdiBatchCount)
320 {
321 *UserStackPointer -= 256;
323 }
324
325 /* Restore stack and return */
326 *UserStackPointer = OldStack;
327 return CallbackStatus;
328}
329
331NTAPI
336{
337 PKTHREAD CurrentThread;
338 PKCALLOUT_FRAME CalloutFrame;
339 PKTRAP_FRAME CallbackTrapFrame, TrapFrame;
340 PKIPCR Pcr;
341
342 /* Get the current thread and make sure we have a callback stack */
343 CurrentThread = KeGetCurrentThread();
344 CalloutFrame = CurrentThread->CallbackStack;
345 if (CalloutFrame == NULL)
346 {
348 }
349
350 /* Store the results in the callback stack */
351 *((PVOID*)CalloutFrame->OutputBuffer) = Result;
352 *((ULONG*)CalloutFrame->OutputLength) = ResultLength;
353
354 /* Get the trap frame */
355 CallbackTrapFrame = CurrentThread->TrapFrame;
356
357 /* Disable interrupts for NPX save and stack switch */
358 _disable();
359
360 /* Restore the exception list */
361 Pcr = (PKIPCR)KeGetPcr();
362
363 /* Get the previous trap frame */
364 TrapFrame = (PKTRAP_FRAME)CalloutFrame->TrapFrame;
365
366 /* Check if we failed in user mode */
368 {
369 *TrapFrame = *CallbackTrapFrame;
370 }
371
372 /* Clear DR7 */
373 TrapFrame->Dr7 = 0;
374
375 /* Check if debugging was active */
376 if (CurrentThread->Header.DebugActive & 0xFF)
377 {
378 /* Copy debug registers data from it */
379 TrapFrame->Dr0 = CallbackTrapFrame->Dr0;
380 TrapFrame->Dr1 = CallbackTrapFrame->Dr1;
381 TrapFrame->Dr2 = CallbackTrapFrame->Dr2;
382 TrapFrame->Dr3 = CallbackTrapFrame->Dr3;
383 TrapFrame->Dr6 = CallbackTrapFrame->Dr6;
384 TrapFrame->Dr7 = CallbackTrapFrame->Dr7;
385 }
386
387 /* Switch the stack back to the previous value */
388 Pcr->TssBase->Rsp0 = CalloutFrame->InitialStack;
389 Pcr->Prcb.RspBase = CalloutFrame->InitialStack;
390
391 /* Get the initial stack and restore it */
392 CurrentThread->InitialStack = (PVOID)CalloutFrame->InitialStack;
393
394 /* Restore the trap frame and the previous callback stack */
395 CurrentThread->TrapFrame = TrapFrame;
396 CurrentThread->CallbackStack = (PVOID)CalloutFrame->CallbackStack;
397
398 /* Bring interrupts back */
399 _enable();
400
401 /* Now switch back to the old stack */
402 KiCallbackReturn(CalloutFrame, CallbackStatus);
403}
404
#define EFLAGS_INTERRUPT_MASK
Definition: SystemCall.c:11
NTSTATUS FASTCALL KiUserModeCallout(_Out_ PKCALLOUT_FRAME CalloutFrame)
Definition: usercall.c:141
NTSTATUS NTAPI KeUserModeCallback(IN ULONG RoutineIndex, IN PVOID Argument, IN ULONG ArgumentLength, OUT PVOID *Result, OUT PULONG ResultLength)
Definition: usercall.c:235
VOID NTAPI KiInitializeUserApc(_In_ PKEXCEPTION_FRAME ExceptionFrame, _Inout_ PKTRAP_FRAME TrapFrame, _In_ PKNORMAL_ROUTINE NormalRoutine, _In_ PVOID NormalContext, _In_ PVOID SystemArgument1, _In_ PVOID SystemArgument2)
Definition: usercall.c:48
VOID KiSetupUserCalloutFrame(_Out_ PUCALLOUT_FRAME UserCalloutFrame, _In_ PKTRAP_FRAME TrapFrame, _In_ ULONG ApiNumber, _In_ PVOID Buffer, _In_ ULONG BufferLength)
Definition: usercall.c:210
NTSTATUS NTAPI NtCallbackReturn(_In_ PVOID Result, _In_ ULONG ResultLength, _In_ NTSTATUS CallbackStatus)
Definition: usercall.c:332
LONG NTSTATUS
Definition: precomp.h:26
#define MODE_MASK
Definition: orders.h:326
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define ULONG_PTR
Definition: config.h:101
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
VOID NTAPI ProbeForWrite(IN PVOID Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:143
_In_ FLT_PREOP_CALLBACK_STATUS CallbackStatus
Definition: fltkernel.h:1020
Status
Definition: gdiplustypes.h:25
#define KeGetCurrentThread
Definition: hal.h:55
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 ULONG64
Definition: imports.h:198
#define EFLAGS_USER_SANITIZE
Definition: ketypes.h:202
#define KGDT64_R3_CODE
Definition: ketypes.h:126
#define KGDT64_R3_DATA
Definition: ketypes.h:125
struct _UCALLOUT_FRAME * PUCALLOUT_FRAME
struct _KIPCR * PKIPCR
#define KGDT64_R3_CMTEB
Definition: ketypes.h:128
struct _UAPC_FRAME * PUAPC_FRAME
struct _KTRAP_FRAME * PKTRAP_FRAME
#define RPL_MASK
Definition: ketypes.h:119
#define KeGetPreviousMode()
Definition: ketypes.h:1115
#define KernelMode
Definition: asm.h:38
#define UserMode
Definition: asm.h:39
#define KeGetPcr()
Definition: ketypes.h:81
@ OriginalApcEnvironment
Definition: ketypes.h:767
VOID(NTAPI * PKNORMAL_ROUTINE)(IN PVOID NormalContext OPTIONAL, IN PVOID SystemArgument1 OPTIONAL, IN PVOID SystemArgument2 OPTIONAL)
Definition: ketypes.h:744
#define _Inout_
Definition: no_sal2.h:162
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define CONTEXT_DEBUG_REGISTERS
Definition: nt_native.h:1373
#define FASTCALL
Definition: nt_native.h:50
#define CONTEXT_FULL
Definition: nt_native.h:1375
DECLSPEC_NORETURN VOID KiUserCallbackExit(_In_ PKTRAP_FRAME TrapFrame)
FORCEINLINE PULONG_PTR KiGetUserModeStackAddress(void)
Definition: ke.h:469
DECLSPEC_NORETURN VOID FASTCALL KiCallbackReturn(IN PVOID Stack, IN NTSTATUS Status)
VOID NTAPI KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN OUT PCONTEXT Context)
Definition: context.c:169
PVOID KeUserCallbackDispatcher
Definition: ke.h:147
PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch
Definition: win32.c:20
NTSTATUS NTAPI KiCallUserMode(IN PVOID *OutputBuffer, IN PULONG OutputLength)
Definition: usercall.c:321
VOID NTAPI KiDispatchException(PEXCEPTION_RECORD ExceptionRecord, PKEXCEPTION_FRAME ExceptionFrame, PKTRAP_FRAME Tf, KPROCESSOR_MODE PreviousMode, BOOLEAN SearchFrames)
PVOID KeUserApcDispatcher
Definition: ke.h:146
NTSTATUS NTAPI MmGrowKernelStack(IN PVOID StackPointer)
Definition: procsup.c:477
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1777
#define STATUS_CALLBACK_POP_STACK
Definition: ntstatus.h:961
#define STATUS_NO_CALLBACK_ACTIVE
Definition: ntstatus.h:726
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:180
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:184
#define KERNEL_STACK_SIZE
BOOLEAN DebugActive
Definition: ketypes.h:793
PVOID ExceptionAddress
Definition: compat.h:211
ULONG64 OutputBuffer
Definition: ketypes.h:1050
ULONG64 OutputLength
Definition: ketypes.h:1051
ULONG64 TrapFrame
Definition: ketypes.h:1046
KPRCB Prcb
Definition: ketypes.h:988
struct _KTSS64 * TssBase
Definition: ketypes.h:960
UINT64 RspBase
Definition: ketypes.h:669
PKTRAP_FRAME TrapFrame
Definition: ketypes.h:1774
PVOID InitialStack
Definition: ketypes.h:1664
ULONG CombinedApcDisable
Definition: ketypes.h:1883
UCHAR ApcStateIndex
Definition: ketypes.h:1942
DISPATCHER_HEADER Header
Definition: ketypes.h:1661
volatile VOID * StackLimit
Definition: ketypes.h:1665
UINT64 Dr0
Definition: ketypes.h:436
UINT64 Dr6
Definition: ketypes.h:440
UINT64 Dr3
Definition: ketypes.h:439
UINT64 Dr7
Definition: ketypes.h:441
UINT64 Dr1
Definition: ketypes.h:437
UINT64 Rip
Definition: ketypes.h:473
UINT64 TrapFrame
Definition: ketypes.h:462
UINT64 Dr2
Definition: ketypes.h:438
ULONG64 Rsp
Definition: ketypes.h:1074
ULONG64 Rip
Definition: ketypes.h:1069
struct _EXCEPTION_REGISTRATION_RECORD * ExceptionList
Definition: compat.h:711
Definition: compat.h:836
NT_TIB NtTib
Definition: ntddk_ex.h:332
ULONG GdiBatchCount
Definition: compat.h:887
MACHINE_FRAME MachineFrame
Definition: ketypes.h:1105
CONTEXT Context
Definition: ketypes.h:1104
uint32_t * PULONG_PTR
Definition: typedefs.h:65
uint32_t * PULONG
Definition: typedefs.h:59
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define ALIGN_DOWN_POINTER_BY(ptr, align)
Definition: umtypes.h:82
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689