ReactOS 0.4.15-dev-7918-g2a2556c
usercall.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for usercall.c:

Go to the source code of this file.

Macros

#define NDEBUG
 

Functions

KiInitializeUserApc

Prepares the current trap frame (which must have come from user mode) with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT record with the context from the old trap frame to the threads user mode stack.

Parameters
ExceptionFrame- Pointer to the Exception Frame
TrapFramePointer to the Trap Frame.
NormalRoutine- Pointer to the NormalRoutine to call.
NormalContext- Pointer to the context to send to the Normal Routine.
SystemArgument[1-2]Pointer to a set of two parameters that contain untyped data.
Remarks
This function is called from KiDeliverApc, when the trap frame came from user mode. This happens before a systemcall or interrupt exits back to usermode or when a thread is started from PspUserThreadstartup. The trap exit code will then leave to KiUserApcDispatcher which in turn calls the NormalRoutine, passing NormalContext, SystemArgument1 and SystemArgument2 as parameters. When that function returns, it calls NtContinue to return back to the kernel, where the old context that was saved on the usermode stack is restored and execution is transferred back to usermode, where the original trap originated from.

VOID NTAPI KiInitializeUserApc (_In_ PKEXCEPTION_FRAME ExceptionFrame, _Inout_ PKTRAP_FRAME TrapFrame, _In_ PKNORMAL_ROUTINE NormalRoutine, _In_ PVOID NormalContext, _In_ PVOID SystemArgument1, _In_ PVOID SystemArgument2)
 
NTSTATUS FASTCALL KiUserModeCallout (_Out_ PKCALLOUT_FRAME CalloutFrame)
 
VOID KiSetupUserCalloutFrame (_Out_ PUCALLOUT_FRAME UserCalloutFrame, _In_ PKTRAP_FRAME TrapFrame, _In_ ULONG ApiNumber, _In_ PVOID Buffer, _In_ ULONG BufferLength)
 
NTSTATUS NTAPI KeUserModeCallback (IN ULONG RoutineIndex, IN PVOID Argument, IN ULONG ArgumentLength, OUT PVOID *Result, OUT PULONG ResultLength)
 
NTSTATUS NTAPI NtCallbackReturn (_In_ PVOID Result, _In_ ULONG ResultLength, _In_ NTSTATUS CallbackStatus)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 11 of file usercall.c.

Function Documentation

◆ KeUserModeCallback()

NTSTATUS NTAPI KeUserModeCallback ( IN ULONG  RoutineIndex,
IN PVOID  Argument,
IN ULONG  ArgumentLength,
OUT PVOID Result,
OUT PULONG  ResultLength 
)

Definition at line 229 of file usercall.c.

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}
VOID KiSetupUserCalloutFrame(_Out_ PUCALLOUT_FRAME UserCalloutFrame, _In_ PKTRAP_FRAME TrapFrame, _In_ ULONG ApiNumber, _In_ PVOID Buffer, _In_ ULONG BufferLength)
Definition: usercall.c:204
LONG NTSTATUS
Definition: precomp.h:26
#define FALSE
Definition: types.h:117
#define ULONG_PTR
Definition: config.h:101
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
#define KeGetCurrentThread
Definition: hal.h:55
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define ASSERT(a)
Definition: mode.c:44
#define UserMode
Definition: asm.h:35
struct _UCALLOUT_FRAME * PUCALLOUT_FRAME
#define KeGetPreviousMode()
Definition: ketypes.h:1115
FORCEINLINE PULONG_PTR KiGetUserModeStackAddress(void)
Definition: ke.h:466
PGDI_BATCHFLUSH_ROUTINE KeGdiFlushUserBatch
Definition: win32.c:20
NTSTATUS NTAPI KiCallUserMode(IN PVOID *OutputBuffer, IN PULONG OutputLength)
Definition: usercall.c:321
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1765
#define STATUS_CALLBACK_POP_STACK
Definition: ntstatus.h:961
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
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
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
uint32_t ULONG_PTR
Definition: typedefs.h:65
unsigned char * PUCHAR
Definition: typedefs.h:53
uint32_t ULONG
Definition: typedefs.h:59
#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
_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

Referenced by co_ClientImmLoadLayout(), co_IntCallEventProc(), co_IntCallHookProc(), co_IntCallLoadMenu(), co_IntCallSentMessageCallback(), co_IntCallWindowProc(), co_IntClientLoadLibrary(), co_IntClientThreadSetup(), co_IntCopyImage(), co_IntDeliverUserAPC(), co_IntGetCharsetInfo(), co_IntImmProcessKey(), co_IntLoadDefaultCursors(), co_IntLoadSysMenuTemplate(), co_IntSetupOBM(), co_IntSetWndIcons(), co_UserCBClientPrinterThunk(), IntDDEGetCallback(), and IntDDEPostCallback().

