Index: /trunk/include/VBox/gmm.h
===================================================================
--- /trunk/include/VBox/gmm.h	(revision 29423)
+++ /trunk/include/VBox/gmm.h	(revision 29424)
@@ -31,5 +31,5 @@
 #include <VBox/sup.h>
 #include <VBox/VMMDev.h> /* for VMMDEVSHAREDREGIONDESC */
-
+#include <iprt/avl.h>
 RT_C_DECLS_BEGIN
 
@@ -279,4 +279,5 @@
 #endif
 
+
 GMMR0DECL(int)  GMMR0Init(void);
 GMMR0DECL(void) GMMR0Term(void);
@@ -297,4 +298,5 @@
 GMMR0DECL(int)  GMMR0UnregisterSharedModule(PVM pVM, VMCPUID idCpu, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule);
 GMMR0DECL(int)  GMMR0UnregisterAllSharedModules(PVM pVM, VMCPUID idCpu);
+GMMR0DECL(int)  GMMR0CheckSharedModules(PVM pVM, VMCPUID idCpu);
 GMMR0DECL(int)  GMMR0ResetSharedModules(PVM pVM, VMCPUID idCpu);
 
@@ -495,4 +497,47 @@
 
 /**
+ * Shared region descriptor
+ */
+typedef struct GMMSHAREDREGIONDESC
+{
+    /** Region base address. */
+    RTGCPTR64           GCRegionAddr;
+    /** Region size. */
+    uint32_t            cbRegion;
+    /** Alignment. */
+    uint32_t            u32Alignment;
+    /** Pointer to physical page id array. */
+    uint32_t           *paHCPhysPageID;
+} GMMSHAREDREGIONDESC;
+/** Pointer to a GMMSHAREDREGIONDESC. */
+typedef GMMSHAREDREGIONDESC *PGMMSHAREDREGIONDESC;
+
+
+/**
+ * Shared module registration info (global)
+ */
+typedef struct GMMSHAREDMODULE
+{
+    /* Tree node. */
+    AVLGCPTRNODECORE            Core;
+    /** Shared module size. */
+    uint32_t                    cbModule;
+    /** Number of included region descriptors */
+    uint32_t                    cRegions;
+    /** Number of users (VMs). */
+    uint32_t                    cUsers;
+    /** Guest OS family type. */
+    VBOXOSFAMILY                enmGuestOS;
+    /** Module name */
+    char                        szName[GMM_SHARED_MODULE_MAX_NAME_STRING];
+    /** Module version */
+    char                        szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING];
+    /** Shared region descriptor(s). */
+    GMMSHAREDREGIONDESC         aRegions[1];
+} GMMSHAREDMODULE;
+/** Pointer to a GMMSHAREDMODULE. */
+typedef GMMSHAREDMODULE *PGMMSHAREDMODULE;
+
+/**
  * Page descriptor for GMMR0SharedModuleCheckRange
  */
@@ -511,5 +556,5 @@
 typedef GMMSHAREDPAGEDESC *PGMMSHAREDPAGEDESC;
 
-GMMR0DECL(int) GMMR0SharedModuleCheckRange(PVM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc);
+GMMR0DECL(int) GMMR0SharedModuleCheckRange(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc);
 
 /**
@@ -562,5 +607,6 @@
 GMMR3DECL(int)  GMMR3BalloonedPages(PVM pVM, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages);
 GMMR3DECL(int)  GMMR3RegisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq);
-GMMR3DECL(int)  GMMR3UnregisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq);
+GMMR3DECL(int)  GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq);
+GMMR3DECL(int)  GMMR3CheckSharedModules(PVM pVM);
 GMMR3DECL(int)  GMMR3ResetSharedModules(PVM pVM);
 /** @} */
Index: /trunk/include/VBox/pgm.h
===================================================================
--- /trunk/include/VBox/pgm.h	(revision 29423)
+++ /trunk/include/VBox/pgm.h	(revision 29424)
@@ -433,5 +433,5 @@
 VMMR0DECL(int)      PGMR0PhysAllocateHandyPages(PVM pVM, PVMCPU pVCpu);
 VMMR0DECL(int)      PGMR0PhysAllocateLargeHandyPage(PVM pVM, PVMCPU pVCpu);
-VMMR0DECL(int)      PGMR0SharedModuleCheck(PVM pVM, PVMCPU pVCpu, PGMMREGISTERSHAREDMODULEREQ pReq);
+VMMR0DECL(int)      PGMR0SharedModuleCheckRegion(PVM pVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, PGVM pGVM);
 VMMR0DECL(int)      PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPHYS pvFault);
 # ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
@@ -569,4 +569,5 @@
 VMMR3DECL(int)     PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule, unsigned cRegions, VMMDEVSHAREDREGIONDESC *pRegions);
 VMMR3DECL(int)     PGMR3SharedModuleUnregister(PVM pVM, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule);
+VMMR3DECL(int)     PGMR3SharedModuleCheckAll(PVM pVM);
 /** @} */
 
Index: /trunk/include/VBox/vmm.h
===================================================================
--- /trunk/include/VBox/vmm.h	(revision 29423)
+++ /trunk/include/VBox/vmm.h	(revision 29424)
@@ -285,6 +285,4 @@
     /** Call PGMR0AllocateLargePage(). */
     VMMR0_DO_PGM_ALLOCATE_LARGE_HANDY_PAGE,
