ReactOS 0.4.17-dev-683-g0dafdc5
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 /* Initialize EFLAGS */
112 TrapFrame->EFlags = EFLAGS_INTERRUPT_MASK;
113}
114
115/*
116 * Stack layout for KiUserModeCallout:
117 * ----------------------------------
118 * KCALLOUT_FRAME.ResultLength <= 2nd Parameter to KiCallUserMode
119 * KCALLOUT_FRAME.Result <= 1st Parameter to KiCallUserMode
120 * KCALLOUT_FRAME.ReturnAddress <= Return address of KiCallUserMode
121 * KCALLOUT_FRAME.Ebp \
122 * KCALLOUT_FRAME.Ebx | = non-volatile registers, pushed
123 * KCALLOUT_FRAME.Esi | by KiCallUserMode
124 * KCALLOUT_FRAME.Edi /
125 * KCALLOUT_FRAME.CallbackStack
126 * KCALLOUT_FRAME.TrapFrame
127 * KCALLOUT_FRAME.InitialStack <= CalloutFrame points here
128 * ----------------------------------
129 * ~~ optional alignment ~~
130 * ----------------------------------
131 * FX_SAVE_AREA
132 * ----------------------------------
133 * KTRAP_FRAME
134 * ----------------------------------
135 * ~~ begin of stack frame for KiUserModeCallout ~~
136 *
137 */
141 _Out_ PKCALLOUT_FRAME CalloutFrame)
142{
143 PKTHREAD CurrentThread;
144 PKTRAP_FRAME TrapFrame;
145 KTRAP_FRAME CallbackTrapFrame;
146 PKIPCR Pcr;
147 ULONG_PTR InitialStack;
149
150 /* Get the current thread */
151 CurrentThread = KeGetCurrentThread();
152
153 /* Check if we are at pasive level */
155
156 /* Check if we are attached or APCs are disabled */
157 ASSERT((CurrentThread->ApcStateIndex == OriginalApcEnvironment) &&
158 (CurrentThread->CombinedApcDisable == 0));
159
160 /* Align stack on a 16-byte boundary */
161 InitialStack = (ULONG_PTR)ALIGN_DOWN_POINTER_BY(CalloutFrame, 16);
162
163 /* Check if we have enough space on the stack */
164 if ((InitialStack - KERNEL_STACK_SIZE) < CurrentThread->StackLimit)
165 {
166 /* We don't, we'll have to grow our stack */
167 Status = MmGrowKernelStack((PVOID)InitialStack);
168
169 /* Quit if we failed */
170 if (!NT_SUCCESS(Status)) return Status;
171 }
172
173 /* Save the current callback stack and initial stack */
174 CalloutFrame->CallbackStack = (ULONG_PTR)CurrentThread->CallbackStack;
175 CalloutFrame->InitialStack = (ULONG_PTR)CurrentThread->InitialStack;
176
177 /* Get and save the trap frame */
178 TrapFrame = CurrentThread->TrapFrame;
179 CalloutFrame->TrapFrame = (ULONG_PTR)TrapFrame;
180
181 /* Set the new callback stack */
182 CurrentThread->CallbackStack = CalloutFrame;
183
184 /* Disable interrupts so we can fill the NPX State */
185 _disable();
186
187 /* Set the stack address */
188 CurrentThread->InitialStack = (PVOID)InitialStack;
189
190 /* Copy the trap frame to the new location */
191 CallbackTrapFrame = *TrapFrame;
192
193 /* Get PCR */
194 Pcr = (PKIPCR)KeGetPcr();
195
196 /* Set user-mode dispatcher address as EIP */
197 Pcr->TssBase->Rsp0 = InitialStack;
198 Pcr->Prcb.RspBase = InitialStack;
199 CallbackTrapFrame.Rip = (ULONG_PTR)KeUserCallbackDispatcher;
200
201 /* Bring interrupts back */
202 _enable();
203
204 /* Exit to user-mode */
205 KiUserCallbackExit(&CallbackTrapFrame);
206}
207
208VOID
210 _Out_ PUCALLOUT_FRAME UserCalloutFrame,
211 _In_ PKTRAP_FRAME TrapFrame,
212 _In_ ULONG ApiNumber,
215{
216#ifdef _M_IX86
217 CalloutFrame->Reserved = 0;
218 CalloutFrame->ApiNumber = ApiNumber;
219 CalloutFrame->Buffer = (ULONG_PTR)NewStack;
220 CalloutFrame->Length = ArgumentLength;
221#elif defined(_M_AMD64)
222 UserCalloutFrame->Buffer = (PVOID)(UserCalloutFrame + 1);
223 UserCalloutFrame->Length = BufferLength;
224 UserCalloutFrame->ApiNumber = ApiNumber;
225 UserCalloutFrame->MachineFrame.Rip = TrapFrame->Rip;
226 UserCalloutFrame->MachineFrame.Rsp = TrapFrame->Rsp;
227#else
228#error "KiSetupUserCalloutFrame not implemented!"
229#endif
230}
231
233NTAPI
235 IN ULONG RoutineIndex,
236 IN PVOID Argument,
237 IN ULONG ArgumentLength,
240{
241 ULONG_PTR OldStack;
242 PUCHAR UserArguments;
243 PUCALLOUT_FRAME CalloutFrame;
244 PULONG_PTR UserStackPointer;
246#ifdef _M_IX86
247 PEXCEPTION_REGISTRATION_RECORD ExceptionList;
248#endif // _M_IX86
249 PTEB Teb;
250 ULONG GdiBatchCount = 0;
251 ASSERT(KeGetCurrentThread()->ApcState.KernelApcInProgress == FALSE);
253
254 /* Get the current user-mode stack */
255 UserStackPointer = KiGetUserModeStackAddress();
256 OldStack = *UserStackPointer;
257
258 /* Enter a SEH Block */
260 {
261 /* Calculate and align the stack. This is unaligned by 8 bytes, since the following
262 UCALLOUT_FRAME compensates for that and on entry we already have a full stack
263 frame with home space for the next call, i.e. we are already inside the function
264 body and the stack needs to be 16 byte aligned. */
265 UserArguments = (PUCHAR)ALIGN_DOWN_POINTER_BY(OldStack - ArgumentLength, 16) - 8;
266
267 /* The callout frame is below the arguments */
268 CalloutFrame = ((PUCALLOUT_FRAME)UserArguments) - 1;
269
270 /* Make sure it's all writable */
271 ProbeForWrite(CalloutFrame,
272 sizeof(PUCALLOUT_FRAME) + ArgumentLength,
273 sizeof(PVOID));
274
275 /* Copy the buffer into the stack */
276 RtlCopyMemory(UserArguments, Argument, ArgumentLength);
277
278 /* Write the arguments */
279 KiSetupUserCalloutFrame(CalloutFrame,
280 KeGetCurrentThread()->TrapFrame,
281 RoutineIndex,
282 UserArguments,
283 ArgumentLength);
284
285 /* Save the exception list */
286 Teb = KeGetCurrentThread()->Teb;
287#ifdef _M_IX86
288 ExceptionList = Teb->NtTib.ExceptionList;
289#endif // _M_IX86
290
291 /* Jump to user mode */
292 *UserStackPointer = (ULONG_PTR)CalloutFrame;
295 {
296#ifdef _M_IX86
297 /* Only restore the exception list if we didn't crash in ring 3 */
298 Teb->NtTib.ExceptionList = ExceptionList;
299#endif // _M_IX86
300 }
301 else
302 {
303 /* Otherwise, pop the stack */
304 OldStack = *UserStackPointer;
305 }
306
307 /* Read the GDI Batch count */
308 GdiBatchCount = Teb->GdiBatchCount;
309 }
311 {
312 /* Get the SEH exception */
314 }
315 _SEH2_END;
316
317 /* Check if we have GDI Batch operations */
318 if (GdiBatchCount)
319 {
320 *UserStackPointer -= 256;
322 }
323
324 /* Restore stack and return */
325 *UserStackPointer = OldStack;
326 return CallbackStatus;
327}
328
330NTAPI
335{
336 PKTHREAD CurrentThread;
337 PKCALLOUT_FRAME CalloutFrame;
338 PKTRAP_FRAME CallbackTrapFrame, TrapFrame;
339 PKIPCR Pcr;
340
341 /* Get the current thread and make sure we have a callback stack */
342 CurrentThread = KeGetCurrentThread();
343 CalloutFrame = CurrentThread->CallbackStack;
344 if (CalloutFrame == NULL)
345 {
347 }
348
349 /* Store the results in the callback stack */
350 *((PVOID*)CalloutFrame->OutputBuffer) = Result;
351 *((ULONG*)CalloutFrame->OutputLength) = ResultLength;
352
353 /* Get the trap frame */
354 CallbackTrapFrame = CurrentThread->TrapFrame;
355
356 /* Disable interrupts for NPX save and stack switch */
357 _disable();
358
359 /* Restore the exception list */
360 Pcr = (PKIPCR)KeGetPcr();
361
362 /* Get the previous trap frame */
363 TrapFrame = (PKTRAP_FRAME)CalloutFrame->TrapFrame;
364
365 /* Check if we failed in user mode */
367 {
368 *TrapFrame = *CallbackTrapFrame;
369 }
370
371 /* Clear DR7 */
372 TrapFrame->Dr7 = 0;
373
374 /* Check if debugging was active */
375 if (CurrentThread->Header.DebugActive & 0xFF)
376 {
377 /* Copy debug registers data from it */
378 TrapFrame->Dr0 = CallbackTrapFrame->Dr0;
379 TrapFrame->Dr1 = CallbackTrapFrame->Dr1;
380 TrapFrame->Dr2 = CallbackTrapFrame->Dr2;
381 TrapFrame->Dr3 = CallbackTrapFrame->Dr3;
382 TrapFrame->Dr6 = CallbackTrapFrame->Dr6;
383 TrapFrame->Dr7 = CallbackTrapFrame->Dr7;
384 }
385
386 /* Switch the stack back to the previous value */
387 Pcr->TssBase->Rsp0 = CalloutFrame->InitialStack;
388 Pcr->Prcb.RspBase = CalloutFrame->InitialStack;
389
390 /* Get the initial stack and restore it */
391 CurrentThread->InitialStack = (PVOID)CalloutFrame->InitialStack;
392
393 /* Restore the trap frame and the previous callback stack */
394 CurrentThread->TrapFrame = TrapFrame;
395 CurrentThread->CallbackStack = (PVOID)CalloutFrame->CallbackStack;
396
397 /* Bring interrupts back */
398 _enable();
399
400 /* Now switch back to the old stack */
401 KiCallbackReturn(CalloutFrame, CallbackStatus);
402}
403
#define EFLAGS_INTERRUPT_MASK
#define KGDT64_R3_CODE
#define KGDT64_R3_DATA
#define KGDT64_R3_CMTEB
#define RPL_MASK
NTSTATUS FASTCALL KiUserModeCallout(_Out_ PKCALLOUT_FRAME CalloutFrame)
Definition: usercall.c:140
NTSTATUS NTAPI KeUserModeCallback(IN ULONG RoutineIndex, IN PVOID Argument, IN ULONG ArgumentLength, OUT PVOID *Result, OUT PULONG ResultLength)
Definition: usercall.c:234
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:209
NTSTATUS NTAPI NtCallbackReturn(_In_ PVOID Result, _In_ ULONG ResultLength, _In_ NTSTATUS CallbackStatus)
Definition: usercall.c:331
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:24
#define KeGetCurrentThread
Definition: hal.h:55
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
if(dx< 0)
Definition: linetemp.h:194
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 ULONG64
Definition: imports.h:198
struct _UCALLOUT_FRAME * PUCALLOUT_FRAME
struct _KIPCR * PKIPCR
struct _UAPC_FRAME * PUAPC_FRAME
struct _KTRAP_FRAME * PKTRAP_FRAME
#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:911
VOID(NTAPI * PKNORMAL_ROUTINE)(IN PVOID NormalContext OPTIONAL, IN PVOID SystemArgument1 OPTIONAL, IN PVOID SystemArgument2 OPTIONAL)
Definition: ketypes.h:888
#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:1376
#define FASTCALL
Definition: nt_native.h:50
#define CONTEXT_FULL
Definition: nt_native.h:1378
DECLSPEC_NORETURN VOID KiUserCallbackExit(_In_ PKTRAP_FRAME TrapFrame)
FORCEINLINE PULONG_PTR KiGetUserModeStackAddress(void)
Definition: ke.h:479
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:533
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1769
#define STATUS_CALLBACK_POP_STACK
Definition: ntstatus.h:1101
#define STATUS_NO_CALLBACK_ACTIVE
Definition: ntstatus.h:848
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:204
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:203
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:207
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
#define KERNEL_STACK_SIZE
_In_ PVOID Context
Definition: storport.h:2269
BOOLEAN DebugActive
Definition: ketypes.h:861
PVOID ExceptionAddress
Definition: compat.h:211
ULONG64 OutputBuffer
Definition: ketypes.h:1065
ULONG64 OutputLength
Definition: ketypes.h:1066
ULONG64 TrapFrame
Definition: ketypes.h:1061
KPRCB Prcb
Definition: ketypes.h:1003
struct _KTSS64 * TssBase
Definition: ketypes.h:975
UINT64 RspBase
Definition: ketypes.h:680
PKTRAP_FRAME TrapFrame
Definition: ketypes.h:1921
PVOID InitialStack
Definition: ketypes.h:1811
ULONG CombinedApcDisable
Definition: ketypes.h:2030
UCHAR ApcStateIndex
Definition: ketypes.h:2089
DISPATCHER_HEADER Header
Definition: ketypes.h:1808
volatile VOID * StackLimit
Definition: ketypes.h:1812
UINT64 Dr0
Definition: ketypes.h:447
UINT64 Dr6
Definition: ketypes.h:451
UINT64 Dr3
Definition: ketypes.h:450
UINT64 Dr7
Definition: ketypes.h:452
UINT64 Dr1
Definition: ketypes.h:448
UINT64 Rip
Definition: ketypes.h:484
UINT64 TrapFrame
Definition: ketypes.h:473
UINT64 Dr2
Definition: ketypes.h:449
ULONG64 Rsp
Definition: ketypes.h:1089
ULONG64 Rip
Definition: ketypes.h:1084
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:1120
CONTEXT Context
Definition: ketypes.h:1119
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:3782
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3777
_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:756
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:757