ReactOS 0.4.16-dev-1025-gd3456f5
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 UAPC_FRAME structure 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 235 of file usercall.c.

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}
VOID KiSetupUserCalloutFrame(_Out_ PUCALLOUT_FRAME UserCalloutFrame, _In_ PKTRAP_FRAME TrapFrame, _In_ ULONG ApiNumber, _In_ PVOID Buffer, _In_ ULONG BufferLength)
Definition: usercall.c:210
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
_In_ FLT_PREOP_CALLBACK_STATUS CallbackStatus
Definition: fltkernel.h:1020
#define KeGetCurrentThread
Definition: hal.h:55
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define ASSERT(a)
Definition: mode.c:44
struct _UCALLOUT_FRAME * PUCALLOUT_FRAME
#define KeGetPreviousMode()
Definition: ketypes.h:1115
#define UserMode
Definition: asm.h:39
FORCEINLINE PULONG_PTR KiGetUserModeStackAddress(void)
Definition: ke.h:469
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:1761
#define STATUS_CALLBACK_POP_STACK
Definition: ntstatus.h:961
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#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
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 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{
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}
#define EFLAGS_INTERRUPT_MASK
Definition: SystemCall.c:11
#define MODE_MASK
Definition: orders.h:326
#define TRUE
Definition: types.h:120
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
#define KGDT64_R3_CMTEB
Definition: ketypes.h:128
struct _UAPC_FRAME * PUAPC_FRAME
#define RPL_MASK
Definition: ketypes.h:119
#define KernelMode
Definition: asm.h:38
#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:146
#define _SEH2_GetExceptionInformation()
Definition: pseh2_64.h:180
PVOID ExceptionAddress
Definition: compat.h:211
ULONG64 Rsp
Definition: ketypes.h:1074
ULONG64 Rip
Definition: ketypes.h:1069
MACHINE_FRAME MachineFrame
Definition: ketypes.h:1105
CONTEXT Context
Definition: ketypes.h:1104
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 210 of file usercall.c.

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}
_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 141 of file usercall.c.

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}
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#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:147
NTSTATUS NTAPI MmGrowKernelStack(IN PVOID StackPointer)
Definition: procsup.c:477
#define KERNEL_STACK_SIZE
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
volatile VOID * StackLimit
Definition: ketypes.h:1665
UINT64 Rip
Definition: ketypes.h:473
UINT64 TrapFrame
Definition: ketypes.h:462

◆ NtCallbackReturn()

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

Definition at line 332 of file usercall.c.

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}
#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:1050
ULONG64 OutputLength
Definition: ketypes.h:1051
ULONG64 TrapFrame
Definition: ketypes.h:1046
DISPATCHER_HEADER Header
Definition: ketypes.h:1661
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 Dr2
Definition: ketypes.h:438

Referenced by KiCallbackReturnHandler(), and VectoredExceptionHandlerForUserModeCallback().