Index: /trunk/src/VBox/VMM/HWACCMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/HWACCMInternal.h	(revision 19909)
+++ /trunk/src/VBox/VMM/HWACCMInternal.h	(revision 19910)
@@ -124,5 +124,5 @@
 
 /** Maximum number of page flushes we are willing to remember before considering a full TLB flush. */
-#define HWACCM_MAX_TLB_SHOOTDOWN_PAGES      16
+#define HWACCM_MAX_TLB_SHOOTDOWN_PAGES      8
 
 /** Size for the EPT identity page table (1024 4 MB pages to cover the entire address space). */
@@ -569,6 +569,9 @@
 
     /** To keep track of pending TLB shootdown pages. (SMP guest only) */
-    RTGCPTR                 aTlbShootdownPages[HWACCM_MAX_TLB_SHOOTDOWN_PAGES];
-    RTUINT                  cTlbShootdownPages;
+    struct
+    {
+        RTGCPTR             aPages[HWACCM_MAX_TLB_SHOOTDOWN_PAGES];
+        unsigned            cPages;
+    } TlbShootdown;
 
     RTUINT                  padding2[1];
Index: /trunk/src/VBox/VMM/VMMAll/HWACCMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/HWACCMAll.cpp	(revision 19909)
+++ /trunk/src/VBox/VMM/VMMAll/HWACCMAll.cpp	(revision 19910)
@@ -45,5 +45,5 @@
 
 /**
- * Invalidates a guest page
+ * Queues a page for invalidation
  *
  * @returns VBox status code.
@@ -51,6 +51,31 @@
  * @param   GCVirt      Page to invalidate
  */
+void hwaccmQueueInvlPage(PVMCPU pVCpu, RTGCPTR GCVirt)
+{
+    Assert(HWACCMIsEnabled(pVCpu->CTX_SUFF(pVM)));
+
+    /* Nothing to do if a TLB flush is already pending */
+    if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_TLB_FLUSH))
+        return;
+#if 1
+    VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
+#else
+    if (iPage == RT_ELEMENTS(pVCpu->hwaccm.s.TlbShootdown.aPages))
+        VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
+    else
+        VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
+#endif
+}
+
+/**
+ * Invalidates a guest page
+ *
+ * @returns VBox status code.
+ * @param   pVCpu       The VMCPU to operate on.
+ * @param   GCVirt      Page to invalidate
+ */
 VMMDECL(int) HWACCMInvalidatePage(PVMCPU pVCpu, RTGCPTR GCVirt)
 {
+    STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushPageManual);
 #ifdef IN_RING0
     PVM pVM = pVCpu->CTX_SUFF(pVM);
@@ -62,4 +87,5 @@
 #endif
 
+    hwaccmQueueInvlPage(pVCpu, GCVirt);
     return VINF_SUCCESS;
 }
@@ -90,6 +116,33 @@
 VMMDECL(int) HWACCMInvalidatePageOnAllVCpus(PVM pVM, RTGCPTR GCPtr)
 {
-    /* @todo */
-    HWACCMInvalidatePage(VMMGetCpu(pVM), GCPtr);
+    VMCPUID idCurCpu = VMMGetCpuId(pVM);
+
+    for (unsigned idCpu = 0; idCpu < pVM->cCPUs; idCpu++)
+    {
+        PVMCPU pVCpu = &pVM->aCpus[idCpu];
+
+        if (pVCpu->idCpu == idCurCpu)
+        {
+            HWACCMInvalidatePage(pVCpu, GCPtr);
+        }
+        else
+        {
+            hwaccmQueueInvlPage(pVCpu, GCPtr);
+            if (VMCPU_GET_STATE(pVCpu) == VMCPUSTATE_STARTED_EXEC)
+            {
+                STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
+#ifdef IN_RING0
+                RTCPUID idHostCpu = pVCpu->hwaccm.s.idEnteredCpu;
+                if (idHostCpu != NIL_RTCPUID)
+                    RTMpPokeCpu(idHostCpu);
+#else
+                VMR3NotifyCpuFFU(pVCpu->pUVCpu, VMNOTIFYFF_FLAGS_POKE);
+#endif
+            }
+            else
+                STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushPageManual);
+        }
+    }
+
     return VINF_SUCCESS;
 }
