3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/ipi.c
6 * PURPOSE: IPI Routines (Inter-Processor Interrupts). NT5+
7 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
13 /* INCLUDES *****************************************************************/
17 #include <internal/debug.h>
19 /* GLOBALS *******************************************************************/
23 /* FUNCTIONS *****************************************************************/
26 KiIpiSendRequest(ULONG TargetSet
, ULONG IpiRequest
)
31 for (i
= 0; i
< KeNumberProcessors
; i
++)
33 if (TargetSet
& (1 << i
))
35 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
36 Ke386TestAndSetBit(IpiRequest
, &Pcr
->PrcbData
.IpiFrozen
);
47 KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame
,
48 IN PKEXCEPTION_FRAME ExceptionFrame
)
51 LARGE_INTEGER StartTime
, CurrentTime
, Frequency
;
56 ASSERT(KeGetCurrentIrql() == IPI_LEVEL
);
58 DPRINT("KiIpiServiceRoutine\n");
60 Pcr
= KeGetCurrentKPCR();
62 if (Ke386TestAndClearBit(IPI_REQUEST_APC
, &Pcr
->PrcbData
.IpiFrozen
))
64 HalRequestSoftwareInterrupt(APC_LEVEL
);
67 if (Ke386TestAndClearBit(IPI_REQUEST_DPC
, &Pcr
->PrcbData
.IpiFrozen
))
69 Pcr
->PrcbData
.DpcInterruptRequested
= TRUE
;
70 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
73 if (Ke386TestAndClearBit(IPI_REQUEST_FUNCTIONCALL
, &Pcr
->PrcbData
.IpiFrozen
))
75 InterlockedDecrementUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[1]);
76 if (InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[2], 0, 0))
79 StartTime
= KeQueryPerformanceCounter(&Frequency
);
81 while (0 != InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[1], 0, 0))
84 CurrentTime
= KeQueryPerformanceCounter(NULL
);
85 if (CurrentTime
.QuadPart
> StartTime
.QuadPart
+ Count
* Frequency
.QuadPart
)
87 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds to start the ipi routine\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), Count
);
93 ((VOID
STDCALL(*)(PVOID
))(Pcr
->PrcbData
.SignalDone
->WorkerRoutine
))(Pcr
->PrcbData
.SignalDone
->CurrentPacket
[0]);
94 Ke386TestAndClearBit(KeGetCurrentProcessorNumber(), &Pcr
->PrcbData
.SignalDone
->TargetSet
);
95 if (InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[2], 0, 0))
98 StartTime
= KeQueryPerformanceCounter(&Frequency
);
100 while (0 != InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->TargetSet
, 0, 0))
103 CurrentTime
= KeQueryPerformanceCounter(NULL
);
104 if (CurrentTime
.QuadPart
> StartTime
.QuadPart
+ Count
* Frequency
.QuadPart
)
106 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds after executing the ipi routine\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), Count
);
112 InterlockedExchangePointer(&Pcr
->PrcbData
.SignalDone
, NULL
);
114 DPRINT("KiIpiServiceRoutine done\n");
120 KiIpiSendPacket(ULONG TargetSet
, VOID
STDCALL (*WorkerRoutine
)(PVOID
), PVOID Argument
, ULONG Count
, BOOLEAN Synchronize
)
122 ULONG i
, Processor
, CurrentProcessor
;
123 PKPCR Pcr
, CurrentPcr
;
127 ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL
);
129 CurrentPcr
= KeGetCurrentKPCR();
130 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.TargetSet
, TargetSet
);
131 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.WorkerRoutine
, (ULONG_PTR
)WorkerRoutine
);
132 InterlockedExchangePointer(&CurrentPcr
->PrcbData
.CurrentPacket
[0], Argument
);
133 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.CurrentPacket
[1], Count
);
134 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.CurrentPacket
[2], Synchronize
? 1 : 0);
136 CurrentProcessor
= 1 << KeGetCurrentProcessorNumber();
138 for (i
= 0, Processor
= 1; i
< KeNumberProcessors
; i
++, Processor
<<= 1)
140 if (TargetSet
& Processor
)
142 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
143 while(0 != InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
, (LONG
)&CurrentPcr
->PrcbData
, 0));
144 Ke386TestAndSetBit(IPI_REQUEST_FUNCTIONCALL
, &Pcr
->PrcbData
.IpiFrozen
);
145 if (Processor
!= CurrentProcessor
)
151 if (TargetSet
& CurrentProcessor
)
153 KeRaiseIrql(IPI_LEVEL
, &oldIrql
);
154 KiIpiServiceRoutine(NULL
, NULL
);
155 KeLowerIrql(oldIrql
);
160 KeIpiGenericCall(VOID
STDCALL (*Function
)(PVOID
), PVOID Argument
)
165 DPRINT("KeIpiGenericCall on CPU%d\n", KeGetCurrentProcessorNumber());
167 KeRaiseIrql(SYNCH_LEVEL
, &oldIrql
);
169 KiAcquireSpinLock(&KiIpiLock
);
171 TargetSet
= (1 << KeNumberProcessors
) - 1;
173 KiIpiSendPacket(TargetSet
, Function
, Argument
, KeNumberProcessors
, TRUE
);
175 KiReleaseSpinLock(&KiIpiLock
);
177 KeLowerIrql(oldIrql
);
179 DPRINT("KeIpiGenericCall on CPU%d done\n", KeGetCurrentProcessorNumber());