[NTOS:MM] Quick fix: use SIZE_T instead of ULONG, because ULONG is 32-bit and on...
[reactos.git] / ntoskrnl / ke / ipi.c
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 }