/*++ Copyright (c) 1993 Microsoft Corporation Module Name: mpipi.c Abstract: This module implements MIPS specific MP routine. Author: Bernard Lint 26-Jun-1996 Environment: Kernel mode only. Revision History: Based on version of David N. Cutler 24-Apr-1993 --*/ #include "ki.h" VOID KiSaveHigherFPVolatile ( PFLOAT128 SaveArea ); VOID KiRestoreProcessorState ( IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame ) /*++ Routine Description: This function moves processor register state from the current processor context structure in the processor block to the specified trap and exception frames. Arguments: TrapFrame - Supplies a pointer to a trap frame. ExceptionFrame - Supplies a pointer to an exception frame. Return Value: None. --*/ { #if !defined(NT_UP) PKPRCB Prcb; // // Get the address of the current processor block and move the // specified register state from the processor context structure // to the specified trap and exception frames // Prcb = KeGetCurrentPrcb(); KeContextToKframes(TrapFrame, ExceptionFrame, &Prcb->ProcessorState.ContextFrame, CONTEXT_FULL, (KPROCESSOR_MODE)TrapFrame->PreviousMode); KiRestoreProcessorControlState(&Prcb->ProcessorState); #endif // !defined(NT_UP) return; } VOID KiSaveProcessorState ( IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame ) /*++ Routine Description: This function moves processor register state from the specified trap and exception frames to the processor context structure in the current processor block. Arguments: TrapFrame - Supplies a pointer to a trap frame. ExceptionFrame - Supplies a pointer to an exception frame. Return Value: None. --*/ { #if !defined(NT_UP) PKPRCB Prcb; // // Get the address of the current processor block and move the // specified register state from specified trap and exception // frames to the current processor context structure. // Prcb = KeGetCurrentPrcb(); if (KeGetCurrentThread()->Teb) { KiSaveHigherFPVolatile((PFLOAT128)GET_HIGH_FLOATING_POINT_REGISTER_SAVEAREA(KeGetCurrentThread()->StackBase)); } Prcb->ProcessorState.ContextFrame.ContextFlags = CONTEXT_FULL; KeContextFromKframes(TrapFrame, ExceptionFrame, &Prcb->ProcessorState.ContextFrame); // // Save ISR in special registers // Prcb->ProcessorState.SpecialRegisters.StISR = TrapFrame->StISR; // // Save the current processor control state. // KiSaveProcessorControlState(&Prcb->ProcessorState); #endif // !defined(NT_UP) return; } BOOLEAN KiIpiServiceRoutine ( IN PKTRAP_FRAME TrapFrame, IN PKEXCEPTION_FRAME ExceptionFrame ) /*++ Routine Description: This function is called at IPI_LEVEL to process any outstanding interprocess request for the current processor. Arguments: TrapFrame - Supplies a pointer to a trap frame. ExceptionFrame - Supplies a pointer to an exception frame Return Value: A value of TRUE is returned, if one of more requests were service. Otherwise, FALSE is returned. --*/ { #if !defined(NT_UP) ULONG RequestSummary; // // Process any outstanding IPI requests // RequestSummary = KiIpiProcessRequests(); // // If freeze is requested, then freeze target execution. // if ((RequestSummary & IPI_FREEZE) != 0) { KiFreezeTargetExecution(TrapFrame, ExceptionFrame); } return ((RequestSummary & ~IPI_FREEZE) != 0); #else return TRUE; #endif // !defined(NT_UP) } ULONG KiIpiProcessRequests ( VOID ) /*++ Routine Description: This routine processes interprocessor requests and returns a summary of the requests that were processed. Arguments: None. Return Value: The request summary is returned as the function value. --*/ { #if !defined(NT_UP) ULONG RequestSummary; PKPRCB SignalDone; PKPRCB Prcb = KeGetCurrentPrcb(); RequestSummary = (ULONG)InterlockedExchange((PLONG)&Prcb->RequestSummary, 0); // // If a packet is ready, then get the address of the requested function // and call the function passing the address of the packet address as a // parameter. // SignalDone = (PKPRCB)( (ULONG_PTR)Prcb->SignalDone & ~(ULONG_PTR)1 ); if (SignalDone != 0) { Prcb->SignalDone = 0; (*SignalDone->WorkerRoutine) ((PKIPI_CONTEXT)SignalDone, SignalDone->CurrentPacket[0], SignalDone->CurrentPacket[1], SignalDone->CurrentPacket[2]); } if ((RequestSummary & IPI_APC) != 0) { KiRequestSoftwareInterrupt (APC_LEVEL); } else if ((RequestSummary & IPI_DPC) != 0) { KiRequestSoftwareInterrupt (DISPATCH_LEVEL); } return RequestSummary; #else return 0; #endif // !defined(NT_UP) } VOID KiIpiSend ( IN KAFFINITY TargetProcessors, IN KIPI_REQUEST IpiRequest ) /*++ Routine Description: This routine requests the specified operation on the target set of processors. Arguments: TargetProcessors (a0) - Supplies the set of processors on which the specified operation is to be executed. IpiRequest (a1) - Supplies the request operation mask. Return Value: None. --*/ { #if !defined(NT_UP) ULONG RequestSummary; KAFFINITY NextProcessors; ULONG Next; // // Loop through the target processors and send the packet to the specified // recipients. // NextProcessors = TargetProcessors; Next = 0; while (NextProcessors != 0) { if ((NextProcessors & 1) != 0) { do { RequestSummary = KiProcessorBlock[Next]->RequestSummary; } while(InterlockedCompareExchange( (PLONG) &KiProcessorBlock[Next]->RequestSummary, (LONG) (RequestSummary | IpiRequest), (LONG) RequestSummary) != (LONG) RequestSummary); } NextProcessors = NextProcessors >> 1; Next = Next + 1; } HalRequestIpi (TargetProcessors); #endif return; } VOID KiIpiSendPacket ( IN KAFFINITY TargetProcessors, IN PKIPI_WORKER WorkerFunction, IN PVOID Parameter1, IN PVOID Parameter2, IN PVOID Parameter3 ) /*++ Routine Description: This routine executes the specified worker function on the specified set of processors. Arguments: TargetProcessors (a0) - Supplies the set of processors on which the specified operation is to be executed. WorkerFunction (a1) - Supplies the address of the worker function. Parameter1 - Parameter3 (a2, a3, 4 * 4(sp)) - Supplies worker function specific parameters. Return Value: None. --*/ { #if !defined(NT_UP) PKPRCB Prcb; KAFFINITY NextProcessors; ULONG Next; Prcb = KeGetCurrentPrcb(); Prcb->TargetSet = TargetProcessors; Prcb->WorkerRoutine = WorkerFunction; Prcb->CurrentPacket[0] = Parameter1; Prcb->CurrentPacket[1] = Parameter2; Prcb->CurrentPacket[2] = Parameter3; // // synchronize memory access // __mf(); // // The low order bit of the packet address is set if there is // exactly one target recipient. Otherwise, the low order bit // of the packet address is clear. // if (((TargetProcessors) & ((TargetProcessors) - 1)) == 0) { (ULONG_PTR) Prcb |= 0x1; } else { Prcb->PacketBarrier = 1; } // // Loop through the target processors and send the packet to the specified // recipients. // NextProcessors = TargetProcessors; Next = 0; while (NextProcessors != 0) { if ((NextProcessors & 1) != 0) { while(InterlockedCompareExchangePointer( (PVOID)&KiProcessorBlock[Next]->SignalDone, (PVOID)Prcb, (PVOID)0) != (PVOID)0); } NextProcessors = NextProcessors >> 1; Next = Next + 1; } HalRequestIpi (TargetProcessors); #endif }