199 lines
6.4 KiB
C
199 lines
6.4 KiB
C
/*++
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
context.c
|
|
|
|
Abstract:
|
|
This module implements user-mode callable context manipulation routines.
|
|
|
|
Author:
|
|
Mark Lucovsky (markl) 20-Jun-1989
|
|
|
|
Revision History:
|
|
David N. Cutler (davec) 18-Apr-1990
|
|
Revise for MIPS environment.
|
|
--*/
|
|
|
|
#include <ntos.h>
|
|
|
|
|
|
VOID RtlInitializeContext(IN HANDLE Process, OUT PCONTEXT Context, IN PVOID Parameter OPTIONAL, IN PVOID InitialPc OPTIONAL, IN PVOID InitialSp OPTIONAL)
|
|
/*++
|
|
Routine Description:
|
|
This function initializes a context structure so that it can be used in a subsequent call to NtCreateThread.
|
|
Arguments:
|
|
Context - Supplies a pointer to a context record that is to be initialized.
|
|
InitialPc - Supplies an initial program counter value.
|
|
InitialSp - Supplies an initial stack pointer value.
|
|
Return Value:
|
|
Raises STATUS_BAD_INITIAL_STACK if the value of InitialSp is not properly aligned.
|
|
Raises STATUS_BAD_INITIAL_PC if the value of InitialPc is not properly aligned.
|
|
--*/
|
|
{
|
|
// Check for proper initial stack and PC alignment.
|
|
if (((ULONG)InitialSp & 0x7) != 0) {
|
|
RtlRaiseStatus(STATUS_BAD_INITIAL_STACK);
|
|
}
|
|
if (((ULONG)InitialPc & 0x3) != 0) {
|
|
RtlRaiseStatus(STATUS_BAD_INITIAL_PC);
|
|
}
|
|
|
|
// Initialize the integer registers to contain their register number.
|
|
Context->XIntZero = 0;
|
|
Context->XIntAt = 1;
|
|
Context->XIntV0 = 2;
|
|
Context->XIntV1 = 3;
|
|
Context->XIntA0 = 4;
|
|
Context->XIntA1 = 5;
|
|
Context->XIntA2 = 6;
|
|
Context->XIntA3 = 7;
|
|
Context->XIntT0 = 8;
|
|
Context->XIntT1 = 9;
|
|
Context->XIntT2 = 10;
|
|
Context->XIntT3 = 11;
|
|
Context->XIntT4 = 12;
|
|
Context->XIntT5 = 13;
|
|
Context->XIntT6 = 14;
|
|
Context->XIntT7 = 15;
|
|
Context->XIntS0 = 16;
|
|
Context->XIntS1 = 17;
|
|
Context->XIntS2 = 18;
|
|
Context->XIntS3 = 19;
|
|
Context->XIntS4 = 20;
|
|
Context->XIntS5 = 21;
|
|
Context->XIntS6 = 22;
|
|
Context->XIntS7 = 23;
|
|
Context->XIntT8 = 24;
|
|
Context->XIntT9 = 25;
|
|
Context->XIntS8 = 30;
|
|
Context->XIntLo = 0;
|
|
Context->XIntHi = 0;
|
|
|
|
// Initialize the floating point registers to contain zero in their upper half and the integer value of their register number in the lower half.
|
|
Context->FltF0 = 0;
|
|
Context->FltF1 = 0;
|
|
Context->FltF2 = 2;
|
|
Context->FltF3 = 0;
|
|
Context->FltF4 = 4;
|
|
Context->FltF5 = 0;
|
|
Context->FltF6 = 6;
|
|
Context->FltF7 = 0;
|
|
Context->FltF8 = 8;
|
|
Context->FltF9 = 0;
|
|
Context->FltF10 = 10;
|
|
Context->FltF11 = 0;
|
|
Context->FltF12 = 12;
|
|
Context->FltF13 = 0;
|
|
Context->FltF14 = 14;
|
|
Context->FltF15 = 0;
|
|
Context->FltF16 = 16;
|
|
Context->FltF17 = 0;
|
|
Context->FltF18 = 18;
|
|
Context->FltF19 = 0;
|
|
Context->FltF20 = 20;
|
|
Context->FltF21 = 0;
|
|
Context->FltF22 = 22;
|
|
Context->FltF23 = 0;
|
|
Context->FltF24 = 24;
|
|
Context->FltF25 = 0;
|
|
Context->FltF26 = 26;
|
|
Context->FltF27 = 0;
|
|
Context->FltF28 = 28;
|
|
Context->FltF29 = 0;
|
|
Context->FltF30 = 30;
|
|
Context->FltF31 = 0;
|
|
Context->Fsr = 0;
|
|
|
|
// Initialize the control registers.
|
|
|
|
// N.B. The register gp is estabished at thread startup by the loader.
|
|
Context->XIntGp = 0;
|
|
Context->XIntSp = (LONG)InitialSp;
|
|
Context->XIntRa = 1;
|
|
Context->Fir = (ULONG)InitialPc;
|
|
Context->Psr = 0;
|
|
Context->ContextFlags = CONTEXT_FULL;
|
|
|
|
// Set the initial context of the thread in a machine specific way.
|
|
Context->XIntA0 = (LONG)Parameter;
|
|
Context->XIntSp -= KTRAP_FRAME_ARGUMENTS;
|
|
}
|
|
|
|
|
|
NTSTATUS RtlRemoteCall(HANDLE Process, HANDLE Thread, PVOID CallSite, ULONG ArgumentCount, PULONG Arguments, BOOLEAN PassContext, BOOLEAN AlreadySuspended)
|
|
/*++
|
|
Routine Description:
|
|
This function calls a procedure in another thread/process, by using NtGetContext and NtSetContext.
|
|
Parameters are passed to the target procedure via the nonvolatile registers (s0 - s7).
|
|
Arguments:
|
|
Process - Supplies an open handle to the target process.
|
|
Thread - Supplies an open handle to the target thread within the target process.
|
|
CallSize - Supplies the address of the procedure to call in the target process.
|
|
ArgumentCount - Supplies the number of 32 bit parameters to pass to the target procedure.
|
|
Arguments - Supplies a pointer to the array of 32 bit parameters to pass.
|
|
PassContext - Supplies a boolean value that determines whether a parameter is to be passed that points to a context record. This parameter is ignored on MIPS hosts.
|
|
AlreadySuspended - Supplies a boolean value that determines whether the target thread is already in a suspended or waiting state.
|
|
Return Value:
|
|
Status - Status value
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
CONTEXT Context;
|
|
ULONG NewSp;
|
|
|
|
if (ArgumentCount > 8) {
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
// If necessary, suspend the target thread before getting the thread's current state.
|
|
if (AlreadySuspended == FALSE) {
|
|
Status = NtSuspendThread(Thread, NULL);
|
|
if (NT_SUCCESS(Status) == FALSE) {
|
|
return(Status);
|
|
}
|
|
}
|
|
|
|
// Get the cuurent state of the target thread.
|
|
Context.ContextFlags = CONTEXT_FULL;
|
|
Status = NtGetContextThread(Thread, &Context);
|
|
if (NT_SUCCESS(Status) == FALSE) {
|
|
if (AlreadySuspended == FALSE) {
|
|
NtResumeThread(Thread, NULL);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
if (AlreadySuspended) {
|
|
Context.XIntV0 = (LONG)STATUS_ALERTED;
|
|
}
|
|
|
|
// Pass the parameters to the other thread via the non-volatile registers s0 - s7. The context record is passed on the stack of the target thread.
|
|
NewSp = (ULONG)(Context.XIntSp - sizeof(CONTEXT));
|
|
Status = NtWriteVirtualMemory(Process, (PVOID)NewSp, &Context, sizeof(CONTEXT), NULL);
|
|
if (NT_SUCCESS(Status) == FALSE) {
|
|
if (AlreadySuspended == FALSE) {
|
|
NtResumeThread(Thread, NULL);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
Context.XIntSp = (LONG)NewSp;
|
|
if (PassContext) {
|
|
Context.XIntS0 = (LONG)NewSp;
|
|
RtlMoveMemory(&Context.XIntS1, Arguments, ArgumentCount * sizeof(ULONG));
|
|
} else {
|
|
RtlMoveMemory(&Context.XIntS0, Arguments, ArgumentCount * sizeof(ULONG));
|
|
}
|
|
|
|
// Set the address of the target code into FIR and set the thread context to cause the target procedure to be executed.
|
|
Context.Fir = (ULONG)CallSite;;
|
|
Status = NtSetContextThread(Thread, &Context);
|
|
if (AlreadySuspended == FALSE) {
|
|
NtResumeThread(Thread, NULL);
|
|
}
|
|
|
|
return Status;
|
|
} |