Index: trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp	(revision 53717)
+++ trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp	(revision 53718)
@@ -58,9 +58,9 @@
 /** HalRequestIpi, introduced in ??. */
 PFNHALREQUESTIPI                    g_pfnrtNtHalRequestIpi;
-/** HalSendSoftwareInterrupt */
+/** HalSendSoftwareInterrupt, introduced in AMD64 version of W2K3. */
 PFNHALSENDSOFTWAREINTERRUPT         g_pfnrtNtHalSendSoftwareInterrupt;
-/** SendIpi handler based on Windows version */
-PFNRTSENDIPI                        g_pfnrtSendIpi;
-/** KeIpiGenericCall - Windows Server 2003+ only */
+/** Worker for RTMpPokeCpu. */
+PFNRTSENDIPI                        g_pfnrtMpPokeCpuWorker;
+/** KeIpiGenericCall - Introduced in Windows Server 2003. */
 PFNRTKEIPIGENERICCALL               g_pfnrtKeIpiGenericCall;
 /** RtlGetVersion, introduced in ??. */
@@ -386,23 +386,18 @@
 
     /*
-     * Special IPI fun.
-     */
-    g_pfnrtSendIpi = rtMpSendIpiDummy;
+     * Special IPI fun for RTMpPokeCpu.
+     *
+     * On Vista and later the DPC fallback doesn't seem to reliably send IPIs,
+     * so we have to use alternative methods.  The NtHalSendSoftwareInterrupt
+     * is preferrable, but if that's not available we'll settle for broadcast
+     * IPIs.
+     */
+    g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingDpc;
 #ifndef IPRT_TARGET_NT4
-    if (    g_pfnrtNtHalRequestIpi
-        &&  OsVerInfo.uMajorVer == 6
-        &&  OsVerInfo.uMinorVer == 0)
-    {
-        /* Vista or Windows Server 2008 */
-        g_pfnrtSendIpi = rtMpSendIpiVista;
-    }
-    else if (   g_pfnrtNtHalSendSoftwareInterrupt
-             && OsVerInfo.uMajorVer == 6
-             && OsVerInfo.uMinorVer == 1)
-    {
-        /* Windows 7 or Windows Server 2008 R2 */
-        g_pfnrtSendIpi = rtMpSendIpiWin7;
-    }
-    /* Windows XP should send always send an IPI -> VERIFY */
+    if (g_pfnrtNtHalSendSoftwareInterrupt)
+        g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalSendSoftwareInterrupt;
+    else if (OsVerInfo.uMajorVer >= 6 && g_pfnrtKeIpiGenericCall)
+        g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingBroadcastIpi;
+    /* else: Windows XP should send always send an IPI -> VERIFY */
 #endif
 
Index: trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h	(revision 53717)
+++ trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h	(revision 53718)
@@ -58,5 +58,5 @@
 extern PFNHALREQUESTIPI                 g_pfnrtNtHalRequestIpi;
 extern PFNHALSENDSOFTWAREINTERRUPT      g_pfnrtNtHalSendSoftwareInterrupt;
-extern PFNRTSENDIPI                     g_pfnrtSendIpi;
+extern PFNRTSENDIPI                     g_pfnrtMpPokeCpuWorker;
 extern PFNRTKEIPIGENERICCALL            g_pfnrtKeIpiGenericCall;
 extern PFNRTRTLGETVERSION               g_pfnrtRtlGetVersion;
@@ -72,7 +72,7 @@
 
 
-int rtMpSendIpiVista(RTCPUID idCpu);
-int rtMpSendIpiWin7(RTCPUID idCpu);
-int rtMpSendIpiDummy(RTCPUID idCpu);
+int rtMpPokeCpuUsingDpc(RTCPUID idCpu);
+int rtMpPokeCpuUsingBroadcastIpi(RTCPUID idCpu);
+int rtMpPokeCpuUsingHalSendSoftwareInterrupt(RTCPUID idCpu);
 
 RT_C_DECLS_END
