xref: /reactos/ntoskrnl/ke/ipi.c (revision 1831bc6a)
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