Windows-Server-2003/base/ntos/ke/amd64/apcuser.c

157 lines
4.1 KiB
C

/*++
Copyright (c) 2000 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) 5-May-2000
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.
--*/
{
CONTEXT ContextRecord;
EXCEPTION_RECORD ExceptionRecord;
PMACHINE_FRAME MachineFrame;
ULONG64 UserStack;
//
// Move machine state from trap and exception frames to the context frame.
//
ContextRecord.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextRecord);
//
// 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 {
//
// Compute address of aligned machine frame, compute address of
// context record, and probe user stack for writeability.
//
MachineFrame =
(PMACHINE_FRAME)((ContextRecord.Rsp - sizeof(MACHINE_FRAME)) & ~STACK_ROUND);
UserStack = (ULONG64)MachineFrame - CONTEXT_LENGTH;
ProbeForWriteSmallStructure((PVOID)UserStack,
sizeof(MACHINE_FRAME) + CONTEXT_LENGTH,
STACK_ALIGN);
//
// Fill in machine frame information.
//
MachineFrame->Rsp = ContextRecord.Rsp;
MachineFrame->Rip = ContextRecord.Rip;
//
// Initialize the user APC parameters.
//
ContextRecord.P1Home = (ULONG64)NormalContext;
ContextRecord.P2Home = (ULONG64)SystemArgument1;
ContextRecord.P3Home = (ULONG64)SystemArgument2;
ContextRecord.P4Home = (ULONG64)NormalRoutine;
//
// Copy context record to the user stack.
//
RtlCopyMemory((PVOID)UserStack, &ContextRecord, sizeof(CONTEXT));
//
// Set the address new stack pointer in the current trap frame and
// the continuation address so control will be transfered to the user
// APC dispatcher.
//
TrapFrame->Rsp = UserStack;
TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
} except (KiCopyInformation(&ExceptionRecord,
(GetExceptionInformation())->ExceptionRecord)) {
//
// Lower the IRQL to PASSIVE_LEVEL, set the exception address to
// the current program address, and raise an exception by calling
// the exception dispatcher.
//
// N.B. The IRQL is lowered to PASSIVE_LEVEL to allow APC interrupts
// during the dispatching of the exception. The current thread
// will be terminated during the dispatching of the exception,
// but lowering of the IRQL is required to enable the debugger
// to obtain the context of the current thread.
//
KeLowerIrql(PASSIVE_LEVEL);
ExceptionRecord.ExceptionAddress = (PVOID)(TrapFrame->Rip);
KiDispatchException(&ExceptionRecord,
ExceptionFrame,
TrapFrame,
UserMode,
TRUE);
}
return;
}