Index: trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp
===================================================================
--- trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp	(revision 53717)
+++ trunk/src/VBox/Runtime/r0drv/nt/mp-r0drv-nt.cpp	(revision 53718)
@@ -188,28 +188,58 @@
 
 /**
- * Wrapper between the native nt per-cpu callbacks and PFNRTWORKER
- *
- * @param   Dpc                 DPC object
- * @param   DeferredContext     Context argument specified by KeInitializeDpc
- * @param   SystemArgument1     Argument specified by KeInsertQueueDpc
- * @param   SystemArgument2     Argument specified by KeInsertQueueDpc
- */
-static VOID rtmpNtDPCWrapper(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
-{
-    PRTMPARGS pArgs = (PRTMPARGS)DeferredContext;
-    ASMAtomicIncU32(&pArgs->cHits);
-
+ * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
+ * the RTMpOnAll case.
+ *
+ * @param   uUserCtx            The user context argument (PRTMPARGS).
+ */
+static ULONG_PTR __stdcall rtmpNtOnAllBroadcastIpiWrapper(ULONG_PTR uUserCtx)
+{
+    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
+    /*ASMAtomicIncU32(&pArgs->cHits); - not needed */
     pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
-
-    /* Dereference the argument structure. */
-    int32_t cRefs = ASMAtomicDecS32(&pArgs->cRefs);
-    Assert(cRefs >= 0);
-    if (cRefs == 0)
-        ExFreePool(pArgs);
+    return 0;
 }
 
 
 /**
- * Internal worker for the RTMpOn* APIs.
+ * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
+ * the RTMpOnOthers case.
+ *
+ * @param   uUserCtx            The user context argument (PRTMPARGS).
+ */
+static ULONG_PTR __stdcall rtmpNtOnOthersBroadcastIpiWrapper(ULONG_PTR uUserCtx)
+{
+    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
+    RTCPUID idCpu = KeGetCurrentProcessorNumber();
+    if (pArgs->idCpu != idCpu)
+    {
+        /*ASMAtomicIncU32(&pArgs->cHits); - not needed */
+        pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+    }
+    return 0;
+}
+
+
+/**
+ * Wrapper between the native KIPI_BROADCAST_WORKER and IPRT's PFNRTMPWORKER for
+ * the RTMpOnSpecific case.
+ *
+ * @param   uUserCtx            The user context argument (PRTMPARGS).
+ */
+static ULONG_PTR __stdcall rtmpNtOnSpecificBroadcastIpiWrapper(ULONG_PTR uUserCtx)
+{
+    PRTMPARGS pArgs = (PRTMPARGS)uUserCtx;
+    RTCPUID idCpu = KeGetCurrentProcessorNumber();
+    if (pArgs->idCpu == idCpu)
+    {
+        ASMAtomicIncU32(&pArgs->cHits);
+        pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
+    }
+    return 0;
+}
+
+
+/**
+ * Internal worker for the RTMpOn* APIs using KeIpiGenericCall.
  *
  * @returns IPRT status code.
@@ -220,5 +250,59 @@
  * @param   idCpu           Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
  */
-static int rtMpCall(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu)
+static int rtMpCallUsingBroadcastIpi(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2,
+                                     PKIPI_BROADCAST_WORKER pfnNativeWrapper, RTCPUID idCpu)
+{
+    RTMPARGS Args;
+    Args.pfnWorker = pfnWorker;
+    Args.pvUser1   = pvUser1;
+    Args.pvUser2   = pvUser2;
+    Args.idCpu     = idCpu;
+    Args.cRefs     = 0;
+    Args.cHits     = 0;
+
+    AssertPtr(g_pfnrtKeIpiGenericCall);
+    g_pfnrtKeIpiGenericCall(pfnNativeWrapper, (uintptr_t)&Args);
+
+    if (   pfnNativeWrapper != rtmpNtOnSpecificBroadcastIpiWrapper
+        || Args.cHits > 0)
+        return VINF_SUCCESS;
+    return VERR_CPU_OFFLINE;
+}
+
+
+/**
+ * Wrapper between the native nt per-cpu callbacks and PFNRTWORKER
+ *
+ * @param   Dpc                 DPC object
+ * @param   DeferredContext     Context argument specified by KeInitializeDpc
+ * @param   SystemArgument1     Argument specified by KeInsertQueueDpc
+ * @param   SystemArgument2     Argument specified by KeInsertQueueDpc
+ */
+static VOID __stdcall rtmpNtDPCWrapper(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
+{
+    PRTMPARGS pArgs = (PRTMPARGS)DeferredContext;
+    ASMAtomicIncU32(&pArgs->cHits);
+
+    pArgs->pfnWorker(KeGetCurrentProcessorNumber(), pArgs->pvUser1, pArgs->pvUser2);
+
+    /* Dereference the argument structure. */
+    int32_t cRefs = ASMAtomicDecS32(&pArgs->cRefs);
+    Assert(cRefs >= 0);
+    if (cRefs == 0)
+        ExFreePool(pArgs);
+}
+
+
+/**
+ * Internal worker for the RTMpOn* APIs.
+ *
+ * @returns IPRT status code.
+ * @param   pfnWorker       The callback.
+ * @param   pvUser1         User argument 1.
+ * @param   pvUser2         User argument 2.
+ * @param   enmCpuid        What to do / is idCpu valid.
+ * @param   idCpu           Used if enmCpuid RT_NT_CPUID_SPECIFIC, otherwise ignored.
+ */
+static int rtMpCallUsingDpcs(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2, RT_NT_CPUID enmCpuid, RTCPUID idCpu)
 {
     PRTMPARGS pArgs;
@@ -331,5 +415,7 @@
 RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
 {
-    return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, 0);
+    if (g_pfnrtKeIpiGenericCall)
+        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnAllBroadcastIpiWrapper, 0);
+    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_ALL, 0);
 }
 
@@ -337,5 +423,7 @@
 RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
 {
-    return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, 0);
+    if (g_pfnrtKeIpiGenericCall)
+        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnOthersBroadcastIpiWrapper, 0);
+    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_OTHERS, 0);
 }
 