-    /** Call PGMR0CheckSharedModule(). */
-    VMMR0_DO_PGM_CHECK_SHARED_MODULE,
 
     /** Call GMMR0InitialReservation(). */
@@ -314,4 +312,6 @@
     /** Call GMMR0ResetSharedModules. */
     VMMR0_DO_GMM_RESET_SHARED_MODULES,
+    /** Call GMMR0CheckSharedModules. */
+    VMMR0_DO_GMM_CHECK_SHARED_MODULES,
 
     /** Set a GVMM or GMM configuration value. */
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp	(revision 29423)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp	(revision 29424)
@@ -299,4 +299,7 @@
     /* Delete leftover modules in the old tree. */
     RTAvlPVDestroy(&pKnownModuleTree, VBoxServicePageSharingEmptyTreeCallback, NULL);
+
+    /* Check all registered modules. */
+    VbglR3CheckSharedModules();
 
     /* Activate new module tree. */
Index: /trunk/src/VBox/VMM/GMM.cpp
===================================================================
--- /trunk/src/VBox/VMM/GMM.cpp	(revision 29423)
+++ /trunk/src/VBox/VMM/GMM.cpp	(revision 29424)
@@ -391,5 +391,5 @@
  * @see GMMR0RegisterSharedModule
  */
-GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)
+GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq)
 {
     pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
@@ -405,2 +405,10 @@
     return VMMR3CallR0(pVM, VMMR0_DO_GMM_RESET_SHARED_MODULES, 0, NULL);
 }
+
+/**
+ * @see GMMR0CheckSharedModules
+ */
+GMMR3DECL(int)  GMMR3CheckSharedModules(PVM pVM)
+{
+    return VMMR3CallR0(pVM, VMMR0_DO_GMM_CHECK_SHARED_MODULES, 0, NULL);
+}
Index: /trunk/src/VBox/VMM/PGMSharedPage.cpp
===================================================================
--- /trunk/src/VBox/VMM/PGMSharedPage.cpp	(revision 29423)
+++ /trunk/src/VBox/VMM/PGMSharedPage.cpp	(revision 29424)
@@ -35,88 +35,4 @@
 #include <iprt/mem.h>
 
-
-#ifdef VBOX_WITH_PAGE_SHARING
-/**
- * Rendezvous callback that will be called once.
- *
- * @returns VBox strict status code.
- * @param   pVM                 VM handle.
- * @param   pVCpu               The VMCPU handle for the calling EMT.
- * @param   pvUser              PGMMREGISTERSHAREDMODULEREQ
- */
-static DECLCALLBACK(VBOXSTRICTRC) pgmR3SharedModuleRegRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
-{
-    PGMMREGISTERSHAREDMODULEREQ pReq = (PGMMREGISTERSHAREDMODULEREQ)pvUser;
-
-    return VMMR3CallR0(pVM, VMMR0_DO_PGM_CHECK_SHARED_MODULE, 0, &pReq->Hdr);
-}
-
-/**
- * Shared module registration helper (called on the way out).
- *
- * @param   pVM         The VM handle.
- * @param   pReq        Registration request info
- */
-static DECLCALLBACK(void) pgmR3SharedModuleRegisterHelper(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)
-{
-    int rc;
-    
-    rc = GMMR3RegisterSharedModule(pVM, pReq);
-    Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED);
-    if (rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED)
-    {
-        PVMCPU   pVCpu = VMMGetCpu(pVM);
-        unsigned cFlushedPages = 0;
-
-        /** todo count copy-on-write actions in the trap handler so we don't have to check everything all the time! */
-
-        /* Count the number of shared pages that were changed (copy-on-write). */
-        for (unsigned i = 0; i < pReq->cRegions; i++)
-        {
-            Assert((pReq->aRegions[i].cbRegion & 0xfff) == 0);
-            Assert((pReq->aRegions[i].GCRegionAddr & 0xfff) == 0);
-
-            RTGCPTR GCRegion  = pReq->aRegions[i].GCRegionAddr;
-            uint32_t cbRegion = pReq->aRegions[i].cbRegion & ~0xfff;
-
-            while (cbRegion)
-            {
-                RTGCPHYS GCPhys;
-                uint64_t fFlags;
-
-                rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys);
-                if (    rc == VINF_SUCCESS
-                    &&  !(fFlags & X86_PTE_RW))
-                {
-                    PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
-                    if (    pPage
-                        &&  !PGM_PAGE_IS_SHARED(pPage))
-                    {
-                        cFlushedPages++;
-                    }
-                }
-
-                GCRegion += PAGE_SIZE;
-                cbRegion -= PAGE_SIZE;
-            }
-        }
-
-        if (cFlushedPages > 32)
-            rc = VINF_SUCCESS;  /* force recheck below */
-    }
-    /* Full (re)check needed? */
-    if (rc == VINF_SUCCESS)
-    {
-        pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
-        pReq->Hdr.cbReq = RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]);
-
-        /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */
-        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, pReq);
-        AssertRC(rc);
-    }
-    RTMemFree(pReq);
-    return;
-}
-#endif
 
 /**
@@ -161,28 +77,14 @@
     }
 
-    /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */
-    return VMR3ReqCallNoWait(pVM, VMMGetCpuId(pVM), (PFNRT)pgmR3SharedModuleRegisterHelper, 2, pVM, pReq);
+    int rc = GMMR3RegisterSharedModule(pVM, pReq);
+    RTMemFree(pReq);
+    Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED);
+    if (RT_FAILURE(rc))
+        return rc;
+    return VINF_SUCCESS;
 #else
     return VERR_NOT_IMPLEMENTED;
 #endif
 }
