204 lines
6.2 KiB
C
204 lines
6.2 KiB
C
|
/*++
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
apcuser.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the machine dependent code necessary to initialize
|
|||
|
a user mode APC.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
William K. Cheung 26-Oct-1995
|
|||
|
|
|||
|
based on MIPS version by David N. Cutler (davec) 23-Apr-1990
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode only, IRQL APC_LEVEL.
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "ki.h"
|
|||
|
#include "kxia64.h"
|
|||
|
|
|||
|
VOID
|
|||
|
KiSaveHigherFPVolatile (
|
|||
|
PVOID
|
|||
|
);
|
|||
|
|
|||
|
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;
|
|||
|
LONG Length;
|
|||
|
ULONGLONG UserStack;
|
|||
|
PULONGLONG Arguments;
|
|||
|
|
|||
|
//
|
|||
|
// Move the user mode state from the trap and exception frames to the
|
|||
|
// context frame.
|
|||
|
//
|
|||
|
|
|||
|
ContextRecord.ContextFlags = CONTEXT_FULL;
|
|||
|
|
|||
|
//
|
|||
|
// Push the user RSE state back out to user mode.
|
|||
|
//
|
|||
|
|
|||
|
KeFlushUserRseState (TrapFrame);
|
|||
|
|
|||
|
KiSaveHigherFPVolatile(GET_HIGH_FLOATING_POINT_REGISTER_SAVEAREA(KeGetCurrentThread()->StackBase));
|
|||
|
TrapFrame->StIPSR &= ~(1i64 << PSR_MFH);
|
|||
|
|
|||
|
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.
|
|||
|
//
|
|||
|
// We build the following structure on the user stack:
|
|||
|
//
|
|||
|
// | |
|
|||
|
// |-------------------------------|
|
|||
|
// | |
|
|||
|
// | Interrupted user's |
|
|||
|
// | stack frame |
|
|||
|
// | |
|
|||
|
// | |
|
|||
|
// |-------------------------------|
|
|||
|
// | Slack Space due to the |
|
|||
|
// | 16-byte stack alignment |
|
|||
|
// | - - - - - - - - - - - - - - - |
|
|||
|
// | NormalRoutine |
|
|||
|
// | SystemArgument2 |
|
|||
|
// | SystemArgument1 |
|
|||
|
// | NormalContext |
|
|||
|
// | - - - - - - - - - - - - - - - |
|
|||
|
// | Context Frame |
|
|||
|
// | Filled in with state |
|
|||
|
// | of interrupted user |
|
|||
|
// | program |
|
|||
|
// | - - - - - - - - - - - - - - - |
|
|||
|
// | Stack Scratch Area |
|
|||
|
// |-------------------------------|
|
|||
|
// | |
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
USHORT LocalFrameSize;
|
|||
|
PPLABEL_DESCRIPTOR Plabel = (PPLABEL_DESCRIPTOR) KeUserApcDispatcher;
|
|||
|
|
|||
|
//
|
|||
|
// Compute total length of 4 arguments, context record, and
|
|||
|
// stack scratch area.
|
|||
|
//
|
|||
|
// Compute the new 16-byte aligned user stack pointer.
|
|||
|
//
|
|||
|
|
|||
|
Length = (4 * sizeof(ULONGLONG) + CONTEXT_LENGTH +
|
|||
|
STACK_SCRATCH_AREA + 15) & (~15);
|
|||
|
UserStack = (ContextRecord.IntSp & (~15)) - Length;
|
|||
|
Arguments = (PULONGLONG)(UserStack + STACK_SCRATCH_AREA + CONTEXT_LENGTH);
|
|||
|
|
|||
|
//
|
|||
|
// Probe user stack area for writeability and then transfer the
|
|||
|
// context record to the user stack.
|
|||
|
//
|
|||
|
|
|||
|
ProbeForWriteSmallStructure((PCHAR)UserStack, Length, sizeof(QUAD));
|
|||
|
RtlCopyMemory((PVOID)(UserStack+STACK_SCRATCH_AREA),
|
|||
|
&ContextRecord, sizeof(CONTEXT));
|
|||
|
|
|||
|
//
|
|||
|
// Set the address of the user APC routine, the APC parameters, the
|
|||
|
// interrupt frame set, the new global pointer, and the new stack
|
|||
|
// pointer in the current trap frame. The four APC parameters are
|
|||
|
// passed via the scratch registers t0 thru t3.
|
|||
|
// Set the continuation address so control will be transfered to
|
|||
|
// the user APC dispatcher.
|
|||
|
//
|
|||
|
|
|||
|
*Arguments++ = (ULONGLONG)NormalContext; // 1st argument
|
|||
|
*Arguments++ = (ULONGLONG)SystemArgument1; // 2nd argument
|
|||
|
*Arguments++ = (ULONGLONG)SystemArgument2; // 3rd argument
|
|||
|
*Arguments++ = (ULONGLONG)NormalRoutine; // 4th argument
|
|||
|
*(PULONGLONG)UserStack = Plabel->GlobalPointer; // user apc dispatcher gp
|
|||
|
|
|||
|
TrapFrame->IntNats = 0; // sanitize integer Nats
|
|||
|
TrapFrame->IntSp = UserStack; // stack pointer
|
|||
|
|
|||
|
TrapFrame->StIIP = Plabel->EntryPoint; // entry point from plabel
|
|||
|
TrapFrame->StIPSR &= ~(0x3ULL << PSR_RI); // start at bundle boundary
|
|||
|
TrapFrame->RsPFS &= 0xffffffc000000000i64; // set the initial frame
|
|||
|
TrapFrame->StIFS &= 0xffffffc000000000i64; // set the initial frame
|
|||
|
// size of KeUserApcDispatcher
|
|||
|
// to be zero.
|
|||
|
TrapFrame->StFPSR = USER_FPSR_INITIAL;
|
|||
|
|
|||
|
//
|
|||
|
// If an exception occurs, then copy the exception information to an
|
|||
|
// exception record and handle the exception.
|
|||
|
//
|
|||
|
|
|||
|
} 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->StIIP);
|
|||
|
KiDispatchException(&ExceptionRecord,
|
|||
|
ExceptionFrame,
|
|||
|
TrapFrame,
|
|||
|
UserMode,
|
|||
|
TRUE);
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|