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+
8 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
12 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
22 /* FUNCTIONS *****************************************************************/
25 KiIpiSendRequest(ULONG TargetSet
, ULONG IpiRequest
)
30 for (i
= 0; i
< KeNumberProcessors
; i
++)
32 if (TargetSet
& (1 << i
))
34 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
35 Ke386TestAndSetBit(IpiRequest
, &Pcr
->PrcbData
.IpiFrozen
);
46 KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame
,
47 IN PKEXCEPTION_FRAME ExceptionFrame
)
50 LARGE_INTEGER StartTime
, CurrentTime
, Frequency
;
55 ASSERT(KeGetCurrentIrql() == IPI_LEVEL
);
57 DPRINT("KiIpiServiceRoutine\n");
59 Pcr
= KeGetCurrentKPCR();
61 if (Ke386TestAndClearBit(IPI_REQUEST_APC
, &Pcr
->PrcbData
.IpiFrozen
))
63 HalRequestSoftwareInterrupt(APC_LEVEL
);
66 if (Ke386TestAndClearBit(IPI_REQUEST_DPC
, &Pcr
->PrcbData
.IpiFrozen
))
68 Pcr
->PrcbData
.DpcInterruptRequested
= TRUE
;
69 HalRequestSoftwareInterrupt(DISPATCH_LEVEL
);
72 if (Ke386TestAndClearBit(IPI_REQUEST_FUNCTIONCALL
, &Pcr
->PrcbData
.IpiFrozen
))
74 InterlockedDecrementUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[1]);
75 if (InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[2], 0, 0))
78 StartTime
= KeQueryPerformanceCounter(&Frequency
);
80 while (0 != InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[1], 0, 0))
83 CurrentTime
= KeQueryPerformanceCounter(NULL
);
84 if (CurrentTime
.QuadPart
> StartTime
.QuadPart
+ Count
* Frequency
.QuadPart
)
86 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds to start the ipi routine\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), Count
);
92 ((VOID
STDCALL(*)(PVOID
))(Pcr
->PrcbData
.SignalDone
->WorkerRoutine
))(Pcr
->PrcbData
.SignalDone
->CurrentPacket
[0]);
93 Ke386TestAndClearBit(KeGetCurrentProcessorNumber(), &Pcr
->PrcbData
.SignalDone
->TargetSet
);
94 if (InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->CurrentPacket
[2], 0, 0))
97 StartTime
= KeQueryPerformanceCounter(&Frequency
);
99 while (0 != InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
->TargetSet
, 0, 0))
102 CurrentTime
= KeQueryPerformanceCounter(NULL
);
103 if (CurrentTime
.QuadPart
> StartTime
.QuadPart
+ Count
* Frequency
.QuadPart
)
105 DbgPrint("(%s:%d) CPU%d, waiting longer than %d seconds after executing the ipi routine\n", __FILE__
,__LINE__
, KeGetCurrentProcessorNumber(), Count
);
111 InterlockedExchangePointer(&Pcr
->PrcbData
.SignalDone
, NULL
);
113 DPRINT("KiIpiServiceRoutine done\n");
119 KiIpiSendPacket(ULONG TargetSet
, VOID
STDCALL (*WorkerRoutine
)(PVOID
), PVOID Argument
, ULONG Count
, BOOLEAN Synchronize
)
121 ULONG i
, Processor
, CurrentProcessor
;
122 PKPCR Pcr
, CurrentPcr
;
126 ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL
);
128 CurrentPcr
= KeGetCurrentKPCR();
129 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.TargetSet
, TargetSet
);
130 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.WorkerRoutine
, (ULONG_PTR
)WorkerRoutine
);
131 InterlockedExchangePointer(&CurrentPcr
->PrcbData
.CurrentPacket
[0], Argument
);
132 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.CurrentPacket
[1], Count
);
133 InterlockedExchangeUL(&CurrentPcr
->PrcbData
.CurrentPacket
[2], Synchronize
? 1 : 0);
135 CurrentProcessor
= 1 << KeGetCurrentProcessorNumber();
137 for (i
= 0, Processor
= 1; i
< KeNumberProcessors
; i
++, Processor
<<= 1)
139 if (TargetSet
& Processor
)
141 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
142 while(0 != InterlockedCompareExchangeUL(&Pcr
->PrcbData
.SignalDone
, (LONG
)&CurrentPcr
->PrcbData
, 0));
143 Ke386TestAndSetBit(IPI_REQUEST_FUNCTIONCALL
, &Pcr
->PrcbData
.IpiFrozen
);
144 if (Processor
!= CurrentProcessor
)
150 if (TargetSet
& CurrentProcessor
)
152 KeRaiseIrql(IPI_LEVEL
, &oldIrql
);
153 KiIpiServiceRoutine(NULL
, NULL
);
154 KeLowerIrql(oldIrql
);
159 KeIpiGenericCall(VOID (STDCALL
*Function
)(PVOID
), PVOID Argument
)
164 DPRINT("KeIpiGenericCall on CPU%d\n", KeGetCurrentProcessorNumber());
166 KeRaiseIrql(SYNCH_LEVEL
, &oldIrql
);
168 KiAcquireSpinLock(&KiIpiLock
);
170 TargetSet
= (1 << KeNumberProcessors
) - 1;
172 KiIpiSendPacket(TargetSet
, Function
, Argument
, KeNumberProcessors
, TRUE
);
174 KiReleaseSpinLock(&KiIpiLock
);
176 KeLowerIrql(oldIrql
);
178 DPRINT("KeIpiGenericCall on CPU%d done\n", KeGetCurrentProcessorNumber());