-
-
-#ifdef VBOX_WITH_PAGE_SHARING
-/**
- * Shared module unregistration helper (called on the way out).
- *
- * @param   pVM         The VM handle.
- * @param   pReq        Unregistration request info
- */
-static DECLCALLBACK(void) pgmR3SharedModuleUnregisterHelper(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)
-{
-    int rc;
-    
-    rc = GMMR3UnregisterSharedModule(pVM, pReq);
-    RTMemFree(pReq);
-    return;
-}
-#endif
 
 /**
@@ -212,10 +114,55 @@
         ||  RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion) != VINF_SUCCESS)
     {
+        RTMemFree(pReq);
         return VERR_BUFFER_OVERFLOW;
     }
-    /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */
-    return VMR3ReqCallNoWait(pVM, VMMGetCpuId(pVM), (PFNRT)pgmR3SharedModuleUnregisterHelper, 2, pVM, pReq);
+    int rc = GMMR3UnregisterSharedModule(pVM, pReq);
+    RTMemFree(pReq);
+    return rc;
 #else 
     return VERR_NOT_IMPLEMENTED;
 #endif
 }
+
+#ifdef VBOX_WITH_PAGE_SHARING
+/**
+ * Rendezvous callback that will be called once.
+ *
+ * @returns VBox strict status code.
+ * @param   pVM                 VM handle.
+ * @param   pVCpu               The VMCPU handle for the calling EMT.
+ * @param   pvUser              Not used;
+ */
+static DECLCALLBACK(VBOXSTRICTRC) pgmR3SharedModuleRegRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
+{
+    return GMMR3CheckSharedModules(pVM);
+}
+
+/**
+ * Shared module unregistration helper (called on the way out).
+ *
+ * @param   pVM         The VM handle.
+ */
+static DECLCALLBACK(void) pgmR3CheckSharedModulesHelper(PVM pVM)
+{   
+    /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */
+    int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, NULL);
+    AssertRC(rc);
+}
+#endif
+
+/**
+ * Check all registered modules for changes.
+ *
+ * @returns VBox status code.
+ * @param   pVM                 VM handle
+ */
+VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM)
+{
+#ifdef VBOX_WITH_PAGE_SHARING
+    /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */
+    return VMR3ReqCallNoWait(pVM, VMMGetCpuId(pVM), (PFNRT)pgmR3CheckSharedModulesHelper, 1, pVM);
+#else 
+    return VERR_NOT_IMPLEMENTED;
+#endif
+}
Index: /trunk/src/VBox/VMM/VMMR0/GMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/GMMR0.cpp	(revision 29423)
+++ /trunk/src/VBox/VMM/VMMR0/GMMR0.cpp	(revision 29424)
@@ -154,4 +154,5 @@
 #include "GMMR0Internal.h"
 #include <VBox/gvm.h>
+#include <VBox/pgm.h>
 #include <VBox/log.h>
 #include <VBox/param.h>
@@ -3718,18 +3719,193 @@
  *
  * @returns VBox status code.
- * @param   pVM                 VM handle
- * @param   idCpu               VCPU id
- * @param   pReq                Module description
+ * @param   pGMM                Pointer to the GMM instance data.
+ * @param   pGVM                Pointer to the GVM instance data.
+ * @param   pModule             Module description
  * @param   idxRegion           Region index
  * @param   cPages              Number of entries in the paPageDesc array
  * @param   paPageDesc          Page descriptor array (in/out)
  */
