diff options
Diffstat (limited to 'private/ntos/ke/i386/apcuser.c')
-rw-r--r-- | private/ntos/ke/i386/apcuser.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/private/ntos/ke/i386/apcuser.c b/private/ntos/ke/i386/apcuser.c new file mode 100644 index 000000000..14d327ec0 --- /dev/null +++ b/private/ntos/ke/i386/apcuser.c @@ -0,0 +1,169 @@ +/*++ + +Copyright (c) 1990 Microsoft Corporation + +Module Name: + + apcuser.c + +Abstract: + + This module implements the machine dependent code necessary to initialize + a user mode APC. + +Author: + + David N. Cutler (davec) 23-Apr-1990 + +Environment: + + Kernel mode only, IRQL APC_LEVEL. + +Revision History: + +--*/ + +#include "ki.h" + +VOID +KiInitializeUserApc ( + IN PKEXCEPTION_FRAME ExceptionFrame, + IN PKTRAP_FRAME TrapFrame, + IN PKNORMAL_ROUTINE NormalRoutine, + IN PVOID NormalContext, + IN PVOID SystemArgument1, + IN PVOID SystemArgument2 + ) + +/*++ + +Routine Description: + + This function is called to initialize the context for a user mode APC. + +Arguments: + + ExceptionFrame - Supplies a pointer to an exception frame. + + TrapFrame - Supplies a pointer to a trap frame. + + NormalRoutine - Supplies a pointer to the user mode APC routine. + + NormalContext - Supplies a pointer to the user context for the APC + routine. + + SystemArgument1 - Supplies the first system supplied value. + + SystemArgument2 - Supplies the second system supplied value. + +Return Value: + + None. + +--*/ + +{ + + EXCEPTION_RECORD ExceptionRecord; + CONTEXT ContextFrame; + LONG Length; + ULONG UserStack; + + + // + // APCs are not defined for V86 mode; however, it is possible a + // thread is trying to set it's context to V86 mode - this isn't + // going to work, but we don't want to crash the system so we + // check for the possibility before hand. + // + + if (TrapFrame->EFlags & EFLAGS_V86_MASK) { + return ; + } + + // + // Move machine state from trap and exception frames to the context frame. + // + + ContextFrame.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS; + KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame); + + // + // Transfer the context information to the user stack, initialize the + // APC routine parameters, and modify the trap frame so execution will + // continue in user mode at the user mode APC dispatch routine. + // + + + try { + ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode); // Assert usermode frame + + // + // Compute length of context record and new aligned user stack pointer. + // + + Length = ((sizeof(CONTEXT) + CONTEXT_ROUND) & + ~CONTEXT_ROUND) + sizeof(KAPC_RECORD); + UserStack = (ContextFrame.Esp & ~CONTEXT_ROUND) - Length; + + // + // Probe user stack area for writeability and then transfer the + // context record to the user stack. + // + + ProbeForWrite((PCHAR)UserStack, Length, CONTEXT_ALIGN); + RtlMoveMemory((PULONG)(UserStack + (sizeof(KAPC_RECORD))), + &ContextFrame, sizeof(CONTEXT)); + + // + // Force correct R3 selectors into TrapFrame. + // + + TrapFrame->SegCs = SANITIZE_SEG(KGDT_R3_CODE, UserMode); + TrapFrame->HardwareSegSs = SANITIZE_SEG(KGDT_R3_DATA, UserMode); + TrapFrame->SegDs = SANITIZE_SEG(KGDT_R3_DATA, UserMode); + TrapFrame->SegEs = SANITIZE_SEG(KGDT_R3_DATA, UserMode); + TrapFrame->SegFs = SANITIZE_SEG(KGDT_R3_TEB, UserMode); + TrapFrame->SegGs = 0; + TrapFrame->EFlags = SANITIZE_FLAGS( ContextFrame.EFlags, UserMode ); + + // + // If thread is supposed to have IOPL, then force it on in eflags + // + + if (KeGetCurrentThread()->Iopl) { + TrapFrame->EFlags |= (EFLAGS_IOPL_MASK & -1); // IOPL = 3 + } + + // + // Set the address of the user APC routine, the APC parameters, the + // new frame pointer, and the new stack pointer in the current trap + // frame. Set the continuation address so control will be transfered + // to the user APC dispatcher. + // + + TrapFrame->HardwareEsp = UserStack; + TrapFrame->Eip = (ULONG)KeUserApcDispatcher; + TrapFrame->ErrCode = 0; + *((PULONG)UserStack)++ = (ULONG)NormalRoutine; + *((PULONG)UserStack)++ = (ULONG)NormalContext; + *((PULONG)UserStack)++ = (ULONG)SystemArgument1; + *((PULONG)UserStack)++ = (ULONG)SystemArgument2; + } except (KiCopyInformation(&ExceptionRecord, + (GetExceptionInformation())->ExceptionRecord)) { + + // + // Set the address of the exception to the current program address + // and raise the exception by calling the exception dispatcher. + // + + ExceptionRecord.ExceptionAddress = (PVOID)(TrapFrame->Eip); + KiDispatchException(&ExceptionRecord, + ExceptionFrame, + TrapFrame, + UserMode, + TRUE); + } + return; +} + |