reactos/ntoskrnl/ke/ipi.c

272 lines
7 KiB
C

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ke/ipi.c
* PURPOSE: Inter-Processor Packet Interface
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
extern KSPIN_LOCK KiReverseStallIpiLock;
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
KiIpiGenericCallTarget(IN PKIPI_CONTEXT PacketContext,
IN PVOID BroadcastFunction,
IN PVOID Argument,
IN PVOID Count)
{
/* FIXME: TODO */
ASSERTMSG("Not yet implemented\n", FALSE);
}
VOID
FASTCALL
KiIpiSend(IN KAFFINITY TargetProcessors,
IN ULONG IpiRequest)
{
/* FIXME: TODO */
ASSERTMSG("Not yet implemented\n", FALSE);
}
VOID
NTAPI
KiIpiSendPacket(IN KAFFINITY TargetProcessors,
IN PKIPI_WORKER WorkerFunction,
IN PKIPI_BROADCAST_WORKER BroadcastFunction,
IN ULONG_PTR Context,
IN PULONG Count)
{
/* FIXME: TODO */
ASSERTMSG("Not yet implemented\n", FALSE);
}
VOID
FASTCALL
KiIpiSignalPacketDone(IN PKIPI_CONTEXT PacketContext)
{
/* FIXME: TODO */
ASSERTMSG("Not yet implemented\n", FALSE);
}
VOID
FASTCALL
KiIpiSignalPacketDoneAndStall(IN PKIPI_CONTEXT PacketContext,
IN volatile PULONG ReverseStall)
{
/* FIXME: TODO */
ASSERTMSG("Not yet implemented\n", FALSE);
}
#if 0
VOID
NTAPI
KiIpiSendRequest(IN KAFFINITY TargetSet,
IN ULONG IpiRequest)
{
#ifdef CONFIG_SMP
LONG i;
PKPRCB Prcb;
KAFFINITY Current;
for (i = 0, Current = 1; i < KeNumberProcessors; i++, Current <<= 1)
{
if (TargetSet & Current)
{
/* Get the PRCB for this CPU */
Prcb = KiProcessorBlock[i];
InterlockedBitTestAndSet((PLONG)&Prcb->IpiFrozen, IpiRequest);
HalRequestIpi(i);
}
}
#endif
}
VOID
NTAPI
KiIpiSendPacket(IN KAFFINITY TargetSet,
IN PKIPI_BROADCAST_WORKER WorkerRoutine,
IN ULONG_PTR Argument,
IN ULONG Count,
IN BOOLEAN Synchronize)
{
#ifdef CONFIG_SMP
KAFFINITY Processor;
LONG i;
PKPRCB Prcb, CurrentPrcb;
KIRQL oldIrql;
ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
CurrentPrcb = KeGetCurrentPrcb();
(void)InterlockedExchangeUL(&CurrentPrcb->TargetSet, TargetSet);
(void)InterlockedExchangeUL(&CurrentPrcb->WorkerRoutine, (ULONG_PTR)WorkerRoutine);
(void)InterlockedExchangePointer(&CurrentPrcb->CurrentPacket[0], Argument);
(void)InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[1], Count);
(void)InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[2], Synchronize ? 1 : 0);
for (i = 0, Processor = 1; i < KeNumberProcessors; i++, Processor <<= 1)
{
if (TargetSet & Processor)
{
Prcb = KiProcessorBlock[i];
while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone, (LONG)CurrentPrcb, 0));
InterlockedBitTestAndSet((PLONG)&Prcb->IpiFrozen, IPI_SYNCH_REQUEST);
if (Processor != CurrentPrcb->SetMember)
{
HalRequestIpi(i);
}
}
}
if (TargetSet & CurrentPrcb->SetMember)
{
KeRaiseIrql(IPI_LEVEL, &oldIrql);
KiIpiServiceRoutine(NULL, NULL);
KeLowerIrql(oldIrql);
}
#endif
}
#endif
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
BOOLEAN
NTAPI
KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame,
IN PKEXCEPTION_FRAME ExceptionFrame)
{
#ifdef CONFIG_SMP
PKPRCB Prcb;
ASSERT(KeGetCurrentIrql() == IPI_LEVEL);
Prcb = KeGetCurrentPrcb();
if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_APC))
{
HalRequestSoftwareInterrupt(APC_LEVEL);
}
if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_DPC))
{
Prcb->DpcInterruptRequested = TRUE;
HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
}
if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_SYNCH_REQUEST))
{
#ifdef _M_ARM
DbgBreakPoint();
#else
(void)InterlockedDecrementUL(&Prcb->SignalDone->CurrentPacket[1]);
if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
{
while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[1], 0, 0));
}
((VOID (NTAPI*)(PVOID))(Prcb->SignalDone->WorkerRoutine))(Prcb->SignalDone->CurrentPacket[0]);
InterlockedBitTestAndReset((PLONG)&Prcb->SignalDone->TargetSet, KeGetCurrentProcessorNumber());
if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
{
while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->TargetSet, 0, 0));
}
(void)InterlockedExchangePointer((PVOID*)&Prcb->SignalDone, NULL);
#endif // _M_ARM
}
#endif
return TRUE;
}
/*
* @implemented
*/
ULONG_PTR
NTAPI
KeIpiGenericCall(IN PKIPI_BROADCAST_WORKER Function,
IN ULONG_PTR Argument)
{
ULONG_PTR Status;
KIRQL OldIrql, OldIrql2;
#ifdef CONFIG_SMP
KAFFINITY Affinity;
ULONG Count;
PKPRCB Prcb = KeGetCurrentPrcb();
#endif
/* Raise to DPC level if required */
OldIrql = KeGetCurrentIrql();
if (OldIrql < DISPATCH_LEVEL) KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
#ifdef CONFIG_SMP
/* Get current processor count and affinity */
Count = KeNumberProcessors;
Affinity = KeActiveProcessors;
/* Exclude ourselves */
Affinity &= ~Prcb->SetMember;
#endif
/* Acquire the IPI lock */
KeAcquireSpinLockAtDpcLevel(&KiReverseStallIpiLock);
#ifdef CONFIG_SMP
/* Make sure this is MP */
if (Affinity)
{
/* Send an IPI */
KiIpiSendPacket(Affinity,
KiIpiGenericCallTarget,
Function,
Argument,
&Count);
/* Spin until the other processors are ready */
while (Count != 1)
{
YieldProcessor();
KeMemoryBarrierWithoutFence();
}
}
#endif
/* Raise to IPI level */
KeRaiseIrql(IPI_LEVEL, &OldIrql2);
#ifdef CONFIG_SMP
/* Let the other processors know it is time */
Count = 0;
#endif
/* Call the function */
Status = Function(Argument);
#ifdef CONFIG_SMP
/* If this is MP, wait for the other processors to finish */
if (Affinity)
{
/* Sanity check */
ASSERT(Prcb == KeGetCurrentPrcb());
/* FIXME: TODO */
ASSERTMSG("Not yet implemented\n", FALSE);
}
#endif
/* Release the lock */
KeReleaseSpinLockFromDpcLevel(&KiReverseStallIpiLock);
/* Lower IRQL back */
KeLowerIrql(OldIrql);
return Status;
}