1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/ipi.c
5 * PURPOSE: Inter-Processor Packet Interface
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 extern KSPIN_LOCK KiReverseStallIpiLock;
18
19 /* PRIVATE FUNCTIONS *********************************************************/
20
21 #ifndef _M_AMD64
22
23 VOID
24 NTAPI
KiIpiGenericCallTarget(IN PKIPI_CONTEXT PacketContext,IN PVOID BroadcastFunction,IN PVOID Argument,IN PVOID Count)25 KiIpiGenericCallTarget(IN PKIPI_CONTEXT PacketContext,
26 IN PVOID BroadcastFunction,
27 IN PVOID Argument,
28 IN PVOID Count)
29 {
30 /* FIXME: TODO */
31 ASSERTMSG("Not yet implemented\n", FALSE);
32 }
33
34 VOID
35 FASTCALL
KiIpiSend(IN KAFFINITY TargetProcessors,IN ULONG IpiRequest)36 KiIpiSend(IN KAFFINITY TargetProcessors,
37 IN ULONG IpiRequest)
38 {
39 /* FIXME: TODO */
40 ASSERTMSG("Not yet implemented\n", FALSE);
41 }
42
43 VOID
44 NTAPI
KiIpiSendPacket(IN KAFFINITY TargetProcessors,IN PKIPI_WORKER WorkerFunction,IN PKIPI_BROADCAST_WORKER BroadcastFunction,IN ULONG_PTR Context,IN PULONG Count)45 KiIpiSendPacket(IN KAFFINITY TargetProcessors,
46 IN PKIPI_WORKER WorkerFunction,
47 IN PKIPI_BROADCAST_WORKER BroadcastFunction,
48 IN ULONG_PTR Context,
49 IN PULONG Count)
50 {
51 /* FIXME: TODO */
52 ASSERTMSG("Not yet implemented\n", FALSE);
53 }
54
55 VOID
56 FASTCALL
KiIpiSignalPacketDone(IN PKIPI_CONTEXT PacketContext)57 KiIpiSignalPacketDone(IN PKIPI_CONTEXT PacketContext)
58 {
59 /* FIXME: TODO */
60 ASSERTMSG("Not yet implemented\n", FALSE);
61 }
62
63 VOID
64 FASTCALL
KiIpiSignalPacketDoneAndStall(IN PKIPI_CONTEXT PacketContext,IN volatile PULONG ReverseStall)65 KiIpiSignalPacketDoneAndStall(IN PKIPI_CONTEXT PacketContext,
66 IN volatile PULONG ReverseStall)
67 {
68 /* FIXME: TODO */
69 ASSERTMSG("Not yet implemented\n", FALSE);
70 }
71
72 #if 0
73 VOID
74 NTAPI
75 KiIpiSendRequest(IN KAFFINITY TargetSet,
76 IN ULONG IpiRequest)
77 {
78 #ifdef CONFIG_SMP
79 LONG i;
80 PKPRCB Prcb;
81 KAFFINITY Current;
82
83 for (i = 0, Current = 1; i < KeNumberProcessors; i++, Current <<= 1)
84 {
85 if (TargetSet & Current)
86 {
87 /* Get the PRCB for this CPU */
88 Prcb = KiProcessorBlock[i];
89
90 InterlockedBitTestAndSet((PLONG)&Prcb->IpiFrozen, IpiRequest);
91 HalRequestIpi(i);
92 }
93 }
94 #endif
95 }
96
97 VOID
98 NTAPI
99 KiIpiSendPacket(IN KAFFINITY TargetSet,
100 IN PKIPI_BROADCAST_WORKER WorkerRoutine,
101 IN ULONG_PTR Argument,
102 IN ULONG Count,
103 IN BOOLEAN Synchronize)
104 {
105 #ifdef CONFIG_SMP
106 KAFFINITY Processor;
107 LONG i;
108 PKPRCB Prcb, CurrentPrcb;
109 KIRQL oldIrql;
110
111 ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
112
113 CurrentPrcb = KeGetCurrentPrcb();
114 (void)InterlockedExchangeUL(&CurrentPrcb->TargetSet, TargetSet);
115 (void)InterlockedExchangeUL(&CurrentPrcb->WorkerRoutine, (ULONG_PTR)WorkerRoutine);
116 (void)InterlockedExchangePointer(&CurrentPrcb->CurrentPacket[0], Argument);
117 (void)InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[1], Count);
118 (void)InterlockedExchangeUL(&CurrentPrcb->CurrentPacket[2], Synchronize ? 1 : 0);
119
120 for (i = 0, Processor = 1; i < KeNumberProcessors; i++, Processor <<= 1)
121 {
122 if (TargetSet & Processor)
123 {
124 Prcb = KiProcessorBlock[i];
125 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone, (LONG)CurrentPrcb, 0));
126 InterlockedBitTestAndSet((PLONG)&Prcb->IpiFrozen, IPI_SYNCH_REQUEST);
127 if (Processor != CurrentPrcb->SetMember)
128 {
129 HalRequestIpi(i);
130 }
131 }
132 }
133 if (TargetSet & CurrentPrcb->SetMember)
134 {
135 KeRaiseIrql(IPI_LEVEL, &oldIrql);
136 KiIpiServiceRoutine(NULL, NULL);
137 KeLowerIrql(oldIrql);
138 }
139 #endif
140 }
141 #endif
142
143 /* PUBLIC FUNCTIONS **********************************************************/
144
145 /*
146 * @implemented
147 */
148 BOOLEAN
149 NTAPI
KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame,IN PKEXCEPTION_FRAME ExceptionFrame)150 KiIpiServiceRoutine(IN PKTRAP_FRAME TrapFrame,
151 IN PKEXCEPTION_FRAME ExceptionFrame)
152 {
153 #ifdef CONFIG_SMP
154 PKPRCB Prcb;
155 ASSERT(KeGetCurrentIrql() == IPI_LEVEL);
156
157 Prcb = KeGetCurrentPrcb();
158
159 if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_APC))
160 {
161 HalRequestSoftwareInterrupt(APC_LEVEL);
162 }
163
164 if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_DPC))
165 {
166 Prcb->DpcInterruptRequested = TRUE;
167 HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
168 }
169
170 if (InterlockedBitTestAndReset((PLONG)&Prcb->IpiFrozen, IPI_SYNCH_REQUEST))
171 {
172 #if defined(_M_ARM) || defined(_M_AMD64)
173 DbgBreakPoint();
174 #else
175 (void)InterlockedDecrementUL(&Prcb->SignalDone->CurrentPacket[1]);
176 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
177 {
178 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[1], 0, 0));
179 }
180 ((VOID (NTAPI*)(PVOID))(Prcb->SignalDone->WorkerRoutine))(Prcb->SignalDone->CurrentPacket[0]);
181 InterlockedBitTestAndReset((PLONG)&Prcb->SignalDone->TargetSet, KeGetCurrentProcessorNumber());
182 if (InterlockedCompareExchangeUL(&Prcb->SignalDone->CurrentPacket[2], 0, 0))
183 {
184 while (0 != InterlockedCompareExchangeUL(&Prcb->SignalDone->TargetSet, 0, 0));
185 }
186 (void)InterlockedExchangePointer((PVOID*)&Prcb->SignalDone, NULL);
187 #endif // _M_ARM
188 }
189 #endif
190 return TRUE;
191 }
192
193 /*
194 * @implemented
195 */
196 ULONG_PTR
197 NTAPI
KeIpiGenericCall(IN PKIPI_BROADCAST_WORKER Function,IN ULONG_PTR Argument)198 KeIpiGenericCall(IN PKIPI_BROADCAST_WORKER Function,
199 IN ULONG_PTR Argument)
200 {
201 ULONG_PTR Status;
202 KIRQL OldIrql, OldIrql2;
203 #ifdef CONFIG_SMP
204 KAFFINITY Affinity;
205 ULONG Count;
206 PKPRCB Prcb = KeGetCurrentPrcb();
207 #endif
208
209 /* Raise to DPC level if required */
210 OldIrql = KeGetCurrentIrql();
211 if (OldIrql < DISPATCH_LEVEL) KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
212
213 #ifdef CONFIG_SMP
214 /* Get current processor count and affinity */
215 Count = KeNumberProcessors;
216 Affinity = KeActiveProcessors;
217
218 /* Exclude ourselves */
219 Affinity &= ~Prcb->SetMember;
220 #endif
221
222 /* Acquire the IPI lock */
223 KeAcquireSpinLockAtDpcLevel(&KiReverseStallIpiLock);
224
225 #ifdef CONFIG_SMP
226 /* Make sure this is MP */
227 if (Affinity)
228 {
229 /* Send an IPI */
230 KiIpiSendPacket(Affinity,
231 KiIpiGenericCallTarget,
232 Function,
233 Argument,
234 &Count);
235
236 /* Spin until the other processors are ready */
237 while (Count != 1)
238 {
239 YieldProcessor();
240 KeMemoryBarrierWithoutFence();
241 }
242 }
243 #endif
244
245 /* Raise to IPI level */
246 KeRaiseIrql(IPI_LEVEL, &OldIrql2);
247
248 #ifdef CONFIG_SMP
249 /* Let the other processors know it is time */
250 Count = 0;
251 #endif
252
253 /* Call the function */
254 Status = Function(Argument);
255
256 #ifdef CONFIG_SMP
257 /* If this is MP, wait for the other processors to finish */
258 if (Affinity)
259 {
260 /* Sanity check */
261 ASSERT(Prcb == KeGetCurrentPrcb());
262
263 /* FIXME: TODO */
264 ASSERTMSG("Not yet implemented\n", FALSE);
265 }
266 #endif
267
268 /* Release the lock */
269 KeReleaseSpinLockFromDpcLevel(&KiReverseStallIpiLock);
270
271 /* Lower IRQL back */
272 KeLowerIrql(OldIrql);
273 return Status;
274 }
275
276 #endif // !_M_AMD64
277