@@ -348,9 +436,11 @@
               : VERR_CPU_OFFLINE;
 
-    return rtMpCall(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
-}
-
-static KDPC aPokeDpcs[MAXIMUM_PROCESSORS] = {0};
-static bool fPokeDPCsInitialized = false;
+    if (g_pfnrtKeIpiGenericCall)
+        return rtMpCallUsingBroadcastIpi(pfnWorker, pvUser1, pvUser2, rtmpNtOnSpecificBroadcastIpiWrapper, 0);
+    return rtMpCallUsingDpcs(pfnWorker, pvUser1, pvUser2, RT_NT_CPUID_SPECIFIC, idCpu);
+}
+
+
+
 
 static VOID rtMpNtPokeCpuDummy(IN PKDPC Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
@@ -364,5 +454,5 @@
 #ifndef IPRT_TARGET_NT4
 
-ULONG_PTR rtMpIpiGenericCall(ULONG_PTR Argument)
+static ULONG_PTR __stdcall rtMpIpiGenericCall(ULONG_PTR Argument)
 {
     NOREF(Argument);
@@ -371,16 +461,24 @@
 
 
+int rtMpPokeCpuUsingBroadcastIpi(RTCPUID idCpu)
+{
+    g_pfnrtKeIpiGenericCall(rtMpIpiGenericCall, 0);
+    return VINF_SUCCESS;
+}
+
+# if 0
 int rtMpSendIpiVista(RTCPUID idCpu)
 {
+    /* If we start care about Vista, we should investigate a non-broadcast API. */
     g_pfnrtKeIpiGenericCall(rtMpIpiGenericCall, 0);
 ////    g_pfnrtNtHalRequestIpi(1 << idCpu);
     return VINF_SUCCESS;
 }
-
-
-int rtMpSendIpiWin7(RTCPUID idCpu)
-{
-    g_pfnrtKeIpiGenericCall(rtMpIpiGenericCall, 0);
-////    g_pfnrtNtHalSendSoftwareInterrupt(idCpu, DISPATCH_LEVEL);
+# endif
+
+
+int rtMpPokeCpuUsingHalSendSoftwareInterrupt(RTCPUID idCpu)
+{
+    g_pfnrtNtHalSendSoftwareInterrupt(idCpu, DISPATCH_LEVEL);
     return VINF_SUCCESS;
 }
@@ -389,31 +487,21 @@
 
 
-int rtMpSendIpiDummy(RTCPUID idCpu)
-{
-    return VERR_NOT_IMPLEMENTED;
-}
-
-
-RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
-{
-    if (!RTMpIsCpuOnline(idCpu))
-        return !RTMpIsCpuPossible(idCpu)
-              ? VERR_CPU_NOT_FOUND
-              : VERR_CPU_OFFLINE;
-
-    int rc = g_pfnrtSendIpi(idCpu);
-    if (rc == VINF_SUCCESS)
-        return rc;
-
-    /* Fallback. */
-    if (!fPokeDPCsInitialized)
-    {
-        for (unsigned i = 0; i < RT_ELEMENTS(aPokeDpcs); i++)
+int rtMpPokeCpuUsingDpc(RTCPUID idCpu)
+{
+    /*
+     * APC fallback.
+     */
+    static KDPC s_aPokeDpcs[MAXIMUM_PROCESSORS] = {0};
+    static bool s_fPokeDPCsInitialized = false;
+
+    if (!s_fPokeDPCsInitialized)
+    {
+        for (unsigned i = 0; i < RT_ELEMENTS(s_aPokeDpcs); i++)
         {
-            KeInitializeDpc(&aPokeDpcs[i], rtMpNtPokeCpuDummy, NULL);
-            KeSetImportanceDpc(&aPokeDpcs[i], HighImportance);
-            KeSetTargetProcessorDpc(&aPokeDpcs[i], (int)i);
+            KeInitializeDpc(&s_aPokeDpcs[i], rtMpNtPokeCpuDummy, NULL);
+            KeSetImportanceDpc(&s_aPokeDpcs[i], HighImportance);
+            KeSetTargetProcessorDpc(&s_aPokeDpcs[i], (int)i);
         }
-        fPokeDPCsInitialized = true;
+        s_fPokeDPCsInitialized = true;
     }
 
@@ -424,11 +512,11 @@
     KeRaiseIrql(DISPATCH_LEVEL, &oldIrql);
 
-    KeSetImportanceDpc(&aPokeDpcs[idCpu], HighImportance);
-    KeSetTargetProcessorDpc(&aPokeDpcs[idCpu], (int)idCpu);
+    KeSetImportanceDpc(&s_aPokeDpcs[idCpu], HighImportance);
+    KeSetTargetProcessorDpc(&s_aPokeDpcs[idCpu], (int)idCpu);
 
     /* Assuming here that high importance DPCs will be delivered immediately; or at least an IPI will be sent immediately.
      * @note: not true on at least Vista & Windows 7
      */
-    BOOLEAN bRet = KeInsertQueueDpc(&aPokeDpcs[idCpu], 0, 0);
+    BOOLEAN bRet = KeInsertQueueDpc(&s_aPokeDpcs[idCpu], 0, 0);
 
     KeLowerIrql(oldIrql);
@@ -437,4 +525,15 @@
 
 
+RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
+{
+    if (!RTMpIsCpuOnline(idCpu))
+        return !RTMpIsCpuPossible(idCpu)
+              ? VERR_CPU_NOT_FOUND
+              : VERR_CPU_OFFLINE;
+    /* Calls rtMpSendIpiFallback, rtMpSendIpiWin7AndLater or rtMpSendIpiVista. */
+    return g_pfnrtMpPokeCpuWorker(idCpu);
+}
+
+
 RTDECL(bool) RTMpOnAllIsConcurrentSafe(void)
 {
