diff --git a/headers/private/kernel/smp.h b/headers/private/kernel/smp.h index f11d0ba424..28e6d96e32 100644 --- a/headers/private/kernel/smp.h +++ b/headers/private/kernel/smp.h @@ -31,6 +31,8 @@ enum { SMP_MSG_FLAG_FREE_ARG = 0x2, }; +typedef uint32 cpu_mask_t; + typedef void (*smp_call_func)(uint32 data1, int32 currentCPU, uint32 data2, uint32 data3); @@ -46,6 +48,8 @@ void smp_wake_up_non_boot_cpus(void); void smp_cpu_rendezvous(volatile uint32 *var, int current_cpu); void smp_send_ici(int32 targetCPU, int32 message, uint32 data, uint32 data2, uint32 data3, void *data_ptr, uint32 flags); +void smp_send_multicast_ici(cpu_mask_t cpuMask, int32 message, uint32 data, + uint32 data2, uint32 data3, void *data_ptr, uint32 flags); void smp_send_broadcast_ici(int32 message, uint32 data, uint32 data2, uint32 data3, void *data_ptr, uint32 flags); diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile index 4849672655..c84c61e277 100644 --- a/src/system/kernel/Jamfile +++ b/src/system/kernel/Jamfile @@ -40,7 +40,7 @@ KernelMergeObject kernel_core.o : shutdown.c signal.cpp system_info.cpp - smp.c + smp.cpp syscalls.cpp team.cpp thread.cpp diff --git a/src/system/kernel/smp.c b/src/system/kernel/smp.cpp similarity index 91% rename from src/system/kernel/smp.c rename to src/system/kernel/smp.cpp index db6f1311bb..dddbc7d1f3 100644 --- a/src/system/kernel/smp.c +++ b/src/system/kernel/smp.cpp @@ -554,6 +554,66 @@ smp_send_ici(int32 targetCPU, int32 message, uint32 data, uint32 data2, uint32 d } +void +smp_send_multicast_ici(cpu_mask_t cpuMask, int32 message, uint32 data, + uint32 data2, uint32 data3, void *data_ptr, uint32 flags) +{ + if (!sICIEnabled) + return; + + int currentCPU = smp_get_current_cpu(); + cpuMask &= ~((cpu_mask_t)1 << currentCPU); + if (cpuMask == 0) + return; + + // count target CPUs + int32 targetCPUs = 0; + for (int32 i = 0; i < sNumCPUs; i++) { + if ((cpuMask & (cpu_mask_t)1 << i) != 0) + targetCPUs++; + } + + // find_free_message leaves interrupts disabled + struct smp_msg *msg; + int state = find_free_message(&msg); + + msg->message = message; + msg->data = data; + msg->data2 = data2; + msg->data3 = data3; + msg->data_ptr = data_ptr; + msg->ref_count = targetCPUs; + msg->flags = flags; + msg->proc_bitmap = ~cpuMask; + msg->done = false; + + // stick it in the broadcast mailbox + acquire_spinlock_nocheck(&sBroadcastMessageSpinlock); + msg->next = sBroadcastMessages; + sBroadcastMessages = msg; + release_spinlock(&sBroadcastMessageSpinlock); + + arch_smp_send_broadcast_ici(); + // TODO: Introduce a call that only bothers the target CPUs! + + if (flags & SMP_MSG_FLAG_SYNC) { + // wait for the other cpus to finish processing it + // the interrupt handler will ref count it to <0 + // if the message is sync after it has removed it from the mailbox + while (msg->done == false) { + process_pending_ici(currentCPU); + PAUSE(); + } + + // for SYNC messages, it's our responsibility to put it + // back into the free list + return_free_message(msg); + } + + restore_interrupts(state); +} + + void smp_send_broadcast_ici(int32 message, uint32 data, uint32 data2, uint32 data3, void *data_ptr, uint32 flags) @@ -658,7 +718,7 @@ smp_cpu_rendezvous(volatile uint32 *var, int current_cpu) { atomic_or((vint32*)var, 1 << current_cpu); - while (*var != ((1 << sNumCPUs) - 1)) + while (*var != (((uint32)1 << sNumCPUs) - 1)) PAUSE(); }