◆ KiInitializeUserApc()

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 at line 48 of file usercall.c.

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}
#define EFLAGS_INTERRUPT_MASK
Definition: SystemCall.c:11
#define MODE_MASK
Definition: orders.h:326
#define TRUE
Definition: types.h:120
CONTEXT * PCONTEXT
Definition: compat.h:699
unsigned __int64 ULONG64
Definition: imports.h:198
#define KernelMode
Definition: asm.h:34
#define EFLAGS_USER_SANITIZE
Definition: ketypes.h:198
#define KGDT64_R3_CODE
Definition: ketypes.h:137
#define KGDT64_R3_DATA
Definition: ketypes.h:136
#define KGDT64_R3_CMTEB
Definition: ketypes.h:139
#define RPL_MASK
Definition: ketypes.h:130
#define CONTEXT_DEBUG_REGISTERS
Definition: nt_native.h:1373
#define CONTEXT_FULL
Definition: nt_native.h:1375
VOID NTAPI KeTrapFrameToContext(IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame, IN OUT PCONTEXT Context)
Definition: context.c:169
VOID NTAPI KiDispatchException(PEXCEPTION_RECORD ExceptionRecord, PKEXCEPTION_FRAME ExceptionFrame, PKTRAP_FRAME Tf, KPROCESSOR_MODE PreviousMode, BOOLEAN SearchFrames)
PVOID KeUserApcDispatcher
Definition: ke.h:141
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:158
PVOID ExceptionAddress
Definition: compat.h:211
void * PVOID
Definition: typedefs.h:50
_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

◆ KiSetupUserCalloutFrame()

VOID KiSetupUserCalloutFrame ( _Out_ PUCALLOUT_FRAME  UserCalloutFrame,
_In_ PKTRAP_FRAME  TrapFrame,
_In_ ULONG  ApiNumber,
_In_ PVOID  Buffer,
_In_ ULONG  BufferLength 
)

Definition at line 204 of file usercall.c.

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}
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771

Referenced by KeUserModeCallback().

◆ KiUserModeCallout()

NTSTATUS FASTCALL KiUserModeCallout ( _Out_ PKCALLOUT_FRAME  CalloutFrame)

Definition at line 135 of file usercall.c.

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}
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
Status
Definition: gdiplustypes.h:25
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
struct _KIPCR * PKIPCR
#define KeGetPcr()
Definition: ketypes.h:81
@ OriginalApcEnvironment
Definition: ketypes.h:767
DECLSPEC_NORETURN VOID KiUserCallbackExit(_In_ PKTRAP_FRAME TrapFrame)
PVOID KeUserCallbackDispatcher
Definition: ke.h:142
NTSTATUS NTAPI MmGrowKernelStack(IN PVOID StackPointer)
Definition: procsup.c:476
#define KERNEL_STACK_SIZE
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
volatile VOID * StackLimit
Definition: ketypes.h:1665
UINT64 Rip
Definition: ketypes.h:449
UINT64 TrapFrame
Definition: ketypes.h:438

◆ NtCallbackReturn()

NTSTATUS NTAPI NtCallbackReturn ( _In_ PVOID  Result,
_In_ ULONG  ResultLength,
_In_ NTSTATUS  CallbackStatus 
)

Definition at line 329 of file usercall.c.

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}
#define NULL
Definition: types.h:112
if(dx< 0)
Definition: linetemp.h:194
struct _KTRAP_FRAME * PKTRAP_FRAME
DECLSPEC_NORETURN VOID FASTCALL KiCallbackReturn(IN PVOID Stack, IN NTSTATUS Status)
#define STATUS_NO_CALLBACK_ACTIVE
Definition: ntstatus.h:726
BOOLEAN DebugActive
Definition: ketypes.h:793
ULONG64 OutputBuffer
Definition: ketypes.h:1023
ULONG64 OutputLength
Definition: ketypes.h:1024
ULONG64 TrapFrame
Definition: ketypes.h:1019
DISPATCHER_HEADER Header
Definition: ketypes.h:1661
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 Dr2
Definition: ketypes.h:414

Referenced by KiCallbackReturnHandler(), and VectoredExceptionHandlerForUserModeCallback().