ReactOS 0.4.17-dev-684-ga6524ef
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 234 of file usercall.c.

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}
VOID KiSetupUserCalloutFrame(_Out_ PUCALLOUT_FRAME UserCalloutFrame, _In_ PKTRAP_FRAME TrapFrame, _In_ ULONG ApiNumber, _In_ PVOID Buffer, _In_ ULONG BufferLength)
Definition: usercall.c:209
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:479
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:1769
#define STATUS_CALLBACK_POP_STACK
Definition: ntstatus.h:1101
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:204
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#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
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:3782
_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 /* Initialize EFLAGS */
112 TrapFrame->EFlags = EFLAGS_INTERRUPT_MASK;
113}
#define EFLAGS_INTERRUPT_MASK
#define KGDT64_R3_CODE
#define KGDT64_R3_DATA
#define KGDT64_R3_CMTEB
#define RPL_MASK
#define MODE_MASK
Definition: orders.h:326
#define TRUE
Definition: types.h:120
unsigned __int64 ULONG64
Definition: imports.h:198
struct _UAPC_FRAME * PUAPC_FRAME
#define KernelMode
Definition: asm.h:38
#define CONTEXT_DEBUG_REGISTERS
Definition: nt_native.h:1376
#define CONTEXT_FULL
Definition: nt_native.h:1378
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:203
_In_ PVOID Context
Definition: storport.h:2269
PVOID ExceptionAddress
Definition: compat.h:211
ULONG64 Rsp
Definition: ketypes.h:1089
ULONG64 Rip
Definition: ketypes.h:1084
MACHINE_FRAME MachineFrame
Definition: ketypes.h:1120
CONTEXT Context
Definition: ketypes.h:1119
void * PVOID
Definition: typedefs.h:50
_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

◆ KiSetupUserCalloutFrame()

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

Definition at line 209 of file usercall.c.

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

Referenced by KeUserModeCallback().

◆ KiUserModeCallout()

NTSTATUS FASTCALL KiUserModeCallout ( _Out_ PKCALLOUT_FRAME  CalloutFrame)

Definition at line 140 of file usercall.c.

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}
#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:24
struct _KIPCR * PKIPCR
#define KeGetPcr()
Definition: ketypes.h:81
@ OriginalApcEnvironment
Definition: ketypes.h:911
DECLSPEC_NORETURN VOID KiUserCallbackExit(_In_ PKTRAP_FRAME TrapFrame)
PVOID KeUserCallbackDispatcher
Definition: ke.h:147
NTSTATUS NTAPI MmGrowKernelStack(IN PVOID StackPointer)
Definition: procsup.c:533
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
#define KERNEL_STACK_SIZE
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
volatile VOID * StackLimit
Definition: ketypes.h:1812
UINT64 Rip
Definition: ketypes.h:484
UINT64 TrapFrame
Definition: ketypes.h:473

◆ NtCallbackReturn()

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

Definition at line 331 of file usercall.c.

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}
#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:848
BOOLEAN DebugActive
Definition: ketypes.h:861
ULONG64 OutputBuffer
Definition: ketypes.h:1065
ULONG64 OutputLength
Definition: ketypes.h:1066
ULONG64 TrapFrame
Definition: ketypes.h:1061
DISPATCHER_HEADER Header
Definition: ketypes.h:1808
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 Dr2
Definition: ketypes.h:449

Referenced by KiCallbackReturnHandler(), test_user_callback(), and VectoredExceptionHandlerForUserModeCallback().