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