258 lines
5.6 KiB
C
258 lines
5.6 KiB
C
/*++
|
||
|
||
Copyright (c) 1993-1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
xipi.c
|
||
|
||
Abstract:
|
||
|
||
This module implements portable interprocessor interrup routines.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 24-Apr-1993
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
|
||
//
|
||
// Define forward reference function prototypes.
|
||
//
|
||
|
||
VOID
|
||
KiIpiGenericCallTarget (
|
||
IN PKIPI_CONTEXT SignalDone,
|
||
IN PVOID BroadcastFunction,
|
||
IN PVOID Context,
|
||
IN PVOID Parameter3
|
||
);
|
||
|
||
ULONG_PTR
|
||
KiIpiGenericCall (
|
||
IN PKIPI_BROADCAST_WORKER BroadcastFunction,
|
||
IN ULONG_PTR Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function executes the specified function on every processor in
|
||
the host configuration in a synchronous manner, i.e., the function
|
||
is executed on each target in series with the execution of the source
|
||
processor.
|
||
|
||
Arguments:
|
||
|
||
BroadcastFunction - Supplies the address of function that is executed
|
||
on each of the target processors.
|
||
|
||
Context - Supplies the value of the context parameter that is passed
|
||
to each function.
|
||
|
||
Return Value:
|
||
|
||
The value returned by the specified function on the source processor
|
||
is returned as the function value.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
KIRQL OldIrql;
|
||
ULONG_PTR Status;
|
||
KAFFINITY TargetProcessors;
|
||
|
||
//
|
||
// Raise IRQL to the higher of the current level and synchronization
|
||
// level to avoid a possible context switch.
|
||
//
|
||
|
||
KeRaiseIrql((KIRQL)(max(KiSynchIrql, KeGetCurrentIrql())), &OldIrql);
|
||
|
||
//
|
||
// Initialize the broadcast packet, compute the set of target processors,
|
||
// and sent the packet to the target processors for execution.
|
||
//
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
TargetProcessors = KeActiveProcessors & ~KeGetCurrentPrcb()->SetMember;
|
||
if (TargetProcessors != 0) {
|
||
KiIpiSendPacket(TargetProcessors,
|
||
KiIpiGenericCallTarget,
|
||
(PVOID)BroadcastFunction,
|
||
(PVOID)Context,
|
||
NULL);
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// Execute function of source processor and capture return status.
|
||
//
|
||
|
||
Status = BroadcastFunction(Context);
|
||
|
||
//
|
||
// Wait until all of the target processors have finished capturing the
|
||
// function parameters.
|
||
//
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
if (TargetProcessors != 0) {
|
||
KiIpiStallOnPacketTargets(TargetProcessors);
|
||
}
|
||
|
||
#endif
|
||
|
||
//
|
||
// Lower IRQL to its previous level and return the function execution
|
||
// status.
|
||
//
|
||
|
||
KeLowerIrql(OldIrql);
|
||
return Status;
|
||
}
|
||
|
||
#if !defined(NT_UP)
|
||
|
||
|
||
VOID
|
||
KiIpiGenericCallTarget (
|
||
IN PKIPI_CONTEXT SignalDone,
|
||
IN PVOID BroadcastFunction,
|
||
IN PVOID Context,
|
||
IN PVOID Parameter3
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is the target jacket function to execute a broadcast
|
||
function on a set of target processors. The broadcast packet address
|
||
is obtained, the specified parameters are captured, the broadcast
|
||
packet address is cleared to signal the source processor to continue,
|
||
and the specified function is executed.
|
||
|
||
Arguments:
|
||
|
||
SignalDone Supplies a pointer to a variable that is cleared when the
|
||
requested operation has been performed.
|
||
|
||
BroadcastFunction - Supplies the address of function that is executed
|
||
on each of the target processors.
|
||
|
||
Context - Supplies the value of the context parameter that is passed
|
||
to each function.
|
||
|
||
Parameter3 - Not used.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Execute the specified function.
|
||
//
|
||
|
||
((PKIPI_BROADCAST_WORKER)(BroadcastFunction))((ULONG_PTR)Context);
|
||
KiIpiSignalPacketDone(SignalDone);
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
KiIpiStallOnPacketTargets (
|
||
KAFFINITY TargetSet
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function waits until the specified set of processors have signaled
|
||
their completion of a requested function.
|
||
|
||
N.B. The exact protocol used between the source and the target of an
|
||
interprocessor request is not specified. Minimally the source
|
||
must construct an appropriate packet and send the packet to a set
|
||
of specified targets. Each target receives the address of the packet
|
||
address as an argument, and minimally must clear the packet address
|
||
when the mutually agreed upon protocol allows. The target has three
|
||
options:
|
||
|
||
1. Capture necessary information, release the source by clearing
|
||
the packet address, execute the request in parallel with the
|
||
source, and return from the interrupt.
|
||
|
||
2. Execute the request in series with the source, release the
|
||
source by clearing the packet address, and return from the
|
||
interrupt.
|
||
|
||
3. Execute the request in series with the source, release the
|
||
source, wait for a reply from the source based on a packet
|
||
parameter, and return from the interrupt.
|
||
|
||
This function is provided to enable the source to synchronize with the
|
||
target for cases 2 and 3 above.
|
||
|
||
N.B. There is no support for method 3 above.
|
||
|
||
Arguments:
|
||
|
||
TargetSet - Supplies the the target set of IPI processors.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
volatile ULONG *Barrier;
|
||
PKPRCB Prcb;
|
||
|
||
//
|
||
// Wait until the target set of processors is zero in the current
|
||
// processor's packet.
|
||
//
|
||
|
||
Prcb = KeGetCurrentPrcb();
|
||
|
||
//
|
||
// If there is one and only one bit set in the target set, then wait
|
||
// on the target set. Otherwise, wait on the packet barrier.
|
||
//
|
||
|
||
Barrier = (volatile ULONG *)&Prcb->TargetSet;
|
||
if ((TargetSet & (TargetSet - 1)) != 0) {
|
||
Barrier = &Prcb->PacketBarrier;
|
||
}
|
||
|
||
while (*Barrier != 0) {
|
||
KeYieldProcessor();
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
#endif
|