/*++ 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. Thomas Van Baak (tvb) 11-May-1992 Adapted for Alpha AXP. --*/ #include #include #include 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: Process - Supplies an open handle to the target process. This argument is ignored by this function. Context - Supplies a pointer to a context record that is to be initialized. Parameter - Supplies an initial value for register A0. 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 & 0xF) != 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 // (they must be initialized and using register numbers instead of 0 // can be useful for debugging). Integer registers a0, ra, gp, and sp // are set later. // Context->IntV0 = 0; Context->IntT0 = 1; Context->IntT1 = 2; Context->IntT2 = 3; Context->IntT3 = 4; Context->IntT4 = 5; Context->IntT5 = 6; Context->IntT6 = 7; Context->IntT7 = 8; Context->IntS0 = 9; Context->IntS1 = 10; Context->IntS2 = 11; Context->IntS3 = 12; Context->IntS4 = 13; Context->IntS5 = 14; Context->IntFp = 15; Context->IntA1 = 17; Context->IntA2 = 18; Context->IntA3 = 19; Context->IntA4 = 20; Context->IntA5 = 21; Context->IntT8 = 22; Context->IntT9 = 23; Context->IntT10 = 24; Context->IntT11 = 25; Context->IntT12 = 27; Context->IntAt = 28; // // Initialize the floating point registers to contain the integer value // of their register number (they must be initialized and using register // numbers instead of 0 can be useful for debugging). // Context->FltF0 = 0; Context->FltF1 = 1; Context->FltF2 = 2; Context->FltF3 = 3; Context->FltF4 = 4; Context->FltF5 = 5; Context->FltF6 = 6; Context->FltF7 = 7; Context->FltF8 = 8; Context->FltF9 = 9; Context->FltF10 = 10; Context->FltF11 = 11; Context->FltF12 = 12; Context->FltF13 = 13; Context->FltF14 = 14; Context->FltF15 = 15; Context->FltF16 = 16; Context->FltF17 = 17; Context->FltF18 = 18; Context->FltF19 = 19; Context->FltF20 = 20; Context->FltF21 = 21; Context->FltF22 = 22; Context->FltF23 = 23; Context->FltF24 = 24; Context->FltF25 = 25; Context->FltF26 = 26; Context->FltF27 = 27; Context->FltF28 = 28; Context->FltF29 = 29; Context->FltF30 = 30; Context->FltF31 = 0; // // Initialize the control registers. // // Gp: will be set in LdrpInitialize at thread startup. // Ra: some debuggers compare for 1 as a top-of-stack indication. // // N.B. ULONG becomes canonical longword with (ULONGLONG)(LONG) cast. // Context->IntGp = 0; Context->IntSp = (ULONGLONG)(LONG)InitialSp; Context->IntRa = 1; Context->Fir = (ULONGLONG)(LONG)InitialPc; // // Set default Alpha floating point control register values. // Context->Fpcr = (ULONGLONG)0; ((PFPCR)(&Context->Fpcr))->DynamicRoundingMode = ROUND_TO_NEAREST; Context->SoftFpcr = (ULONGLONG)0; Context->Psr = 0; Context->ContextFlags = CONTEXT_FULL; // // Set the initial context of the thread in a machine specific way. // Context->IntA0 = (ULONGLONG)(LONG)Parameter; } 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 - s5). Arguments: Process - Supplies an open handle to the target process. Thread - Supplies an open handle to the target thread within the target process. CallSite - 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 and Alpha 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 Index; ULONGLONG NewSp; if ((ArgumentCount > 6) || (PassContext && (ArgumentCount > 5))) { 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 current 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.IntV0 = STATUS_ALERTED; } // // Pass the parameters to the other thread via the non-volatile registers // s0 - s5. The context record is passed on the stack of the target thread. // NewSp = Context.IntSp - sizeof(CONTEXT); Status = NtWriteVirtualMemory(Process, (PVOID)NewSp, &Context, sizeof(CONTEXT), NULL); if (NT_SUCCESS(Status) == FALSE) { if (AlreadySuspended == FALSE) { NtResumeThread(Thread, NULL); } return(Status); } // // N.B. Each ULONG argument is converted to canonical form with the // (ULONGLONG)(LONG) cast as required by the calling standard. // // N.B. Given the PULONG Arguments prototype, this function cannot pass // quadword arguments (including structures such as LARGE_INTEGER). // Context.IntSp = NewSp; if (PassContext) { Context.IntS0 = NewSp; for (Index = 0; Index < ArgumentCount; Index += 1) { (&Context.IntS1)[Index] = (ULONGLONG)(LONG)Arguments[Index]; } } else { for (Index = 0; Index < ArgumentCount; Index += 1) { (&Context.IntS0)[Index] = (ULONGLONG)(LONG)Arguments[Index]; } } // // Set the address of the target code into FIR and set the thread context // to cause the target procedure to be executed. // // N.B. The PVOID CallSite is stored as a canonical longword in order // for Fir to be a valid 64-bit address. // Context.Fir = (ULONGLONG)(LONG)CallSite; Status = NtSetContextThread(Thread, &Context); if (AlreadySuspended == FALSE) { NtResumeThread(Thread, NULL); } return(Status); }