reactos/ntoskrnl/ke/amd64/usercall.c

115 lines
4 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - 2.0 + (https ://spdx.org/licenses/GPL-2.0+)
* PURPOSE: AMD64 User-mode Callout Mechanisms (APC and Win32K Callbacks)
* COPYRIGHT: Timo Kreuzer(timo.kreuzer@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/*! \name KiInitializeUserApc
*
* \brief
* 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.
*
* \param ExceptionFrame
* \param TrapFrame
* \param NormalRoutine
* \param NormalContext
* \param SystemArgument1
* \param SystemArgument2
*
* \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)
{
CONTEXT Context;
ULONG64 AlignedRsp, Stack;
EXCEPTION_RECORD SehExceptRecord;
/* Sanity check, that the trap frame is from user mode */
ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
/* Convert the current trap frame to a context */
Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
/* We jump to KiUserApcDispatcher in ntdll */
TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
/* Setup Ring 3 segments */
TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
/* Sanitize EFLAGS, enable interrupts */
TrapFrame->EFlags = (Context.EFlags & EFLAGS_USER_SANITIZE);
TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
/* Set parameters for KiUserApcDispatcher */
Context.P1Home = (ULONG64)NormalContext;
Context.P2Home = (ULONG64)SystemArgument1;
Context.P3Home = (ULONG64)SystemArgument2;
Context.P4Home = (ULONG64)NormalRoutine;
/* Check if thread has IOPL and force it enabled if so */
//if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
/* Align Stack to 16 bytes and allocate space */
AlignedRsp = Context.Rsp & ~15;
Stack = AlignedRsp - sizeof(CONTEXT);
TrapFrame->Rsp = Stack;
/* The stack must be 16 byte aligned for KiUserApcDispatcher */
ASSERT((Stack & 15) == 0);
/* Protect with SEH */
_SEH2_TRY
{
/* Probe the stack */
ProbeForWrite((PCONTEXT)Stack, sizeof(CONTEXT), 8);
/* Copy the context */
RtlCopyMemory((PCONTEXT)Stack, &Context, sizeof(CONTEXT));
}
_SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
{
/* Dispatch the exception */
SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
KiDispatchException(&SehExceptRecord,
ExceptionFrame,
TrapFrame,
UserMode,
TRUE);
}
_SEH2_END;
}