@@ -184,4 +237,5 @@
 
     Assert(pVM->hwaccm.s.svm.fSupported);
+    /* AMD-V doesn't support invalidation with guest physical addresses; see comment in SVMR0InvalidatePhysPage. */
     HWACCMFlushTLBOnAllVCpus(pVM);
 #else
Index: /trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp	(revision 19909)
+++ /trunk/src/VBox/VMM/VMMR0/HWSVMR0.cpp	(revision 19910)
@@ -1048,9 +1048,9 @@
             /* Deal with pending TLB shootdown actions which were queued when we were not executing code. */
             STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
-            for (unsigned i=0;i<pVCpu->hwaccm.s.cTlbShootdownPages;i++)
-                SVMR0InvlpgA(pVCpu->hwaccm.s.aTlbShootdownPages[i], pVMCB->ctrl.TLBCtrl.n.u32ASID);
-        }
-    }
-    pVCpu->hwaccm.s.cTlbShootdownPages = 0;
+            for (unsigned i=0;i<pVCpu->hwaccm.s.TlbShootdown.cPages;i++)
+                SVMR0InvlpgA(pVCpu->hwaccm.s.TlbShootdown.aPages[i], pVMCB->ctrl.TLBCtrl.n.u32ASID);
+        }
+    }
+    pVCpu->hwaccm.s.TlbShootdown.cPages = 0;
     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
 
@@ -2339,5 +2339,4 @@
         AssertMsgReturn(pVMCB, ("Invalid pVMCB\n"), VERR_EM_INTERNAL_ERROR);
 
-        STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatFlushPageManual);
 #if HC_ARCH_BITS == 32
         /* If we get a flush in 64 bits guest mode, then force a full TLB flush. Invlpga takes only 32 bits addresses. */
Index: /trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp	(revision 19909)
+++ /trunk/src/VBox/VMM/VMMR0/HWVMXR0.cpp	(revision 19910)
@@ -1798,5 +1798,5 @@
     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_FLUSH);
     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
-    pVCpu->hwaccm.s.cTlbShootdownPages = 0;
+    pVCpu->hwaccm.s.TlbShootdown.cPages = 0;
     return;
 }
@@ -1846,11 +1846,12 @@
         /* Deal with pending TLB shootdown actions which were queued when we were not executing code. */
         STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
-        for (unsigned i=0;i<pVCpu->hwaccm.s.cTlbShootdownPages;i++)
+
+        for (unsigned i=0;i<pVCpu->hwaccm.s.TlbShootdown.cPages;i++)
         {
             /* aTlbShootdownPages contains physical addresses in this case. */
-            vmxR0FlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushContext, pVCpu->hwaccm.s.aTlbShootdownPages[i]);
-        }
-    }
-    pVCpu->hwaccm.s.cTlbShootdownPages = 0;
+            vmxR0FlushEPT(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushContext, pVCpu->hwaccm.s.TlbShootdown.aPages[i]);
+        }
+    }
+    pVCpu->hwaccm.s.TlbShootdown.cPages= 0;
     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
 
@@ -1926,9 +1927,9 @@
             /* Deal with pending TLB shootdown actions which were queued when we were not executing code. */
             STAM_COUNTER_INC(&pVCpu->hwaccm.s.StatTlbShootdown);
-            for (unsigned i=0;i<pVCpu->hwaccm.s.cTlbShootdownPages;i++)
-                vmxR0FlushVPID(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushContext, pVCpu->hwaccm.s.aTlbShootdownPages[i]);
-        }
-    }
-    pVCpu->hwaccm.s.cTlbShootdownPages = 0;
+            for (unsigned i=0;i<pVCpu->hwaccm.s.TlbShootdown.cPages;i++)
+                vmxR0FlushVPID(pVM, pVCpu, pVM->hwaccm.s.vmx.enmFlushContext, pVCpu->hwaccm.s.TlbShootdown.aPages[i]);
+        }
+    }
+    pVCpu->hwaccm.s.TlbShootdown.cPages = 0;
     VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TLB_SHOOTDOWN);
 