-GMMR0DECL(int) GMMR0SharedModuleCheckRange(PVM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc)
-{
-    AssertReturn(idxRegion < pReq->cRegions, VERR_INVALID_PARAMETER);
-    AssertReturn(cPages == (pReq->aRegions[idxRegion].cbRegion >> PAGE_SHIFT), VERR_INVALID_PARAMETER);
-
-    Log(("GMMR0SharedModuleCheckRange %s base %RGv region %d cPages %d\n", pReq->szName, pReq->GCBaseAddr, idxRegion, cPages));
-
+GMMR0DECL(int) GMMR0SharedModuleCheckRange(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc)
+{
+    int rc = VINF_SUCCESS;
+    PGMM pGMM;
+    GMM_GET_VALID_INSTANCE(pGMM, VERR_INTERNAL_ERROR);
+
+    AssertReturn(idxRegion < pModule->cRegions, VERR_INVALID_PARAMETER);
+    AssertReturn(cPages == (pModule->aRegions[idxRegion].cbRegion >> PAGE_SHIFT), VERR_INVALID_PARAMETER);
+
+    Log(("GMMR0SharedModuleCheckRange %s base %RGv region %d cPages %d\n", pModule->szName, pModule->Core.Key, idxRegion, cPages));
+
+    PGMMSHAREDREGIONDESC pGlobalRegion = &pModule->aRegions[idxRegion];
+
+    if (!pGlobalRegion->paHCPhysPageID)
+    {
+        /* First time; create a page descriptor array. */
+        Log(("Allocate page descriptor array for %d pages\n", cPages));
+        pGlobalRegion->paHCPhysPageID = (uint32_t *)RTMemAlloc(cPages * sizeof(*pGlobalRegion->paHCPhysPageID));
+        if (!pGlobalRegion->paHCPhysPageID)
+        {
+            AssertFailed();
+            rc = VERR_NO_MEMORY;
+            goto end;
+        }
+        /* Invalidate all descriptors. */
+        for (unsigned i = 0; i < cPages; i++)
+            pGlobalRegion->paHCPhysPageID[i] = NIL_GMM_PAGEID;
+    }
+
+    /* Check all pages in the region. */
+    for (unsigned i = 0; i < cPages; i++)
+    {
+        /* Valid page present? */
+        if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID)
+        {
+            /* We've seen this shared page for the first time? */
+            if (pGlobalRegion->paHCPhysPageID[i] == NIL_GMM_PAGEID)
+            {
+                /* Easy case: just change the internal page type. */
+                PGMMPAGE pPage = gmmR0GetPage(pGMM, paPageDesc[i].uHCPhysPageId);
+                if (!pPage)
+                {
+                    AssertFailed();
+                    rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
+                    goto end;
+                }
+                Log(("New shared page guest %RGp host %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys));
+
+                AssertMsg(paPageDesc[i].GCPhys == (pPage->Private.pfn << 12), ("desc %RGp gmm %RGp\n", paPageDesc[i].HCPhys, (pPage->Private.pfn << 12)));
+
+                gmmR0ConvertToSharedPage(pGMM, pGVM, paPageDesc[i].HCPhys, paPageDesc[i].uHCPhysPageId, pPage);
+
+                /* Keep track of these references. */
+                pGlobalRegion->paHCPhysPageID[i] = paPageDesc[i].uHCPhysPageId;
+            }
+            else
+            {
+                uint8_t  *pbLocalPage, *pbSharedPage;
+                uint8_t  *pbChunk;
+                PGMMCHUNK pChunk;
+
+                Assert(paPageDesc[i].uHCPhysPageId != pGlobalRegion->paHCPhysPageID[i]);
+
+                /* Get the shared page source. */
+                PGMMPAGE pPage = gmmR0GetPage(pGMM, pGlobalRegion->paHCPhysPageID[i]);
+                if (!pPage)
+                {
+                    AssertFailed();
+                    rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
+                    goto end;
+                }
+                Assert(pPage->Common.u2State == GMM_PAGE_STATE_SHARED);
+
+                Log(("Replace existing page guest %RGp host %RHp -> %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys, pPage->Shared.pfn << PAGE_SHIFT));
+
+                /* Calculate the virtual address of the local page. */
+                pChunk = gmmR0GetChunk(pGMM, paPageDesc[i].uHCPhysPageId >> GMM_CHUNKID_SHIFT);
+                if (pChunk)
+                {
+                    if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk))
+                    {
+                        AssertFailed();
+                        rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
+                        goto end;
+                    }
+                    pbLocalPage = pbChunk + ((paPageDesc[i].uHCPhysPageId & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT);
+                }
+                else
+                {
+                    AssertFailed();
+                    rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
+                    goto end;
+                }
+
+                /* Calculate the virtual address of the shared page. */
+                pChunk = gmmR0GetChunk(pGMM, pGlobalRegion->paHCPhysPageID[i] >> GMM_CHUNKID_SHIFT);
+                Assert(pChunk); /* can't fail as gmmR0GetPage succeeded. */
+
+                /* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */
+                if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk))
+                {
+                    rc = gmmR0MapChunk(pGMM, pGVM, pChunk, (PRTR3PTR)&pbChunk);
+                    if (rc != VINF_SUCCESS)
+                    {
+                        AssertRC(rc);
+                        goto end;
+                    }
+                }
+                pbSharedPage = pbChunk + ((pGlobalRegion->paHCPhysPageID[i] & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT);
+
+                /** todo write ASMMemComparePage. */
+                if (memcmp(pbSharedPage, pbLocalPage, PAGE_SIZE))
+                {
+                    Log(("Unexpected differences found between local and shared page; skip\n"));
+                    /* Signal to the caller that this one hasn't changed. */
+                    paPageDesc[i].uHCPhysPageId = NIL_GMM_PAGEID;
+                    continue;
+                }
+
+                /* Free the old local page. */
+                GMMFREEPAGEDESC PageDesc;
+
+                PageDesc.idPage = paPageDesc[i].uHCPhysPageId;
+                rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE);
+                AssertRC(rc);
+
+                gmmR0UseSharedPage(pGMM, pGVM, pPage);
+
+                /* Pass along the new physical address & page id. */
+                paPageDesc[i].HCPhys        = pPage->Shared.pfn << PAGE_SHIFT;
+                paPageDesc[i].uHCPhysPageId = pGlobalRegion->paHCPhysPageID[i];
+            }
+        }
+    }
+end:
+    return rc;
+}
+
+/**
+ * RTAvlU32Destroy callback.
+ *
+ * @returns 0
+ * @param   pNode   The node to destroy.
+ * @param   pvGVM   The GVM handle.
+ */
+static DECLCALLBACK(int) gmmR0CleanupSharedModule(PAVLGCPTRNODECORE pNode, void *pvGVM)
+{
+    PGVM pGVM = (PGVM)pvGVM;
+    PGMMSHAREDMODULEPERVM pRecVM = (PGMMSHAREDMODULEPERVM)pNode;
+
+    Assert(pRecVM->pGlobalModule);
+    if (pRecVM->pGlobalModule)
+    {
+        PGMMSHAREDMODULE pRec = pRecVM->pGlobalModule;
+        Assert(pRec);
+        Assert(pRec->cUsers);
+
+        pRec->cUsers--;
+        if (pRec->cUsers == 0)
+        {
+            for (unsigned i = 0; i < pRec->cRegions; i++)
+                if (pRec->aRegions[i].paHCPhysPageID)
+                    RTMemFree(pRec->aRegions[i].paHCPhysPageID);
+
+            RTMemFree(pRec);
+        }
+    }
+    RTMemFree(pRecVM);
+    return 0;
+}
+#endif
+
+/**
+ * Removes all shared modules for the specified VM
+ *
+ * @returns VBox status code.
+ * @param   pVM                 VM handle
+ * @param   idCpu               VCPU id
+ */
+GMMR0DECL(int) GMMR0ResetSharedModules(PVM pVM, VMCPUID idCpu)
+{
+#ifdef VBOX_WITH_PAGE_SHARING
     /*
      * Validate input and get the basics.
@@ -3749,138 +3925,7 @@
     if (GMM_CHECK_SANITY_UPON_ENTERING(pGMM))
     {
-        PGMMSHAREDMODULEPERVM pLocalModule = (PGMMSHAREDMODULEPERVM)RTAvlGCPtrGet(&pGVM->gmm.s.pSharedModuleTree, pReq->GCBaseAddr);
-        if (    !pLocalModule
-            ||  pLocalModule->fCollision)
-        {
-            Assert(!pLocalModule);
-            rc = VERR_PGM_SHARED_MODULE_NOT_FOUND;
-            goto end;
-        }
-
-        PGMMSHAREDMODULE     pGlobalModule = pLocalModule->pGlobalModule;
-        PGMMSHAREDREGIONDESC pGlobalRegion = &pGlobalModule->aRegions[idxRegion];
-
-        if (!pGlobalRegion->paHCPhysPageID)
-        {
-            /* First time; create a page descriptor array. */
-            Log(("Allocate page descriptor array for %d pages\n", cPages));
-            pGlobalRegion->paHCPhysPageID = (uint32_t *)RTMemAlloc(cPages * sizeof(*pGlobalRegion->paHCPhysPageID));
-            if (!pGlobalRegion->paHCPhysPageID)
-            {
-                AssertFailed();
-                rc = VERR_NO_MEMORY;
-                goto end;
-            }
-            /* Invalidate all descriptors. */
-            for (unsigned i = 0; i < cPages; i++)
-                pGlobalRegion->paHCPhysPageID[i] = NIL_GMM_PAGEID;
-        }
-
-        /* Check all pages in the region. */
-        for (unsigned i = 0; i < cPages; i++)
-        {
-            /* Valid page present? */
-            if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID)
-            {
-                /* We've seen this shared page for the first time? */
-                if (pGlobalRegion->paHCPhysPageID[i] == NIL_GMM_PAGEID)
-                {
-                    /* Easy case: just change the internal page type. */
-                    PGMMPAGE pPage = gmmR0GetPage(pGMM, paPageDesc[i].uHCPhysPageId);
-                    if (!pPage)
-                    {
-                        AssertFailed();
-                        rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
-                        goto end;
-                    }
-                    Log(("New shared page guest %RGp host %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys));
-
-                    AssertMsg(paPageDesc[i].GCPhys == (pPage->Private.pfn << 12), ("desc %RGp gmm %RGp\n", paPageDesc[i].HCPhys, (pPage->Private.pfn << 12)));
-
-                    gmmR0ConvertToSharedPage(pGMM, pGVM, paPageDesc[i].HCPhys, paPageDesc[i].uHCPhysPageId, pPage);
-
-                    /* Keep track of these references. */
-                    pGlobalRegion->paHCPhysPageID[i] = paPageDesc[i].uHCPhysPageId;
-                }
-                else
-                {
-                    uint8_t  *pbLocalPage, *pbSharedPage;
-                    uint8_t  *pbChunk;
-                    PGMMCHUNK pChunk;
-
-                    Assert(paPageDesc[i].uHCPhysPageId != pGlobalRegion->paHCPhysPageID[i]);
-
-                    /* Get the shared page source. */
-                    PGMMPAGE pPage = gmmR0GetPage(pGMM, pGlobalRegion->paHCPhysPageID[i]);
-                    if (!pPage)
-                    {
-                        AssertFailed();
-                        rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
-                        goto end;
-                    }
-                    Assert(pPage->Common.u2State == GMM_PAGE_STATE_SHARED);
-
-                    Log(("Replace existing page guest %RGp host %RHp -> %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys, pPage->Shared.pfn << PAGE_SHIFT));
-
-                    /* Calculate the virtual address of the local page. */
-                    pChunk = gmmR0GetChunk(pGMM, paPageDesc[i].uHCPhysPageId >> GMM_CHUNKID_SHIFT);
-                    if (pChunk)
-                    {
-                        if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk))
-                        {
-                            AssertFailed();
-                            rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
-                            goto end;
-                        }
-                        pbLocalPage = pbChunk + ((paPageDesc[i].uHCPhysPageId & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT);
-                    }
-                    else
-                    {
-                        AssertFailed();
-                        rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
-                        goto end;
-                    }
-
-                    /* Calculate the virtual address of the shared page. */
-                    pChunk = gmmR0GetChunk(pGMM, pGlobalRegion->paHCPhysPageID[i] >> GMM_CHUNKID_SHIFT);
-                    Assert(pChunk); /* can't fail as gmmR0GetPage succeeded. */
-
-                    /* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */
-                    if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk))
-                    {
-                        rc = gmmR0MapChunk(pGMM, pGVM, pChunk, (PRTR3PTR)&pbChunk);
-                        if (rc != VINF_SUCCESS)
-                        {
-                            AssertRC(rc);
-                            goto end;
-                        }
-                    }
-                    pbSharedPage = pbChunk + ((pGlobalRegion->paHCPhysPageID[i] & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT);
-
-                    /** todo write ASMMemComparePage. */
-                    if (memcmp(pbSharedPage, pbLocalPage, PAGE_SIZE))
-                    {
-                        Log(("Unexpected differences found between local and shared page; skip\n"));
-                        /* Signal to the caller that this one hasn't changed. */
-                        paPageDesc[i].uHCPhysPageId = NIL_GMM_PAGEID;
-                        continue;
-                    }
-
-                    /* Free the old local page. */
-                    GMMFREEPAGEDESC PageDesc;
-
-                    PageDesc.idPage = paPageDesc[i].uHCPhysPageId;
-                    rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE);
-                    AssertRC(rc);
-
-                    gmmR0UseSharedPage(pGMM, pGVM, pPage);
-
-                    /* Pass along the new physical address & page id. */
-                    paPageDesc[i].HCPhys        = pPage->Shared.pfn << PAGE_SHIFT;
-                    paPageDesc[i].uHCPhysPageId = pGlobalRegion->paHCPhysPageID[i];
-                }
-            }
-        }
-
+        RTAvlGCPtrDestroy(&pGVM->gmm.s.pSharedModuleTree, gmmR0CleanupSharedModule, pGVM);
+
+        rc = VINF_SUCCESS;
         GMM_CHECK_SANITY_UPON_LEAVING(pGMM);
     }
