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;
|
|||
|
}
|
|||
|
|