Changeset 29424 in vbox
- Timestamp:
- May 12, 2010 3:11:09 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/gmm.h
r29308 r29424 31 31 #include <VBox/sup.h> 32 32 #include <VBox/VMMDev.h> /* for VMMDEVSHAREDREGIONDESC */ 33 33 #include <iprt/avl.h> 34 34 RT_C_DECLS_BEGIN 35 35 … … 279 279 #endif 280 280 281 281 282 GMMR0DECL(int) GMMR0Init(void); 282 283 GMMR0DECL(void) GMMR0Term(void); … … 297 298 GMMR0DECL(int) GMMR0UnregisterSharedModule(PVM pVM, VMCPUID idCpu, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule); 298 299 GMMR0DECL(int) GMMR0UnregisterAllSharedModules(PVM pVM, VMCPUID idCpu); 300 GMMR0DECL(int) GMMR0CheckSharedModules(PVM pVM, VMCPUID idCpu); 299 301 GMMR0DECL(int) GMMR0ResetSharedModules(PVM pVM, VMCPUID idCpu); 300 302 … … 495 497 496 498 /** 499 * Shared region descriptor 500 */ 501 typedef struct GMMSHAREDREGIONDESC 502 { 503 /** Region base address. */ 504 RTGCPTR64 GCRegionAddr; 505 /** Region size. */ 506 uint32_t cbRegion; 507 /** Alignment. */ 508 uint32_t u32Alignment; 509 /** Pointer to physical page id array. */ 510 uint32_t *paHCPhysPageID; 511 } GMMSHAREDREGIONDESC; 512 /** Pointer to a GMMSHAREDREGIONDESC. */ 513 typedef GMMSHAREDREGIONDESC *PGMMSHAREDREGIONDESC; 514 515 516 /** 517 * Shared module registration info (global) 518 */ 519 typedef struct GMMSHAREDMODULE 520 { 521 /* Tree node. */ 522 AVLGCPTRNODECORE Core; 523 /** Shared module size. */ 524 uint32_t cbModule; 525 /** Number of included region descriptors */ 526 uint32_t cRegions; 527 /** Number of users (VMs). */ 528 uint32_t cUsers; 529 /** Guest OS family type. */ 530 VBOXOSFAMILY enmGuestOS; 531 /** Module name */ 532 char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; 533 /** Module version */ 534 char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; 535 /** Shared region descriptor(s). */ 536 GMMSHAREDREGIONDESC aRegions[1]; 537 } GMMSHAREDMODULE; 538 /** Pointer to a GMMSHAREDMODULE. */ 539 typedef GMMSHAREDMODULE *PGMMSHAREDMODULE; 540 541 /** 497 542 * Page descriptor for GMMR0SharedModuleCheckRange 498 543 */ … … 511 556 typedef GMMSHAREDPAGEDESC *PGMMSHAREDPAGEDESC; 512 557 513 GMMR0DECL(int) GMMR0SharedModuleCheckRange(P VM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc);558 GMMR0DECL(int) GMMR0SharedModuleCheckRange(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc); 514 559 515 560 /** … … 562 607 GMMR3DECL(int) GMMR3BalloonedPages(PVM pVM, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); 563 608 GMMR3DECL(int) GMMR3RegisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq); 564 GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq); 609 GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq); 610 GMMR3DECL(int) GMMR3CheckSharedModules(PVM pVM); 565 611 GMMR3DECL(int) GMMR3ResetSharedModules(PVM pVM); 566 612 /** @} */ -
trunk/include/VBox/pgm.h
r29307 r29424 433 433 VMMR0DECL(int) PGMR0PhysAllocateHandyPages(PVM pVM, PVMCPU pVCpu); 434 434 VMMR0DECL(int) PGMR0PhysAllocateLargeHandyPage(PVM pVM, PVMCPU pVCpu); 435 VMMR0DECL(int) PGMR0SharedModuleCheck (PVM pVM, PVMCPU pVCpu, PGMMREGISTERSHAREDMODULEREQ pReq);435 VMMR0DECL(int) PGMR0SharedModuleCheckRegion(PVM pVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, PGVM pGVM); 436 436 VMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPHYS pvFault); 437 437 # ifdef VBOX_WITH_2X_4GB_ADDR_SPACE … … 569 569 VMMR3DECL(int) PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule, unsigned cRegions, VMMDEVSHAREDREGIONDESC *pRegions); 570 570 VMMR3DECL(int) PGMR3SharedModuleUnregister(PVM pVM, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule); 571 VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM); 571 572 /** @} */ 572 573 -
trunk/include/VBox/vmm.h
r29201 r29424 285 285 /** Call PGMR0AllocateLargePage(). */ 286 286 VMMR0_DO_PGM_ALLOCATE_LARGE_HANDY_PAGE, 287 /** Call PGMR0CheckSharedModule(). */288 VMMR0_DO_PGM_CHECK_SHARED_MODULE,289 287 290 288 /** Call GMMR0InitialReservation(). */ … … 314 312 /** Call GMMR0ResetSharedModules. */ 315 313 VMMR0_DO_GMM_RESET_SHARED_MODULES, 314 /** Call GMMR0CheckSharedModules. */ 315 VMMR0_DO_GMM_CHECK_SHARED_MODULES, 316 316 317 317 /** Set a GVMM or GMM configuration value. */ -
trunk/src/VBox/Additions/common/VBoxService/VBoxServicePageSharing.cpp
r29420 r29424 299 299 /* Delete leftover modules in the old tree. */ 300 300 RTAvlPVDestroy(&pKnownModuleTree, VBoxServicePageSharingEmptyTreeCallback, NULL); 301 302 /* Check all registered modules. */ 303 VbglR3CheckSharedModules(); 301 304 302 305 /* Activate new module tree. */ -
trunk/src/VBox/VMM/GMM.cpp
r29401 r29424 391 391 * @see GMMR0RegisterSharedModule 392 392 */ 393 GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMM REGISTERSHAREDMODULEREQ pReq)393 GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq) 394 394 { 395 395 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; … … 405 405 return VMMR3CallR0(pVM, VMMR0_DO_GMM_RESET_SHARED_MODULES, 0, NULL); 406 406 } 407 408 /** 409 * @see GMMR0CheckSharedModules 410 */ 411 GMMR3DECL(int) GMMR3CheckSharedModules(PVM pVM) 412 { 413 return VMMR3CallR0(pVM, VMMR0_DO_GMM_CHECK_SHARED_MODULES, 0, NULL); 414 } -
trunk/src/VBox/VMM/PGMSharedPage.cpp
r29411 r29424 35 35 #include <iprt/mem.h> 36 36 37 38 #ifdef VBOX_WITH_PAGE_SHARING39 /**40 * Rendezvous callback that will be called once.41 *42 * @returns VBox strict status code.43 * @param pVM VM handle.44 * @param pVCpu The VMCPU handle for the calling EMT.45 * @param pvUser PGMMREGISTERSHAREDMODULEREQ46 */47 static DECLCALLBACK(VBOXSTRICTRC) pgmR3SharedModuleRegRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)48 {49 PGMMREGISTERSHAREDMODULEREQ pReq = (PGMMREGISTERSHAREDMODULEREQ)pvUser;50 51 return VMMR3CallR0(pVM, VMMR0_DO_PGM_CHECK_SHARED_MODULE, 0, &pReq->Hdr);52 }53 54 /**55 * Shared module registration helper (called on the way out).56 *57 * @param pVM The VM handle.58 * @param pReq Registration request info59 */60 static DECLCALLBACK(void) pgmR3SharedModuleRegisterHelper(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)61 {62 int rc;63 64 rc = GMMR3RegisterSharedModule(pVM, pReq);65 Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED);66 if (rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED)67 {68 PVMCPU pVCpu = VMMGetCpu(pVM);69 unsigned cFlushedPages = 0;70 71 /** todo count copy-on-write actions in the trap handler so we don't have to check everything all the time! */72 73 /* Count the number of shared pages that were changed (copy-on-write). */74 for (unsigned i = 0; i < pReq->cRegions; i++)75 {76 Assert((pReq->aRegions[i].cbRegion & 0xfff) == 0);77 Assert((pReq->aRegions[i].GCRegionAddr & 0xfff) == 0);78 79 RTGCPTR GCRegion = pReq->aRegions[i].GCRegionAddr;80 uint32_t cbRegion = pReq->aRegions[i].cbRegion & ~0xfff;81 82 while (cbRegion)83 {84 RTGCPHYS GCPhys;85 uint64_t fFlags;86 87 rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys);88 if ( rc == VINF_SUCCESS89 && !(fFlags & X86_PTE_RW))90 {91 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);92 if ( pPage93 && !PGM_PAGE_IS_SHARED(pPage))94 {95 cFlushedPages++;96 }97 }98 99 GCRegion += PAGE_SIZE;100 cbRegion -= PAGE_SIZE;101 }102 }103 104 if (cFlushedPages > 32)105 rc = VINF_SUCCESS; /* force recheck below */106 }107 /* Full (re)check needed? */108 if (rc == VINF_SUCCESS)109 {110 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;111 pReq->Hdr.cbReq = RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]);112 113 /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */114 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, pReq);115 AssertRC(rc);116 }117 RTMemFree(pReq);118 return;119 }120 #endif121 37 122 38 /** … … 161 77 } 162 78 163 /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */ 164 return VMR3ReqCallNoWait(pVM, VMMGetCpuId(pVM), (PFNRT)pgmR3SharedModuleRegisterHelper, 2, pVM, pReq); 79 int rc = GMMR3RegisterSharedModule(pVM, pReq); 80 RTMemFree(pReq); 81 Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED); 82 if (RT_FAILURE(rc)) 83 return rc; 84 return VINF_SUCCESS; 165 85 #else 166 86 return VERR_NOT_IMPLEMENTED; 167 87 #endif 168 88 } 169 170 171 #ifdef VBOX_WITH_PAGE_SHARING172 /**173 * Shared module unregistration helper (called on the way out).174 *175 * @param pVM The VM handle.176 * @param pReq Unregistration request info177 */178 static DECLCALLBACK(void) pgmR3SharedModuleUnregisterHelper(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)179 {180 int rc;181 182 rc = GMMR3UnregisterSharedModule(pVM, pReq);183 RTMemFree(pReq);184 return;185 }186 #endif187 89 188 90 /** … … 212 114 || RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion) != VINF_SUCCESS) 213 115 { 116 RTMemFree(pReq); 214 117 return VERR_BUFFER_OVERFLOW; 215 118 } 216 /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */ 217 return VMR3ReqCallNoWait(pVM, VMMGetCpuId(pVM), (PFNRT)pgmR3SharedModuleUnregisterHelper, 2, pVM, pReq); 119 int rc = GMMR3UnregisterSharedModule(pVM, pReq); 120 RTMemFree(pReq); 121 return rc; 218 122 #else 219 123 return VERR_NOT_IMPLEMENTED; 220 124 #endif 221 125 } 126 127 #ifdef VBOX_WITH_PAGE_SHARING 128 /** 129 * Rendezvous callback that will be called once. 130 * 131 * @returns VBox strict status code. 132 * @param pVM VM handle. 133 * @param pVCpu The VMCPU handle for the calling EMT. 134 * @param pvUser Not used; 135 */ 136 static DECLCALLBACK(VBOXSTRICTRC) pgmR3SharedModuleRegRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser) 137 { 138 return GMMR3CheckSharedModules(pVM); 139 } 140 141 /** 142 * Shared module unregistration helper (called on the way out). 143 * 144 * @param pVM The VM handle. 145 */ 146 static DECLCALLBACK(void) pgmR3CheckSharedModulesHelper(PVM pVM) 147 { 148 /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */ 149 int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, NULL); 150 AssertRC(rc); 151 } 152 #endif 153 154 /** 155 * Check all registered modules for changes. 156 * 157 * @returns VBox status code. 158 * @param pVM VM handle 159 */ 160 VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM) 161 { 162 #ifdef VBOX_WITH_PAGE_SHARING 163 /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */ 164 return VMR3ReqCallNoWait(pVM, VMMGetCpuId(pVM), (PFNRT)pgmR3CheckSharedModulesHelper, 1, pVM); 165 #else 166 return VERR_NOT_IMPLEMENTED; 167 #endif 168 } -
trunk/src/VBox/VMM/VMMR0/GMMR0.cpp
r29417 r29424 154 154 #include "GMMR0Internal.h" 155 155 #include <VBox/gvm.h> 156 #include <VBox/pgm.h> 156 157 #include <VBox/log.h> 157 158 #include <VBox/param.h> … … 3718 3719 * 3719 3720 * @returns VBox status code. 3720 * @param p VM VM handle3721 * @param idCpu VCPU id3722 * @param p ReqModule description3721 * @param pGMM Pointer to the GMM instance data. 3722 * @param pGVM Pointer to the GVM instance data. 3723 * @param pModule Module description 3723 3724 * @param idxRegion Region index 3724 3725 * @param cPages Number of entries in the paPageDesc array 3725 3726 * @param paPageDesc Page descriptor array (in/out) 3726 3727 */ 3727 GMMR0DECL(int) GMMR0SharedModuleCheckRange(PVM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc) 3728 { 3729 AssertReturn(idxRegion < pReq->cRegions, VERR_INVALID_PARAMETER); 3730 AssertReturn(cPages == (pReq->aRegions[idxRegion].cbRegion >> PAGE_SHIFT), VERR_INVALID_PARAMETER); 3731 3732 Log(("GMMR0SharedModuleCheckRange %s base %RGv region %d cPages %d\n", pReq->szName, pReq->GCBaseAddr, idxRegion, cPages)); 3733 3728 GMMR0DECL(int) GMMR0SharedModuleCheckRange(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc) 3729 { 3730 int rc = VINF_SUCCESS; 3731 PGMM pGMM; 3732 GMM_GET_VALID_INSTANCE(pGMM, VERR_INTERNAL_ERROR); 3733 3734 AssertReturn(idxRegion < pModule->cRegions, VERR_INVALID_PARAMETER); 3735 AssertReturn(cPages == (pModule->aRegions[idxRegion].cbRegion >> PAGE_SHIFT), VERR_INVALID_PARAMETER); 3736 3737 Log(("GMMR0SharedModuleCheckRange %s base %RGv region %d cPages %d\n", pModule->szName, pModule->Core.Key, idxRegion, cPages)); 3738 3739 PGMMSHAREDREGIONDESC pGlobalRegion = &pModule->aRegions[idxRegion]; 3740 3741 if (!pGlobalRegion->paHCPhysPageID) 3742 { 3743 /* First time; create a page descriptor array. */ 3744 Log(("Allocate page descriptor array for %d pages\n", cPages)); 3745 pGlobalRegion->paHCPhysPageID = (uint32_t *)RTMemAlloc(cPages * sizeof(*pGlobalRegion->paHCPhysPageID)); 3746 if (!pGlobalRegion->paHCPhysPageID) 3747 { 3748 AssertFailed(); 3749 rc = VERR_NO_MEMORY; 3750 goto end; 3751 } 3752 /* Invalidate all descriptors. */ 3753 for (unsigned i = 0; i < cPages; i++) 3754 pGlobalRegion->paHCPhysPageID[i] = NIL_GMM_PAGEID; 3755 } 3756 3757 /* Check all pages in the region. */ 3758 for (unsigned i = 0; i < cPages; i++) 3759 { 3760 /* Valid page present? */ 3761 if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID) 3762 { 3763 /* We've seen this shared page for the first time? */ 3764 if (pGlobalRegion->paHCPhysPageID[i] == NIL_GMM_PAGEID) 3765 { 3766 /* Easy case: just change the internal page type. */ 3767 PGMMPAGE pPage = gmmR0GetPage(pGMM, paPageDesc[i].uHCPhysPageId); 3768 if (!pPage) 3769 { 3770 AssertFailed(); 3771 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3772 goto end; 3773 } 3774 Log(("New shared page guest %RGp host %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys)); 3775 3776 AssertMsg(paPageDesc[i].GCPhys == (pPage->Private.pfn << 12), ("desc %RGp gmm %RGp\n", paPageDesc[i].HCPhys, (pPage->Private.pfn << 12))); 3777 3778 gmmR0ConvertToSharedPage(pGMM, pGVM, paPageDesc[i].HCPhys, paPageDesc[i].uHCPhysPageId, pPage); 3779 3780 /* Keep track of these references. */ 3781 pGlobalRegion->paHCPhysPageID[i] = paPageDesc[i].uHCPhysPageId; 3782 } 3783 else 3784 { 3785 uint8_t *pbLocalPage, *pbSharedPage; 3786 uint8_t *pbChunk; 3787 PGMMCHUNK pChunk; 3788 3789 Assert(paPageDesc[i].uHCPhysPageId != pGlobalRegion->paHCPhysPageID[i]); 3790 3791 /* Get the shared page source. */ 3792 PGMMPAGE pPage = gmmR0GetPage(pGMM, pGlobalRegion->paHCPhysPageID[i]); 3793 if (!pPage) 3794 { 3795 AssertFailed(); 3796 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3797 goto end; 3798 } 3799 Assert(pPage->Common.u2State == GMM_PAGE_STATE_SHARED); 3800 3801 Log(("Replace existing page guest %RGp host %RHp -> %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys, pPage->Shared.pfn << PAGE_SHIFT)); 3802 3803 /* Calculate the virtual address of the local page. */ 3804 pChunk = gmmR0GetChunk(pGMM, paPageDesc[i].uHCPhysPageId >> GMM_CHUNKID_SHIFT); 3805 if (pChunk) 3806 { 3807 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3808 { 3809 AssertFailed(); 3810 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3811 goto end; 3812 } 3813 pbLocalPage = pbChunk + ((paPageDesc[i].uHCPhysPageId & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3814 } 3815 else 3816 { 3817 AssertFailed(); 3818 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3819 goto end; 3820 } 3821 3822 /* Calculate the virtual address of the shared page. */ 3823 pChunk = gmmR0GetChunk(pGMM, pGlobalRegion->paHCPhysPageID[i] >> GMM_CHUNKID_SHIFT); 3824 Assert(pChunk); /* can't fail as gmmR0GetPage succeeded. */ 3825 3826 /* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */ 3827 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3828 { 3829 rc = gmmR0MapChunk(pGMM, pGVM, pChunk, (PRTR3PTR)&pbChunk); 3830 if (rc != VINF_SUCCESS) 3831 { 3832 AssertRC(rc); 3833 goto end; 3834 } 3835 } 3836 pbSharedPage = pbChunk + ((pGlobalRegion->paHCPhysPageID[i] & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3837 3838 /** todo write ASMMemComparePage. */ 3839 if (memcmp(pbSharedPage, pbLocalPage, PAGE_SIZE)) 3840 { 3841 Log(("Unexpected differences found between local and shared page; skip\n")); 3842 /* Signal to the caller that this one hasn't changed. */ 3843 paPageDesc[i].uHCPhysPageId = NIL_GMM_PAGEID; 3844 continue; 3845 } 3846 3847 /* Free the old local page. */ 3848 GMMFREEPAGEDESC PageDesc; 3849 3850 PageDesc.idPage = paPageDesc[i].uHCPhysPageId; 3851 rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE); 3852 AssertRC(rc); 3853 3854 gmmR0UseSharedPage(pGMM, pGVM, pPage); 3855 3856 /* Pass along the new physical address & page id. */ 3857 paPageDesc[i].HCPhys = pPage->Shared.pfn << PAGE_SHIFT; 3858 paPageDesc[i].uHCPhysPageId = pGlobalRegion->paHCPhysPageID[i]; 3859 } 3860 } 3861 } 3862 end: 3863 return rc; 3864 } 3865 3866 /** 3867 * RTAvlU32Destroy callback. 3868 * 3869 * @returns 0 3870 * @param pNode The node to destroy. 3871 * @param pvGVM The GVM handle. 3872 */ 3873 static DECLCALLBACK(int) gmmR0CleanupSharedModule(PAVLGCPTRNODECORE pNode, void *pvGVM) 3874 { 3875 PGVM pGVM = (PGVM)pvGVM; 3876 PGMMSHAREDMODULEPERVM pRecVM = (PGMMSHAREDMODULEPERVM)pNode; 3877 3878 Assert(pRecVM->pGlobalModule); 3879 if (pRecVM->pGlobalModule) 3880 { 3881 PGMMSHAREDMODULE pRec = pRecVM->pGlobalModule; 3882 Assert(pRec); 3883 Assert(pRec->cUsers); 3884 3885 pRec->cUsers--; 3886 if (pRec->cUsers == 0) 3887 { 3888 for (unsigned i = 0; i < pRec->cRegions; i++) 3889 if (pRec->aRegions[i].paHCPhysPageID) 3890 RTMemFree(pRec->aRegions[i].paHCPhysPageID); 3891 3892 RTMemFree(pRec); 3893 } 3894 } 3895 RTMemFree(pRecVM); 3896 return 0; 3897 } 3898 #endif 3899 3900 /** 3901 * Removes all shared modules for the specified VM 3902 * 3903 * @returns VBox status code. 3904 * @param pVM VM handle 3905 * @param idCpu VCPU id 3906 */ 3907 GMMR0DECL(int) GMMR0ResetSharedModules(PVM pVM, VMCPUID idCpu) 3908 { 3909 #ifdef VBOX_WITH_PAGE_SHARING 3734 3910 /* 3735 3911 * Validate input and get the basics. … … 3749 3925 if (GMM_CHECK_SANITY_UPON_ENTERING(pGMM)) 3750 3926 { 3751 PGMMSHAREDMODULEPERVM pLocalModule = (PGMMSHAREDMODULEPERVM)RTAvlGCPtrGet(&pGVM->gmm.s.pSharedModuleTree, pReq->GCBaseAddr); 3752 if ( !pLocalModule 3753 || pLocalModule->fCollision) 3754 { 3755 Assert(!pLocalModule); 3756 rc = VERR_PGM_SHARED_MODULE_NOT_FOUND; 3757 goto end; 3758 } 3759 3760 PGMMSHAREDMODULE pGlobalModule = pLocalModule->pGlobalModule; 3761 PGMMSHAREDREGIONDESC pGlobalRegion = &pGlobalModule->aRegions[idxRegion]; 3762 3763 if (!pGlobalRegion->paHCPhysPageID) 3764 { 3765 /* First time; create a page descriptor array. */ 3766 Log(("Allocate page descriptor array for %d pages\n", cPages)); 3767 pGlobalRegion->paHCPhysPageID = (uint32_t *)RTMemAlloc(cPages * sizeof(*pGlobalRegion->paHCPhysPageID)); 3768 if (!pGlobalRegion->paHCPhysPageID) 3769 { 3770 AssertFailed(); 3771 rc = VERR_NO_MEMORY; 3772 goto end; 3773 } 3774 /* Invalidate all descriptors. */ 3775 for (unsigned i = 0; i < cPages; i++) 3776 pGlobalRegion->paHCPhysPageID[i] = NIL_GMM_PAGEID; 3777 } 3778 3779 /* Check all pages in the region. */ 3780 for (unsigned i = 0; i < cPages; i++) 3781 { 3782 /* Valid page present? */ 3783 if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID) 3784 { 3785 /* We've seen this shared page for the first time? */ 3786 if (pGlobalRegion->paHCPhysPageID[i] == NIL_GMM_PAGEID) 3787 { 3788 /* Easy case: just change the internal page type. */ 3789 PGMMPAGE pPage = gmmR0GetPage(pGMM, paPageDesc[i].uHCPhysPageId); 3790 if (!pPage) 3791 { 3792 AssertFailed(); 3793 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3794 goto end; 3795 } 3796 Log(("New shared page guest %RGp host %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys)); 3797 3798 AssertMsg(paPageDesc[i].GCPhys == (pPage->Private.pfn << 12), ("desc %RGp gmm %RGp\n", paPageDesc[i].HCPhys, (pPage->Private.pfn << 12))); 3799 3800 gmmR0ConvertToSharedPage(pGMM, pGVM, paPageDesc[i].HCPhys, paPageDesc[i].uHCPhysPageId, pPage); 3801 3802 /* Keep track of these references. */ 3803 pGlobalRegion->paHCPhysPageID[i] = paPageDesc[i].uHCPhysPageId; 3804 } 3805 else 3806 { 3807 uint8_t *pbLocalPage, *pbSharedPage; 3808 uint8_t *pbChunk; 3809 PGMMCHUNK pChunk; 3810 3811 Assert(paPageDesc[i].uHCPhysPageId != pGlobalRegion->paHCPhysPageID[i]); 3812 3813 /* Get the shared page source. */ 3814 PGMMPAGE pPage = gmmR0GetPage(pGMM, pGlobalRegion->paHCPhysPageID[i]); 3815 if (!pPage) 3816 { 3817 AssertFailed(); 3818 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3819 goto end; 3820 } 3821 Assert(pPage->Common.u2State == GMM_PAGE_STATE_SHARED); 3822 3823 Log(("Replace existing page guest %RGp host %RHp -> %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys, pPage->Shared.pfn << PAGE_SHIFT)); 3824 3825 /* Calculate the virtual address of the local page. */ 3826 pChunk = gmmR0GetChunk(pGMM, paPageDesc[i].uHCPhysPageId >> GMM_CHUNKID_SHIFT); 3827 if (pChunk) 3828 { 3829 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3830 { 3831 AssertFailed(); 3832 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3833 goto end; 3834 } 3835 pbLocalPage = pbChunk + ((paPageDesc[i].uHCPhysPageId & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3836 } 3837 else 3838 { 3839 AssertFailed(); 3840 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3841 goto end; 3842 } 3843 3844 /* Calculate the virtual address of the shared page. */ 3845 pChunk = gmmR0GetChunk(pGMM, pGlobalRegion->paHCPhysPageID[i] >> GMM_CHUNKID_SHIFT); 3846 Assert(pChunk); /* can't fail as gmmR0GetPage succeeded. */ 3847 3848 /* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */ 3849 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3850 { 3851 rc = gmmR0MapChunk(pGMM, pGVM, pChunk, (PRTR3PTR)&pbChunk); 3852 if (rc != VINF_SUCCESS) 3853 { 3854 AssertRC(rc); 3855 goto end; 3856 } 3857 } 3858 pbSharedPage = pbChunk + ((pGlobalRegion->paHCPhysPageID[i] & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3859 3860 /** todo write ASMMemComparePage. */ 3861 if (memcmp(pbSharedPage, pbLocalPage, PAGE_SIZE)) 3862 { 3863 Log(("Unexpected differences found between local and shared page; skip\n")); 3864 /* Signal to the caller that this one hasn't changed. */ 3865 paPageDesc[i].uHCPhysPageId = NIL_GMM_PAGEID; 3866 continue; 3867 } 3868 3869 /* Free the old local page. */ 3870 GMMFREEPAGEDESC PageDesc; 3871 3872 PageDesc.idPage = paPageDesc[i].uHCPhysPageId; 3873 rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE); 3874 AssertRC(rc); 3875 3876 gmmR0UseSharedPage(pGMM, pGVM, pPage); 3877 3878 /* Pass along the new physical address & page id. */ 3879 paPageDesc[i].HCPhys = pPage->Shared.pfn << PAGE_SHIFT; 3880 paPageDesc[i].uHCPhysPageId = pGlobalRegion->paHCPhysPageID[i]; 3881 } 3882 } 3883 } 3884 3927 RTAvlGCPtrDestroy(&pGVM->gmm.s.pSharedModuleTree, gmmR0CleanupSharedModule, pGVM); 3928 3929 rc = VINF_SUCCESS; 3885 3930 GMM_CHECK_SANITY_UPON_LEAVING(pGMM); 3886 3931 } … … 3888 3933 rc = VERR_INTERNAL_ERROR_5; 3889 3934 3890 end:3891 3935 RTSemFastMutexRelease(pGMM->Mtx); 3892 3936 return rc; 3893 } 3894 3895 /** 3896 * RTAvlU32Destroy callback. 3897 * 3898 * @returns 0 3899 * @param pNode The node to destroy. 3900 * @param pvGVM The GVM handle. 3901 */ 3902 static DECLCALLBACK(int) gmmR0CleanupSharedModule(PAVLGCPTRNODECORE pNode, void *pvGVM) 3903 { 3904 PGVM pGVM = (PGVM)pvGVM; 3905 PGMMSHAREDMODULEPERVM pRecVM = (PGMMSHAREDMODULEPERVM)pNode; 3906 3907 Assert(pRecVM->pGlobalModule); 3908 if (pRecVM->pGlobalModule) 3909 { 3910 PGMMSHAREDMODULE pRec = pRecVM->pGlobalModule; 3911 Assert(pRec); 3912 Assert(pRec->cUsers); 3913 3914 pRec->cUsers--; 3915 if (pRec->cUsers == 0) 3916 { 3917 for (unsigned i = 0; i < pRec->cRegions; i++) 3918 if (pRec->aRegions[i].paHCPhysPageID) 3919 RTMemFree(pRec->aRegions[i].paHCPhysPageID); 3920 3921 RTMemFree(pRec); 3922 } 3923 } 3924 RTMemFree(pRecVM); 3937 #else 3938 return VERR_NOT_IMPLEMENTED; 3939 #endif 3940 } 3941 3942 #ifdef VBOX_WITH_PAGE_SHARING 3943 typedef struct 3944 { 3945 PGVM pGVM; 3946 VMCPUID idCpu; 3947 } GMMCHECKSHAREDMODULEINFO, *PGMMCHECKSHAREDMODULEINFO; 3948 3949 /** 3950 * Tree enumeration callback for checking a shared module. 3951 */ 3952 DECLCALLBACK(int) gmmR0CheckSharedModule(PAVLGCPTRNODECORE pNode, void *pvUser) 3953 { 3954 PGMMCHECKSHAREDMODULEINFO pInfo = (PGMMCHECKSHAREDMODULEINFO)pvUser; 3955 PGMMSHAREDMODULEPERVM pLocalModule = (PGMMSHAREDMODULEPERVM)pNode; 3956 PGMMSHAREDMODULE pGlobalModule = pLocalModule->pGlobalModule; 3957 3958 Log(("gmmR0CheckSharedModule: check %s %s base=%RGv size=%x collision=%d\n", pGlobalModule->szName, pGlobalModule->szVersion, pGlobalModule->Core.Key, pGlobalModule->cbModule, pLocalModule->fCollision)); 3959 if (!pLocalModule->fCollision) 3960 { 3961 PGMR0SharedModuleCheckRegion(pInfo->pGVM->pVM, pInfo->idCpu, pGlobalModule, pInfo->pGVM); 3962 } 3925 3963 return 0; 3926 3964 } … … 3928 3966 3929 3967 /** 3930 * Removesall shared modules for the specified VM3968 * Check all shared modules for the specified VM 3931 3969 * 3932 3970 * @returns VBox status code. … … 3934 3972 * @param idCpu VCPU id 3935 3973 */ 3936 GMMR0DECL(int) GMMR0 ResetSharedModules(PVM pVM, VMCPUID idCpu)3974 GMMR0DECL(int) GMMR0CheckSharedModules(PVM pVM, VMCPUID idCpu) 3937 3975 { 3938 3976 #ifdef VBOX_WITH_PAGE_SHARING … … 3954 3992 if (GMM_CHECK_SANITY_UPON_ENTERING(pGMM)) 3955 3993 { 3956 RTAvlGCPtrDestroy(&pGVM->gmm.s.pSharedModuleTree, gmmR0CleanupSharedModule, pGVM); 3994 GMMCHECKSHAREDMODULEINFO Info; 3995 3996 Info.pGVM = pGVM; 3997 Info.idCpu = idCpu; 3998 3999 RTAvlGCPtrDoWithAll(&pGVM->gmm.s.pSharedModuleTree, true /* fFromLeft */, gmmR0CheckSharedModule, &Info); 3957 4000 3958 4001 rc = VINF_SUCCESS; -
trunk/src/VBox/VMM/VMMR0/GMMR0Internal.h
r29308 r29424 37 37 /** Pointer to a GMMVMSIZES. */ 38 38 typedef GMMVMSIZES *PGMMVMSIZES; 39 40 /**41 * Shared region descriptor42 */43 typedef struct GMMSHAREDREGIONDESC44 {45 /** Region base address. */46 RTGCPTR64 GCRegionAddr;47 /** Region size. */48 uint32_t cbRegion;49 /** Alignment. */50 uint32_t u32Alignment;51 /** Pointer to physical page id array. */52 uint32_t *paHCPhysPageID;53 } GMMSHAREDREGIONDESC;54 /** Pointer to a GMMSHAREDREGIONDESC. */55 typedef GMMSHAREDREGIONDESC *PGMMSHAREDREGIONDESC;56 57 58 /**59 * Shared module registration info (global)60 */61 typedef struct GMMSHAREDMODULE62 {63 /* Tree node. */64 AVLGCPTRNODECORE Core;65 /** Shared module size. */66 uint32_t cbModule;67 /** Number of included region descriptors */68 uint32_t cRegions;69 /** Number of users (VMs). */70 uint32_t cUsers;71 /** Guest OS family type. */72 VBOXOSFAMILY enmGuestOS;73 /** Module name */74 char szName[GMM_SHARED_MODULE_MAX_NAME_STRING];75 /** Module version */76 char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING];77 /** Shared region descriptor(s). */78 GMMSHAREDREGIONDESC aRegions[1];79 } GMMSHAREDMODULE;80 /** Pointer to a GMMSHAREDMODULE. */81 typedef GMMSHAREDMODULE *PGMMSHAREDMODULE;82 39 83 40 /** -
trunk/src/VBox/VMM/VMMR0/PGMR0.cpp
r29418 r29424 21 21 #define LOG_GROUP LOG_GROUP_PGM 22 22 #include <VBox/pgm.h> 23 #include <VBox/gmm.h> 23 24 #include "../PGMInternal.h" 24 25 #include <VBox/vm.h> … … 308 309 * 309 310 * @param pVM The VM handle. 310 * @param pVCpu The VMCPU handle. 311 * @param pReq Module request packet 312 */ 313 VMMR0DECL(int) PGMR0SharedModuleCheck(PVM pVM, PVMCPU pVCpu, PGMMREGISTERSHAREDMODULEREQ pReq) 311 * @param idCpu VCPU id 312 * @param pModule Module description 313 * @param pGVM Pointer to the GVM instance data. 314 */ 315 VMMR0DECL(int) PGMR0SharedModuleCheckRegion(PVM pVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, PGVM pGVM) 314 316 { 315 317 int rc = VINF_SUCCESS; … … 317 319 uint32_t cbPreviousRegion = 0; 318 320 bool fFlushTLBs = false; 319 320 /* 321 * Validate input. 322 */ 323 AssertPtrReturn(pReq, VERR_INVALID_POINTER); 324 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); 325 326 Log(("PGMR0SharedModuleCheck: check %s %s base=%RGv size=%x\n", pReq->szName, pReq->szVersion, pReq->GCBaseAddr, pReq->cbModule)); 321 PVMCPU pVCpu = &pVM->aCpus[idCpu]; 322 323 Log(("PGMR0SharedModuleCheck: check %s %s base=%RGv size=%x\n", pModule->szName, pModule->szVersion, pModule->Core.Key, pModule->cbModule)); 327 324 328 325 pgmLock(pVM); 329 326 330 327 /* Check every region of the shared module. */ 331 for (unsigned i = 0; i < p Req->cRegions; i++)332 { 333 Assert((p Req->aRegions[i].cbRegion & 0xfff) == 0);334 Assert((p Req->aRegions[i].GCRegionAddr & 0xfff) == 0);335 336 RTGCPTR GCRegion = p Req->aRegions[i].GCRegionAddr;337 unsigned cbRegion = p Req->aRegions[i].cbRegion & ~0xfff;328 for (unsigned i = 0; i < pModule->cRegions; i++) 329 { 330 Assert((pModule->aRegions[i].cbRegion & 0xfff) == 0); 331 Assert((pModule->aRegions[i].GCRegionAddr & 0xfff) == 0); 332 333 RTGCPTR GCRegion = pModule->aRegions[i].GCRegionAddr; 334 unsigned cbRegion = pModule->aRegions[i].cbRegion & ~0xfff; 338 335 unsigned idxPage = 0; 339 336 bool fValidChanges = false; … … 385 382 if (fValidChanges) 386 383 { 387 rc = GMMR0SharedModuleCheckRange(p VM, pVCpu->idCpu, pReq, i, idxPage, paPageDesc);384 rc = GMMR0SharedModuleCheckRange(pGVM, pModule, i, idxPage, paPageDesc); 388 385 AssertRC(rc); 389 386 if (RT_FAILURE(rc)) … … 452 449 } 453 450 #endif 451 452 #if 0 453 /** 454 * Shared module registration helper (called on the way out). 455 * 456 * @param pVM The VM handle. 457 * @param pReq Registration request info 458 */ 459 static DECLCALLBACK(void) pgmR3SharedModuleRegisterHelper(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq) 460 { 461 int rc; 462 463 rc = GMMR3RegisterSharedModule(pVM, pReq); 464 Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED); 465 if (rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED) 466 { 467 PVMCPU pVCpu = VMMGetCpu(pVM); 468 unsigned cFlushedPages = 0; 469 470 /** todo count copy-on-write actions in the trap handler so we don't have to check everything all the time! */ 471 472 /* Count the number of shared pages that were changed (copy-on-write). */ 473 for (unsigned i = 0; i < pReq->cRegions; i++) 474 { 475 Assert((pReq->aRegions[i].cbRegion & 0xfff) == 0); 476 Assert((pReq->aRegions[i].GCRegionAddr & 0xfff) == 0); 477 478 RTGCPTR GCRegion = pReq->aRegions[i].GCRegionAddr; 479 uint32_t cbRegion = pReq->aRegions[i].cbRegion & ~0xfff; 480 481 while (cbRegion) 482 { 483 RTGCPHYS GCPhys; 484 uint64_t fFlags; 485 486 rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys); 487 if ( rc == VINF_SUCCESS 488 && !(fFlags & X86_PTE_RW)) 489 { 490 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys); 491 if ( pPage 492 && !PGM_PAGE_IS_SHARED(pPage)) 493 { 494 cFlushedPages++; 495 } 496 } 497 498 GCRegion += PAGE_SIZE; 499 cbRegion -= PAGE_SIZE; 500 } 501 } 502 503 if (cFlushedPages > 32) 504 rc = VINF_SUCCESS; /* force recheck below */ 505 } 506 /* Full (re)check needed? */ 507 if (rc == VINF_SUCCESS) 508 { 509 pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC; 510 pReq->Hdr.cbReq = RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]); 511 512 /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */ 513 rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, pReq); 514 AssertRC(rc); 515 } 516 RTMemFree(pReq); 517 return; 518 } 519 #endif -
trunk/src/VBox/VMM/VMMR0/VMMR0.cpp
r29250 r29424 878 878 return PGMR0PhysAllocateLargeHandyPage(pVM, &pVM->aCpus[idCpu]); 879 879 880 #ifdef VBOX_WITH_PAGE_SHARING881 case VMMR0_DO_PGM_CHECK_SHARED_MODULE:882 {883 if (idCpu == NIL_VMCPUID)884 return VERR_INVALID_CPU_ID;885 886 PVMCPU pVCpu = &pVM->aCpus[idCpu];887 888 /* Select a valid VCPU context. */889 ASMAtomicWriteU32(&pVCpu->idHostCpu, RTMpCpuId());890 891 int rc = PGMR0SharedModuleCheck(pVM, pVCpu, (PGMMREGISTERSHAREDMODULEREQ)pReqHdr);892 893 /* Clear the VCPU context. */894 ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID);895 return rc;896 }897 #endif898 899 880 /* 900 881 * GMM wrappers. … … 973 954 return VERR_INVALID_PARAMETER; 974 955 return GMMR0ResetSharedModules(pVM, idCpu); 956 957 #ifdef VBOX_WITH_PAGE_SHARING 958 case VMMR0_DO_GMM_CHECK_SHARED_MODULES: 959 { 960 if (idCpu == NIL_VMCPUID) 961 return VERR_INVALID_CPU_ID; 962 if ( u64Arg 963 || pReqHdr) 964 return VERR_INVALID_PARAMETER; 965 966 PVMCPU pVCpu = &pVM->aCpus[idCpu]; 967 968 /* Select a valid VCPU context. */ 969 ASMAtomicWriteU32(&pVCpu->idHostCpu, RTMpCpuId()); 970 971 int rc = GMMR0CheckSharedModules(pVM, idCpu); 972 973 /* Clear the VCPU context. */ 974 ASMAtomicWriteU32(&pVCpu->idHostCpu, NIL_RTCPUID); 975 return rc; 976 } 977 #endif 975 978 976 979 /*
Note:
See TracChangeset
for help on using the changeset viewer.