@@ -3888,39 +3933,32 @@
         rc = VERR_INTERNAL_ERROR_5;
 
-end:
     RTSemFastMutexRelease(pGMM->Mtx);
     return rc;
-}
-
-/**
- * RTAvlU32Destroy callback.
- *
- * @returns 0
- * @param   pNode   The node to destroy.
- * @param   pvGVM   The GVM handle.
- */
-static DECLCALLBACK(int) gmmR0CleanupSharedModule(PAVLGCPTRNODECORE pNode, void *pvGVM)
-{
-    PGVM pGVM = (PGVM)pvGVM;
-    PGMMSHAREDMODULEPERVM pRecVM = (PGMMSHAREDMODULEPERVM)pNode;
-
-    Assert(pRecVM->pGlobalModule);
-    if (pRecVM->pGlobalModule)
-    {
-        PGMMSHAREDMODULE pRec = pRecVM->pGlobalModule;
-        Assert(pRec);
-        Assert(pRec->cUsers);
-
-        pRec->cUsers--;
-        if (pRec->cUsers == 0)
-        {
-            for (unsigned i = 0; i < pRec->cRegions; i++)
-                if (pRec->aRegions[i].paHCPhysPageID)
-                    RTMemFree(pRec->aRegions[i].paHCPhysPageID);
-
-            RTMemFree(pRec);
-        }
-    }
-    RTMemFree(pRecVM);
+#else
+    return VERR_NOT_IMPLEMENTED;
+#endif
+}
+
+#ifdef VBOX_WITH_PAGE_SHARING
+typedef struct
+{
+    PGVM    pGVM;
+    VMCPUID idCpu;
+} GMMCHECKSHAREDMODULEINFO, *PGMMCHECKSHAREDMODULEINFO;
+
+/**
+ * Tree enumeration callback for checking a shared module.
+ */
+DECLCALLBACK(int) gmmR0CheckSharedModule(PAVLGCPTRNODECORE pNode, void *pvUser)
+{
+    PGMMCHECKSHAREDMODULEINFO   pInfo = (PGMMCHECKSHAREDMODULEINFO)pvUser;
+    PGMMSHAREDMODULEPERVM       pLocalModule = (PGMMSHAREDMODULEPERVM)pNode;
+    PGMMSHAREDMODULE            pGlobalModule = pLocalModule->pGlobalModule;
+
+    Log(("gmmR0CheckSharedModule: check %s %s base=%RGv size=%x collision=%d\n", pGlobalModule->szName, pGlobalModule->szVersion, pGlobalModule->Core.Key, pGlobalModule->cbModule, pLocalModule->fCollision));
+    if (!pLocalModule->fCollision)
+    {
+        PGMR0SharedModuleCheckRegion(pInfo->pGVM->pVM, pInfo->idCpu, pGlobalModule, pInfo->pGVM);
+    }
     return 0;
 }
