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