mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
5.8 KiB
194 lines
5.8 KiB
/*++
|
|
|
|
Copyright (c) 1993 IBM Corporation and Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
apcuser.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the machine dependent code necessary to initialize
|
|
a user mode APC.
|
|
|
|
Author:
|
|
|
|
Rick Simpson 25-Oct-1993
|
|
|
|
based on MIPS version by David N. Cutler (davec) 23-Apr-1990
|
|
|
|
Environment:
|
|
|
|
Kernel mode only, IRQL APC_LEVEL.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ki.h"
|
|
#pragma hdrstop
|
|
#define _KXPPC_C_HEADER_
|
|
#include "kxppc.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;
|
|
LONG Length;
|
|
ULONG UserStack;
|
|
PULONG PUserStack;
|
|
|
|
//
|
|
// Move the user mode state from the trap and exception frames to the
|
|
// context frame.
|
|
//
|
|
|
|
ContextRecord.ContextFlags = CONTEXT_FULL;
|
|
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:
|
|
//
|
|
// | |
|
|
// |-------------------------------|
|
|
// | Stack frame header |
|
|
// | Back chain points to |
|
|
// | user's stack frame |
|
|
// | - - - - - - - - - - - - - - - |
|
|
// | Context Frame |
|
|
// | Filled in with state |
|
|
// | of interrupted user |
|
|
// | program |
|
|
// | - - - - - - - - - - - - - - - |
|
|
// | Trap Frame |
|
|
// | Empty; for use by |
|
|
// | NtContinue eventually |
|
|
// | - - - - - - - - - - - - - - - |
|
|
// | Save word for TOC ptr |
|
|
// | - - - - - - - - - - - - - - - |
|
|
// | Canonical slack space |
|
|
// |-------------------------------|
|
|
// | |
|
|
// | Interrupted user's |
|
|
// | stack frame |
|
|
// | |
|
|
// | |
|
|
// |-------------------------------|
|
|
// | |
|
|
|
|
try {
|
|
|
|
//
|
|
// Set pointer to KeUserApcDispatcher\'s function descriptor
|
|
// First word = address of entry point
|
|
// Second word = address of TOC
|
|
//
|
|
|
|
PULONG FnDesc = (PULONG) KeUserApcDispatcher;
|
|
|
|
//
|
|
// Compute length of context record and new aligned user stack pointer.
|
|
//
|
|
|
|
Length = (STK_MIN_FRAME + CONTEXT_LENGTH + KTRAP_FRAME_LENGTH +
|
|
sizeof(ULONG) + STK_SLACK_SPACE + 7) & (-8);
|
|
UserStack = (ContextRecord.Gpr1 & (~7)) - Length;
|
|
|
|
//
|
|
// Probe user stack area for writeability and then transfer the
|
|
// context record to the user stack.
|
|
//
|
|
|
|
ProbeForWrite((PCHAR)UserStack, Length, sizeof(QUAD));
|
|
RtlCopyMemory((PULONG)(UserStack + STK_MIN_FRAME), &ContextRecord, sizeof(CONTEXT));
|
|
|
|
//
|
|
// Set the back chain in the new stack frame, store the resume
|
|
// address as if it were the LR value (for stack trace/unwind),
|
|
// and fill in TOC value as if it had been saved by prologue.
|
|
//
|
|
|
|
PUserStack = (PULONG) UserStack;
|
|
PUserStack[0] = ContextRecord.Gpr1;
|
|
PUserStack[(STK_MIN_FRAME + CONTEXT_LENGTH +
|
|
KTRAP_FRAME_LENGTH) / sizeof(ULONG)] = FnDesc[1];
|
|
|
|
//
|
|
// 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->Gpr1 = UserStack; // stack pointer
|
|
TrapFrame->Gpr2 = FnDesc[1]; // TOC address from descriptor
|
|
TrapFrame->Gpr3 = (ULONG)NormalContext; // 1st parameter
|
|
TrapFrame->Gpr4 = (ULONG)SystemArgument1; // 2nd parameter
|
|
TrapFrame->Gpr5 = (ULONG)SystemArgument2; // 3rd parameter
|
|
TrapFrame->Gpr6 = (ULONG)NormalRoutine; // 4th parameter
|
|
TrapFrame->Iar = FnDesc[0]; // entry point from descriptor
|
|
|
|
//
|
|
// 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->Iar);
|
|
KiDispatchException(&ExceptionRecord,
|
|
ExceptionFrame,
|
|
TrapFrame,
|
|
UserMode,
|
|
TRUE);
|
|
}
|
|
|
|
return;
|
|
}
|