@@ -3928,5 +3966,5 @@
 
 /**
- * Removes all shared modules for the specified VM
+ * Check all shared modules for the specified VM
  *
  * @returns VBox status code.
@@ -3934,5 +3972,5 @@
  * @param   idCpu               VCPU id
  */
-GMMR0DECL(int) GMMR0ResetSharedModules(PVM pVM, VMCPUID idCpu)
+GMMR0DECL(int) GMMR0CheckSharedModules(PVM pVM, VMCPUID idCpu)
 {
 #ifdef VBOX_WITH_PAGE_SHARING
@@ -3954,5 +3992,10 @@
     if (GMM_CHECK_SANITY_UPON_ENTERING(pGMM))
     {
-        RTAvlGCPtrDestroy(&pGVM->gmm.s.pSharedModuleTree, gmmR0CleanupSharedModule, pGVM);
+        GMMCHECKSHAREDMODULEINFO Info;
+
+        Info.pGVM = pGVM;
+        Info.idCpu = idCpu;
+
+        RTAvlGCPtrDoWithAll(&pGVM->gmm.s.pSharedModuleTree, true /* fFromLeft */, gmmR0CheckSharedModule, &Info);
 
         rc = VINF_SUCCESS;
Index: /trunk/src/VBox/VMM/VMMR0/GMMR0Internal.h
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/GMMR0Internal.h	(revision 29423)
+++ /trunk/src/VBox/VMM/VMMR0/GMMR0Internal.h	(revision 29424)
@@ -37,47 +37,4 @@
 /** Pointer to a GMMVMSIZES. */
 typedef GMMVMSIZES *PGMMVMSIZES;
-
-/**
- * Shared region descriptor
- */
-typedef struct GMMSHAREDREGIONDESC
-{
-    /** Region base address. */
-    RTGCPTR64           GCRegionAddr;
-    /** Region size. */
-    uint32_t            cbRegion;
-    /** Alignment. */
-    uint32_t            u32Alignment;
-    /** Pointer to physical page id array. */
-    uint32_t           *paHCPhysPageID;
-} GMMSHAREDREGIONDESC;
-/** Pointer to a GMMSHAREDREGIONDESC. */
-typedef GMMSHAREDREGIONDESC *PGMMSHAREDREGIONDESC;
-
-
-/**
- * Shared module registration info (global)
- */
-typedef struct GMMSHAREDMODULE
-{
-    /* Tree node. */
-    AVLGCPTRNODECORE            Core;
-    /** Shared module size. */
-    uint32_t                    cbModule;
-    /** Number of included region descriptors */
-    uint32_t                    cRegions;
-    /** Number of users (VMs). */
-    uint32_t                    cUsers;
-    /** Guest OS family type. */
-    VBOXOSFAMILY                enmGuestOS;
-    /** Module name */
-    char                        szName[GMM_SHARED_MODULE_MAX_NAME_STRING];
-    /** Module version */
-    char                        szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING];
-    /** Shared region descriptor(s). */
-    GMMSHAREDREGIONDESC         aRegions[1];
-} GMMSHAREDMODULE;
-/** Pointer to a GMMSHAREDMODULE. */
-typedef GMMSHAREDMODULE *PGMMSHAREDMODULE;
 
 /**
Index: /trunk/src/VBox/VMM/VMMR0/PGMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/PGMR0.cpp	(revision 29423)
+++ /trunk/src/VBox/VMM/VMMR0/PGMR0.cpp	(revision 29424)
@@ -21,4 +21,5 @@
 #define LOG_GROUP LOG_GROUP_PGM
 #include <VBox/pgm.h>
+#include <VBox/gmm.h>
 #include "../PGMInternal.h"
 #include <VBox/vm.h>
@@ -308,8 +309,9 @@
  *
  * @param   pVM         The VM handle.
- * @param   pVCpu       The VMCPU handle.
- * @param   pReq        Module request packet
- */
-VMMR0DECL(int) PGMR0SharedModuleCheck(PVM pVM, PVMCPU pVCpu, PGMMREGISTERSHAREDMODULEREQ pReq)
+ * @param   idCpu       VCPU id
+ * @param   pModule     Module description
+ * @param   pGVM        Pointer to the GVM instance data.
+ */
+VMMR0DECL(int) PGMR0SharedModuleCheckRegion(PVM pVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, PGVM pGVM)
 {
     int                rc = VINF_SUCCESS;
@@ -317,23 +319,18 @@
     uint32_t           cbPreviousRegion  = 0;
     bool               fFlushTLBs = false;
-
-    /*
-     * Validate input.
-     */
-    AssertPtrReturn(pReq, VERR_INVALID_POINTER);
-    AssertMsgReturn(pReq->Hdr.cbReq >= sizeof(*pReq) && pReq->Hdr.cbReq == RT_UOFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]), ("%#x != %#x\n", pReq->Hdr.cbReq, RT_UOFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions])), VERR_INVALID_PARAMETER);
-
-    Log(("PGMR0SharedModuleCheck: check %s %s base=%RGv size=%x\n", pReq->szName, pReq->szVersion, pReq->GCBaseAddr, pReq->cbModule));
+    PVMCPU             pVCpu = &pVM->aCpus[idCpu];
+
+    Log(("PGMR0SharedModuleCheck: check %s %s base=%RGv size=%x\n", pModule->szName, pModule->szVersion, pModule->Core.Key, pModule->cbModule));
 
     pgmLock(pVM);
 
     /* Check every region of the shared module. */
