417 lines
8.2 KiB
C
417 lines
8.2 KiB
C
/*++
|
||
|
||
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
|
||
}
|