ReactOS 0.4.15-dev-7934-g1dc8d80
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{
57 EXCEPTION_RECORD ExceptionRecord;
58
59 /* Sanity check, that the trap frame is from user mode */
60 ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
61
62 /* Align the user tack to 16 bytes and allocate space for a CONTEXT structure */
63 Context = (PCONTEXT)ALIGN_DOWN_POINTER_BY(TrapFrame->Rsp, 16) - 1;
64
65 /* Protect with SEH */
67 {
68 /* Probe the context */
69 ProbeForWrite(Context, sizeof(CONTEXT), 16);
70
71 /* Convert the current trap frame to a context */
73 KeTrapFrameToContext(TrapFrame, ExceptionFrame, Context);
74
75 /* Set parameters for KiUserApcDispatcher */
76 Context->P1Home = (ULONG64)NormalContext;
79 Context->P4Home = (ULONG64)NormalRoutine;
80 }
81 _SEH2_EXCEPT(ExceptionRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord, EXCEPTION_EXECUTE_HANDLER)
82 {
83 /* Dispatch the exception */
84 ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
85 KiDispatchException(&ExceptionRecord,
86 ExceptionFrame,
87 TrapFrame,
89 TRUE);
90 }
92
93 /* Set the stack pointer to the context record */
94 TrapFrame->Rsp = (ULONG64)Context;
95
96 /* We jump to KiUserApcDispatcher in ntdll */
97 TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
98
99 /* Setup Ring 3 segments */
100 TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
101 TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
102 TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
103 TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
104
105 /* Sanitize EFLAGS, enable interrupts */
106 TrapFrame->EFlags &= EFLAGS_USER_SANITIZE;
107 TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
108}
109
110/*
111 * Stack layout for KiUserModeCallout:
112 * ----------------------------------
113 * KCALLOUT_FRAME.ResultLength <= 2nd Parameter to KiCallUserMode
114 * KCALLOUT_FRAME.Result <= 1st Parameter to KiCallUserMode
115 * KCALLOUT_FRAME.ReturnAddress <= Return address of KiCallUserMode
116 * KCALLOUT_FRAME.Ebp \
117 * KCALLOUT_FRAME.Ebx | = non-volatile registers, pushed
118 * KCALLOUT_FRAME.Esi | by KiCallUserMode
119 * KCALLOUT_FRAME.Edi /
120 * KCALLOUT_FRAME.CallbackStack
121 * KCALLOUT_FRAME.TrapFrame
122 * KCALLOUT_FRAME.InitialStack <= CalloutFrame points here
123 * ----------------------------------
124 * ~~ optional alignment ~~
125 * ----------------------------------
126 * FX_SAVE_AREA
127 * ----------------------------------
128 * KTRAP_FRAME
129 * ----------------------------------
130 * ~~ begin of stack frame for KiUserModeCallout ~~
131 *
132 */
136 _Out_ PKCALLOUT_FRAME CalloutFrame)
137{
138 PKTHREAD CurrentThread;
139 PKTRAP_FRAME TrapFrame;
140 KTRAP_FRAME CallbackTrapFrame;
141 PKIPCR Pcr;
142 ULONG_PTR InitialStack;
144
145 /* Get the current thread */
146 CurrentThread = KeGetCurrentThread();
147
148 /* Check if we are at pasive level */
150
151 /* Check if we are attached or APCs are disabled */
152 ASSERT((CurrentThread->ApcStateIndex == OriginalApcEnvironment) &&
153 (CurrentThread->CombinedApcDisable == 0));
154
155 /* Align stack on a 16-byte boundary */
156 InitialStack = (ULONG_PTR)ALIGN_DOWN_POINTER_BY(CalloutFrame, 16);
157
158 /* Check if we have enough space on the stack */
159 if ((InitialStack - KERNEL_STACK_SIZE) < CurrentThread->StackLimit)
160 {
161 /* We don't, we'll have to grow our stack */
162 Status = MmGrowKernelStack((PVOID)InitialStack);
163
164 /* Quit if we failed */
165 if (!NT_SUCCESS(Status)) return Status;
166 }
167
168 /* Save the current callback stack and initial stack */
169 CalloutFrame->CallbackStack = (ULONG_PTR)CurrentThread->CallbackStack;
170 CalloutFrame->InitialStack = (ULONG_PTR)CurrentThread->InitialStack;
171
172 /* Get and save the trap frame */
173 TrapFrame = CurrentThread->TrapFrame;
174 CalloutFrame->TrapFrame = (ULONG_PTR)TrapFrame;
175
176 /* Set the new callback stack */
177 CurrentThread->CallbackStack = CalloutFrame;
178
179 /* Disable interrupts so we can fill the NPX State */
180 _disable();
181
182 /* Set the stack address */
183 CurrentThread->InitialStack = (PVOID)InitialStack;
184
185 /* Copy the trap frame to the new location */
186 CallbackTrapFrame = *TrapFrame;
187
188 /* Get PCR */
189 Pcr = (PKIPCR)KeGetPcr();
190
191 /* Set user-mode dispatcher address as EIP */
192 Pcr->TssBase->Rsp0 = InitialStack;
193 Pcr->Prcb.RspBase = InitialStack;
194 CallbackTrapFrame.Rip = (ULONG_PTR)KeUserCallbackDispatcher;
195
196 /* Bring interrupts back */
197 _enable();
198
199 /* Exit to user-mode */
200 KiUserCallbackExit(&CallbackTrapFrame);
201}
202
203VOID
205 _Out_ PUCALLOUT_FRAME UserCalloutFrame,
206 _In_ PKTRAP_FRAME TrapFrame,
207 _In_ ULONG ApiNumber,
210{
211#ifdef _M_IX86
212 CalloutFrame->Reserved = 0;
213 CalloutFrame->ApiNumber = ApiNumber;
214 CalloutFrame->Buffer = (ULONG_PTR)NewStack;
215 CalloutFrame->Length = ArgumentLength;
216#elif defined(_M_AMD64)
217 UserCalloutFrame->Buffer = (PVOID)(UserCalloutFrame + 1);
218 UserCalloutFrame->Length = BufferLength;
219 UserCalloutFrame->ApiNumber = ApiNumber;
220 UserCalloutFrame->MachineFrame.Rip = TrapFrame->Rip;
221 UserCalloutFrame->MachineFrame.Rsp = TrapFrame->Rsp;
222#else
223#error "KiSetupUserCalloutFrame not implemented!"
224#endif
225}
226
228NTAPI
230 IN ULONG RoutineIndex,
231 IN PVOID Argument,
232 IN ULONG ArgumentLength,
235{
236 ULONG_PTR OldStack;
237 PUCHAR UserArguments;
238 PUCALLOUT_FRAME CalloutFrame;
239 PULONG_PTR UserStackPointer;
241#ifdef _M_IX86
242 PEXCEPTION_REGISTRATION_RECORD ExceptionList;
243#endif // _M_IX86
244 PTEB Teb;
245 ULONG GdiBatchCount = 0;
246 ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
248
249 /* Get the current user-mode stack */
250 UserStackPointer = KiGetUserModeStackAddress();
251 OldStack = *UserStackPointer;
252
253 /* Enter a SEH Block */
255 {
256 /* Calculate and align the stack. This is unaligned by 8 bytes, since the following
257 UCALLOUT_FRAME compensates for that and on entry we already have a full stack
258 frame with home space for the next call, i.e. we are already inside the function
259 body and the stack needs to be 16 byte aligned. */
260 UserArguments = (PUCHAR)ALIGN_DOWN_POINTER_BY(OldStack - ArgumentLength, 16) - 8;
261
262 /* The callout frame is below the arguments */
263 CalloutFrame = ((PUCALLOUT_FRAME)UserArguments) - 1;
264
265 /* Make sure it's all writable */
266 ProbeForWrite(CalloutFrame,
267 sizeof(PUCALLOUT_FRAME) + ArgumentLength,
268 sizeof(PVOID));
269
270 /* Copy the buffer into the stack */
271 RtlCopyMemory(UserArguments, Argument, ArgumentLength);
272
273 /* Write the arguments */
274 KiSetupUserCalloutFrame(CalloutFrame,
275 KeGetCurrentThread()->TrapFrame,
276 RoutineIndex,
277 UserArguments,
278 ArgumentLength);
279
280 /* Save the exception list */
281 Teb = KeGetCurrentThread()->Teb;
282#ifdef _M_IX86
283 ExceptionList = Teb->NtTib.ExceptionList;
284#endif // _M_IX86
285
286 /* Jump to user mode */
287 *UserStackPointer = (ULONG_PTR)CalloutFrame;
290 {
291#ifdef _M_IX86
292 /* Only restore the exception list if we didn't crash in ring 3 */
293 Teb->NtTib.ExceptionList = ExceptionList;
294#endif // _M_IX86
295 }
296 else
297 {
298 /* Otherwise, pop the stack */
299 OldStack = *UserStackPointer;
300 }
301
302 /* Read the GDI Batch count */
303 GdiBatchCount = Teb->GdiBatchCount;
304 }
306 {
307 /* Get the SEH exception */
309 }
310 _SEH2_END;
311
312 /* Check if we have GDI Batch operations */
313 if (GdiBatchCount)
314 {
315 *UserStackPointer -= 256;
317 }
318
319 /* Restore stack and return */
320 *UserStackPointer = OldStack;
321#ifdef _M_AMD64 // could probably move the update to TrapFrame->Rsp from the C handler to the asm code
322 __writegsqword(FIELD_OFFSET(KIPCR, UserRsp), OldStack);
323#endif
324 return CallbackStatus;
325}
326
328NTAPI
333{
334 PKTHREAD CurrentThread;
335 PKCALLOUT_FRAME CalloutFrame;
336 PKTRAP_FRAME CallbackTrapFrame, TrapFrame;
337 PKIPCR Pcr;
338
339 /* Get the current thread and make sure we have a callback stack */
340 CurrentThread = KeGetCurrentThread();
341 CalloutFrame = CurrentThread->CallbackStack;
342 if (CalloutFrame == NULL)
343 {
345 }
346
347 /* Store the results in the callback stack */
348 *((PVOID*)CalloutFrame->OutputBuffer) = Result;
349 *((ULONG*)CalloutFrame->OutputLength) = ResultLength;
350
351 /* Get the trap frame */
352 CallbackTrapFrame = CurrentThread->TrapFrame;
353
354 /* Disable interrupts for NPX save and stack switch */
355 _disable();
356
357 /* Restore the exception list */
358 Pcr = (PKIPCR)KeGetPcr();
359
360 /* Get the previous trap frame */
361 TrapFrame = (PKTRAP_FRAME)CalloutFrame->TrapFrame;
362
363 /* Check if we failed in user mode */
365 {
366 *TrapFrame = *CallbackTrapFrame;
367 }
368
369 /* Clear DR7 */
370 TrapFrame->Dr7 = 0;
371
372 /* Check if debugging was active */
373 if (CurrentThread->Header.DebugActive & 0xFF)
374 {
375 /* Copy debug registers data from it */
376 TrapFrame->Dr0 = CallbackTrapFrame->Dr0;
377 TrapFrame->Dr1 = CallbackTrapFrame->Dr1;
378 TrapFrame->Dr2 = CallbackTrapFrame->Dr2;
379 TrapFrame->Dr3 = CallbackTrapFrame->Dr3;
380 TrapFrame->Dr6 = CallbackTrapFrame->Dr6;
381 TrapFrame->Dr7 = CallbackTrapFrame->Dr7;
382 }
383
384 /* Switch the stack back to the previous value */
385 Pcr->TssBase->Rsp0 = CalloutFrame->InitialStack;
386 Pcr->Prcb.RspBase = CalloutFrame->InitialStack;
387
388 /* Get the initial stack and restore it */
389 CurrentThread->InitialStack = (PVOID)CalloutFrame->InitialStack;
390
391 /* Restore the trap frame and the previous callback stack */
392 CurrentThread->TrapFrame = TrapFrame;
393 CurrentThread->CallbackStack = (PVOID)CalloutFrame->CallbackStack;
394
395 /* Bring interrupts back */
396 _enable();
397
398 /* Now switch back to the old stack */
399 KiCallbackReturn(CalloutFrame, CallbackStatus);
400}
401
#define EFLAGS_INTERRUPT_MASK
Definition: SystemCall.c:11
NTSTATUS FASTCALL KiUserModeCallout(_Out_ PKCALLOUT_FRAME CalloutFrame)
Definition: usercall.c:135
NTSTATUS NTAPI KeUserModeCallback(IN ULONG RoutineIndex, IN PVOID Argument, IN ULONG ArgumentLength, OUT PVOID *Result, OUT PULONG ResultLength)
Definition: usercall.c:229
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:204
NTSTATUS NTAPI NtCallbackReturn(_In_ PVOID Result, _In_ ULONG ResultLength, _In_ NTSTATUS CallbackStatus)
Definition: usercall.c:329
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:32
CONTEXT * PCONTEXT
Definition: compat.h:699
#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
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
_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:85
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 _Inout_
Definition: ms_sal.h:378
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define KernelMode
Definition: asm.h:34
#define UserMode
Definition: asm.h:35
#define EFLAGS_USER_SANITIZE
Definition: ketypes.h:198
#define KGDT64_R3_CODE
Definition: ketypes.h:137
#define KGDT64_R3_DATA
Definition: ketypes.h:136
struct _UCALLOUT_FRAME * PUCALLOUT_FRAME
struct _KIPCR * PKIPCR
#define KGDT64_R3_CMTEB
Definition: ketypes.h:139
struct _KTRAP_FRAME * PKTRAP_FRAME
#define RPL_MASK
Definition: ketypes.h:130
#define KeGetPreviousMode()
Definition: ketypes.h:1115
#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 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:466
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:142
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:141
NTSTATUS NTAPI MmGrowKernelStack(IN PVOID StackPointer)
Definition: procsup.c:476
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1765
#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:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:158
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define KERNEL_STACK_SIZE
BOOLEAN DebugActive
Definition: ketypes.h:793
PVOID ExceptionAddress
Definition: compat.h:211
ULONG64 OutputBuffer
Definition: ketypes.h:1023
ULONG64 OutputLength
Definition: ketypes.h:1024
ULONG64 TrapFrame
Definition: ketypes.h:1019
KPRCB Prcb
Definition: ketypes.h:961
struct _KTSS64 * TssBase
Definition: ketypes.h:933
UINT64 RspBase
Definition: ketypes.h:645
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 Dr6
Definition: ketypes.h:416
UINT64 Dr0
Definition: ketypes.h:412
UINT64 Dr7
Definition: ketypes.h:417
UINT64 Dr1
Definition: ketypes.h:413
UINT64 Dr3
Definition: ketypes.h:415
UINT64 Rip
Definition: ketypes.h:449
UINT64 TrapFrame
Definition: ketypes.h:438
UINT64 Dr2
Definition: ketypes.h:414
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
uint32_t * PULONG_PTR
Definition: typedefs.h:65
uint32_t * PULONG
Definition: typedefs.h:59
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#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