-    for (unsigned i = 0; i < pReq->cRegions; i++)
-    {
-        Assert((pReq->aRegions[i].cbRegion & 0xfff) == 0);
-        Assert((pReq->aRegions[i].GCRegionAddr & 0xfff) == 0);
-
-        RTGCPTR  GCRegion  = pReq->aRegions[i].GCRegionAddr;
-        unsigned cbRegion = pReq->aRegions[i].cbRegion & ~0xfff;
+    for (unsigned i = 0; i < pModule->cRegions; i++)
+    {
+        Assert((pModule->aRegions[i].cbRegion & 0xfff) == 0);
+        Assert((pModule->aRegions[i].GCRegionAddr & 0xfff) == 0);
+
+        RTGCPTR  GCRegion  = pModule->aRegions[i].GCRegionAddr;
+        unsigned cbRegion = pModule->aRegions[i].cbRegion & ~0xfff;
         unsigned idxPage = 0;
         bool     fValidChanges = false;
@@ -385,5 +382,5 @@
         if (fValidChanges)
         {
-            rc = GMMR0SharedModuleCheckRange(pVM, pVCpu->idCpu, pReq, i, idxPage, paPageDesc);
+            rc = GMMR0SharedModuleCheckRange(pGVM, pModule, i, idxPage, paPageDesc);
             AssertRC(rc);
             if (RT_FAILURE(rc))
@@ -452,2 +449,71 @@
 }
 #endif
+
+#if 0
+/**
+ * Shared module registration helper (called on the way out).
+ *
+ * @param   pVM         The VM handle.
+ * @param   pReq        Registration request info
+ */
+static DECLCALLBACK(void) pgmR3SharedModuleRegisterHelper(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)
+{
+    int rc;
+    
+    rc = GMMR3RegisterSharedModule(pVM, pReq);
+    Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED);
+    if (rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED)
+    {
+        PVMCPU   pVCpu = VMMGetCpu(pVM);
+        unsigned cFlushedPages = 0;
+
+        /** todo count copy-on-write actions in the trap handler so we don't have to check everything all the time! */
+
+        /* Count the number of shared pages that were changed (copy-on-write). */
+        for (unsigned i = 0; i < pReq->cRegions; i++)
+        {
+            Assert((pReq->aRegions[i].cbRegion & 0xfff) == 0);
+            Assert((pReq->aRegions[i].GCRegionAddr & 0xfff) == 0);
+
+            RTGCPTR GCRegion  = pReq->aRegions[i].GCRegionAddr;
+            uint32_t cbRegion = pReq->aRegions[i].cbRegion & ~0xfff;
+
+            while (cbRegion)
+            {
+                RTGCPHYS GCPhys;
+                uint64_t fFlags;
+
+                rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys);
+                if (    rc == VINF_SUCCESS
+                    &&  !(fFlags & X86_PTE_RW))
+                {
+                    PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
+                    if (    pPage
+                        &&  !PGM_PAGE_IS_SHARED(pPage))
+                    {
+                        cFlushedPages++;
+                    }
+                }
+
+                GCRegion += PAGE_SIZE;
+                cbRegion -= PAGE_SIZE;
+            }
+        }
+
+        if (cFlushedPages > 32)
+            rc = VINF_SUCCESS;  /* force recheck below */
+    }
+    /* Full (re)check needed? */
+    if (rc == VINF_SUCCESS)
+    {
+        pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
+        pReq->Hdr.cbReq = RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]);
+
+        /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */
+        rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, pReq);
+        AssertRC(rc);
+    }
+    RTMemFree(pReq);
+    return;
+}
+#endif
Index: /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 29423)
+++ /trunk/src/VBox/VMM/VMMR0/VMMR0.cpp	(revision 29424)
@@ -878,23 +878,4 @@
             return PGMR0PhysAllocateLargeHandyPage(pVM, &pVM->aCpus[idCpu]);
 
