mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
272 lines
7 KiB
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;
|
|
}
|