170 lines
4.6 KiB
C
170 lines
4.6 KiB
C
/*++
|
||
|
||
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 writability and then transfer the
|
||
// context record to the user stack.
|
||
//
|
||
|
||
ProbeForWrite((PCHAR)UserStack, Length, CONTEXT_ALIGN);
|
||
RtlCopyMemory((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 transferred
|
||
// 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;
|
||
}
|
||
|