-#ifdef VBOX_WITH_PAGE_SHARING
-        case VMMR0_DO_PGM_CHECK_SHARED_MODULE:
-        {
-            if (idCpu == NIL_VMCPUID)
-                return VERR_INVALID_CPU_ID;
-
-            PVMCPU pVCpu = &pVM->aCpus[idCpu];
-
-            /* Select a valid VCPU context. */
-            ASMAtomicWriteU32(&pVCpu->idHostCpu, RTMpCpuId());
-
-            int rc = PGMR0SharedModuleCheck(pVM, pVCpu, (PGMMREGISTERSHAREDMODULEREQ)pReqHdr);
-
-            /* Clear the VCPU context. */
-            ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
-            return rc;
-        }
-#endif
-
         /*
          * GMM wrappers.
@@ -973,4 +954,26 @@
                 return VERR_INVALID_PARAMETER;
             return GMMR0ResetSharedModules(pVM, idCpu);
+
+#ifdef VBOX_WITH_PAGE_SHARING
+        case VMMR0_DO_GMM_CHECK_SHARED_MODULES:
+        {
+            if (idCpu == NIL_VMCPUID)
+                return VERR_INVALID_CPU_ID;
+            if (    u64Arg
+                ||  pReqHdr)
+                return VERR_INVALID_PARAMETER;
+
+            PVMCPU pVCpu = &pVM->aCpus[idCpu];
+
+            /* Select a valid VCPU context. */
+            ASMAtomicWriteU32(&pVCpu->idHostCpu, RTMpCpuId());
+
+            int rc = GMMR0CheckSharedModules(pVM, idCpu);
+
+            /* Clear the VCPU context. */
+            ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);
+            return rc;
+        }
+#endif
 
         /*
