Changeset 30783 in vbox
- Timestamp:
- Jul 12, 2010 9:19:24 AM (15 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/err.h
r30660 r30783 479 479 /** Inconsistent local and global registration records. */ 480 480 #define VERR_PGM_SHARED_MODULE_REGISTRATION_INCONSISTENCY (-1650) 481 /** First shared module check. */482 #define VERR_PGM_SHARED_MODULE_FIRST_CHECK (-1651)483 481 /** @} */ 484 482 -
trunk/include/VBox/gmm.h
r30660 r30783 561 561 typedef GMMSHAREDPAGEDESC *PGMMSHAREDPAGEDESC; 562 562 563 GMMR0DECL(int) GMMR0SharedModuleCheck Range(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc);563 GMMR0DECL(int) GMMR0SharedModuleCheckPage(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned idxPage, PGMMSHAREDPAGEDESC pPageDesc); 564 564 565 565 /** -
trunk/src/VBox/VMM/VMMR0/GMMR0.cpp
r30769 r30783 3819 3819 * 3820 3820 * Performs the following tasks: 3821 * - if a shared page is new, then it changes the GMM page type to shared and returns it in the p aPageDesc array3822 * - if a shared page already exists, then it checks if the VM page is identical and if so frees the VM page and returns the shared page in the paPageDesc array3821 * - if a shared page is new, then it changes the GMM page type to shared and returns it in the pPageDesc descriptor 3822 * - if a shared page already exists, then it checks if the VM page is identical and if so frees the VM page and returns the shared page in pPageDesc descriptor 3823 3823 * 3824 3824 * Note: assumes the caller has acquired the GMM semaphore!! … … 3829 3829 * @param pModule Module description 3830 3830 * @param idxRegion Region index 3831 * @param cPages Number of entries in the paPageDesc array3832 * @param paPageDesc Page descriptor array (in/out)3833 */ 3834 GMMR0DECL(int) GMMR0SharedModuleCheck Range(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc)3831 * @param idxPage Page index 3832 * @param paPageDesc Page descriptor 3833 */ 3834 GMMR0DECL(int) GMMR0SharedModuleCheckPage(PGVM pGVM, PGMMSHAREDMODULE pModule, unsigned idxRegion, unsigned idxPage, PGMMSHAREDPAGEDESC pPageDesc) 3835 3835 { 3836 3836 int rc = VINF_SUCCESS; 3837 3837 PGMM pGMM; 3838 3838 GMM_GET_VALID_INSTANCE(pGMM, VERR_INTERNAL_ERROR); 3839 unsigned cPages = pModule->aRegions[idxRegion].cbRegion >> PAGE_SHIFT; 3839 3840 3840 3841 AssertReturn(idxRegion < pModule->cRegions, VERR_INVALID_PARAMETER); 3841 AssertReturn( cPages == (pModule->aRegions[idxRegion].cbRegion >> PAGE_SHIFT), VERR_INVALID_PARAMETER);3842 3843 Log (("GMMR0SharedModuleCheckRange %s base %RGv region %d cPages %d\n", pModule->szName, pModule->Core.Key, idxRegion, cPages));3842 AssertReturn(idxPage < cPages, VERR_INVALID_PARAMETER); 3843 3844 LogFlow(("GMMR0SharedModuleCheckRange %s base %RGv region %d idxPage %d\n", pModule->szName, pModule->Core.Key, idxRegion, idxPage)); 3844 3845 3845 3846 PGMMSHAREDREGIONDESC pGlobalRegion = &pModule->aRegions[idxRegion]; 3846 3847 3847 if (!pGlobalRegion->paHCPhysPageID) 3848 3848 { … … 3861 3861 } 3862 3862 3863 /* Check all pages in the region. */ 3864 for (unsigned i = 0; i < cPages; i++) 3865 { 3866 /* Valid page present? */ 3867 if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID) 3868 { 3869 /* We've seen this shared page for the first time? */ 3870 if (pGlobalRegion->paHCPhysPageID[i] == NIL_GMM_PAGEID) 3863 /* We've seen this shared page for the first time? */ 3864 if (pGlobalRegion->paHCPhysPageID[idxPage] == NIL_GMM_PAGEID) 3865 { 3866 new_shared_page: 3867 Log(("New shared page guest %RGp host %RHp\n", pPageDesc->GCPhys, pPageDesc->HCPhys)); 3868 3869 /* Easy case: just change the internal page type. */ 3870 PGMMPAGE pPage = gmmR0GetPage(pGMM, pPageDesc->uHCPhysPageId); 3871 if (!pPage) 3872 { 3873 AssertFailed(); 3874 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3875 goto end; 3876 } 3877 3878 AssertMsg(pPageDesc->GCPhys == (pPage->Private.pfn << 12), ("desc %RGp gmm %RGp\n", pPageDesc->HCPhys, (pPage->Private.pfn << 12))); 3879 3880 gmmR0ConvertToSharedPage(pGMM, pGVM, pPageDesc->HCPhys, pPageDesc->uHCPhysPageId, pPage); 3881 3882 /* Keep track of these references. */ 3883 pGlobalRegion->paHCPhysPageID[idxPage] = pPageDesc->uHCPhysPageId; 3884 } 3885 else 3886 { 3887 uint8_t *pbLocalPage, *pbSharedPage; 3888 uint8_t *pbChunk; 3889 PGMMCHUNK pChunk; 3890 3891 Assert(pPageDesc->uHCPhysPageId != pGlobalRegion->paHCPhysPageID[idxPage]); 3892 3893 Log(("Replace existing page guest %RGp host %RHp id %x -> id %x\n", pPageDesc->GCPhys, pPageDesc->HCPhys, pPageDesc->uHCPhysPageId, pGlobalRegion->paHCPhysPageID[idxPage])); 3894 3895 /* Get the shared page source. */ 3896 PGMMPAGE pPage = gmmR0GetPage(pGMM, pGlobalRegion->paHCPhysPageID[idxPage]); 3897 if (!pPage) 3898 { 3899 AssertFailed(); 3900 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3901 goto end; 3902 } 3903 if (pPage->Common.u2State != GMM_PAGE_STATE_SHARED) 3904 { 3905 /* Page was freed at some point; invalidate this entry. */ 3906 /** todo this isn't really bullet proof. */ 3907 Log(("Old shared page was freed -> create a new one\n")); 3908 pGlobalRegion->paHCPhysPageID[idxPage] = NIL_GMM_PAGEID; 3909 goto new_shared_page; /* ugly goto */ 3910 } 3911 3912 Log(("Replace existing page guest host %RHp -> %RHp\n", pPageDesc->HCPhys, ((uint64_t)pPage->Shared.pfn) << PAGE_SHIFT)); 3913 3914 /* Calculate the virtual address of the local page. */ 3915 pChunk = gmmR0GetChunk(pGMM, pPageDesc->uHCPhysPageId >> GMM_CHUNKID_SHIFT); 3916 if (pChunk) 3917 { 3918 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3871 3919 { 3872 new_shared_page: 3873 Log(("New shared page guest %RGp host %RHp\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys)); 3874 3875 /* Easy case: just change the internal page type. */ 3876 PGMMPAGE pPage = gmmR0GetPage(pGMM, paPageDesc[i].uHCPhysPageId); 3877 if (!pPage) 3878 { 3879 AssertFailed(); 3880 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3881 goto end; 3882 } 3883 3884 AssertMsg(paPageDesc[i].GCPhys == (pPage->Private.pfn << 12), ("desc %RGp gmm %RGp\n", paPageDesc[i].HCPhys, (pPage->Private.pfn << 12))); 3885 3886 gmmR0ConvertToSharedPage(pGMM, pGVM, paPageDesc[i].HCPhys, paPageDesc[i].uHCPhysPageId, pPage); 3887 3888 /* Keep track of these references. */ 3889 pGlobalRegion->paHCPhysPageID[i] = paPageDesc[i].uHCPhysPageId; 3920 AssertFailed(); 3921 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3922 goto end; 3890 3923 } 3891 else 3924 pbLocalPage = pbChunk + ((pPageDesc->uHCPhysPageId & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3925 } 3926 else 3927 { 3928 AssertFailed(); 3929 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3930 goto end; 3931 } 3932 3933 /* Calculate the virtual address of the shared page. */ 3934 pChunk = gmmR0GetChunk(pGMM, pGlobalRegion->paHCPhysPageID[idxPage] >> GMM_CHUNKID_SHIFT); 3935 Assert(pChunk); /* can't fail as gmmR0GetPage succeeded. */ 3936 3937 /* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */ 3938 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3939 { 3940 Log(("Map chunk into process!\n")); 3941 rc = gmmR0MapChunk(pGMM, pGVM, pChunk, (PRTR3PTR)&pbChunk); 3942 if (rc != VINF_SUCCESS) 3892 3943 { 3893 uint8_t *pbLocalPage, *pbSharedPage; 3894 uint8_t *pbChunk; 3895 PGMMCHUNK pChunk; 3896 3897 Assert(paPageDesc[i].uHCPhysPageId != pGlobalRegion->paHCPhysPageID[i]); 3898 3899 Log(("Replace existing page guest %RGp host %RHp id %x -> id %x\n", paPageDesc[i].GCPhys, paPageDesc[i].HCPhys, paPageDesc[i].uHCPhysPageId, pGlobalRegion->paHCPhysPageID[i])); 3900 3901 /* Get the shared page source. */ 3902 PGMMPAGE pPage = gmmR0GetPage(pGMM, pGlobalRegion->paHCPhysPageID[i]); 3903 if (!pPage) 3904 { 3905 AssertFailed(); 3906 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3907 goto end; 3908 } 3909 if (pPage->Common.u2State != GMM_PAGE_STATE_SHARED) 3910 { 3911 /* Page was freed at some point; invalidate this entry. */ 3912 /** todo this isn't really bullet proof. */ 3913 Log(("Old shared page was freed -> create a new one\n")); 3914 pGlobalRegion->paHCPhysPageID[i] = NIL_GMM_PAGEID; 3915 goto new_shared_page; /* ugly goto */ 3916 } 3917 3918 Log(("Replace existing page guest host %RHp -> %RHp\n", paPageDesc[i].HCPhys, ((uint64_t)pPage->Shared.pfn) << PAGE_SHIFT)); 3919 3920 /* Calculate the virtual address of the local page. */ 3921 pChunk = gmmR0GetChunk(pGMM, paPageDesc[i].uHCPhysPageId >> GMM_CHUNKID_SHIFT); 3922 if (pChunk) 3923 { 3924 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3925 { 3926 AssertFailed(); 3927 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3928 goto end; 3929 } 3930 pbLocalPage = pbChunk + ((paPageDesc[i].uHCPhysPageId & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3931 } 3932 else 3933 { 3934 AssertFailed(); 3935 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3936 goto end; 3937 } 3938 3939 /* Calculate the virtual address of the shared page. */ 3940 pChunk = gmmR0GetChunk(pGMM, pGlobalRegion->paHCPhysPageID[i] >> GMM_CHUNKID_SHIFT); 3941 Assert(pChunk); /* can't fail as gmmR0GetPage succeeded. */ 3942 3943 /* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */ 3944 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbChunk)) 3945 { 3946 Log(("Map chunk into process!\n")); 3947 rc = gmmR0MapChunk(pGMM, pGVM, pChunk, (PRTR3PTR)&pbChunk); 3948 if (rc != VINF_SUCCESS) 3949 { 3950 AssertRC(rc); 3951 goto end; 3952 } 3953 } 3954 pbSharedPage = pbChunk + ((pGlobalRegion->paHCPhysPageID[i] & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3955 3956 /** todo write ASMMemComparePage. */ 3957 if (memcmp(pbSharedPage, pbLocalPage, PAGE_SIZE)) 3958 { 3959 Log(("Unexpected differences found between local and shared page; skip\n")); 3960 /* Signal to the caller that this one hasn't changed. */ 3961 paPageDesc[i].uHCPhysPageId = NIL_GMM_PAGEID; 3962 continue; 3963 } 3964 3965 /* Free the old local page. */ 3966 GMMFREEPAGEDESC PageDesc; 3967 3968 PageDesc.idPage = paPageDesc[i].uHCPhysPageId; 3969 rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE); 3970 AssertRCReturn(rc, rc); 3971 3972 gmmR0UseSharedPage(pGMM, pGVM, pPage); 3973 3974 /* Pass along the new physical address & page id. */ 3975 paPageDesc[i].HCPhys = ((uint64_t)pPage->Shared.pfn) << PAGE_SHIFT; 3976 paPageDesc[i].uHCPhysPageId = pGlobalRegion->paHCPhysPageID[i]; 3944 AssertRC(rc); 3945 goto end; 3977 3946 } 3978 3947 } 3948 pbSharedPage = pbChunk + ((pGlobalRegion->paHCPhysPageID[idxPage] & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3949 3950 /** todo write ASMMemComparePage. */ 3951 if (memcmp(pbSharedPage, pbLocalPage, PAGE_SIZE)) 3952 { 3953 Log(("Unexpected differences found between local and shared page; skip\n")); 3954 /* Signal to the caller that this one hasn't changed. */ 3955 pPageDesc->uHCPhysPageId = NIL_GMM_PAGEID; 3956 goto end; 3957 } 3958 3959 /* Free the old local page. */ 3960 GMMFREEPAGEDESC PageDesc; 3961 3962 PageDesc.idPage = pPageDesc->uHCPhysPageId; 3963 rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE); 3964 AssertRCReturn(rc, rc); 3965 3966 gmmR0UseSharedPage(pGMM, pGVM, pPage); 3967 3968 /* Pass along the new physical address & page id. */ 3969 pPageDesc->HCPhys = ((uint64_t)pPage->Shared.pfn) << PAGE_SHIFT; 3970 pPageDesc->uHCPhysPageId = pGlobalRegion->paHCPhysPageID[idxPage]; 3979 3971 } 3980 3972 end: -
trunk/src/VBox/VMM/VMMR0/PGMR0SharedPage.cpp
r30761 r30783 47 47 { 48 48 int rc = VINF_SUCCESS; 49 PGMMSHAREDPAGEDESC paPageDesc = NULL; 50 uint32_t cbPreviousRegion = 0; 49 GMMSHAREDPAGEDESC PageDesc; 51 50 bool fFlushTLBs = false; 52 51 PVMCPU pVCpu = &pVM->aCpus[idCpu]; … … 65 64 unsigned cbRegion = pRegions[idxRegion].cbRegion & ~0xfff; 66 65 unsigned idxPage = 0; 67 bool fValidChanges = false;68 69 if (cbPreviousRegion < cbRegion)70 {71 if (paPageDesc)72 RTMemFree(paPageDesc);73 74 paPageDesc = (PGMMSHAREDPAGEDESC)RTMemAlloc((cbRegion >> PAGE_SHIFT) * sizeof(*paPageDesc));75 if (!paPageDesc)76 {77 AssertFailed();78 rc = VERR_NO_MEMORY;79 goto end;80 }81 cbPreviousRegion = cbRegion;82 }83 66 84 67 while (cbRegion) … … 97 80 && PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED) 98 81 { 99 fValidChanges = true; 100 paPageDesc[idxPage].uHCPhysPageId = PGM_PAGE_GET_PAGEID(pPage); 101 paPageDesc[idxPage].HCPhys = PGM_PAGE_GET_HCPHYS(pPage); 102 paPageDesc[idxPage].GCPhys = GCPhys; 82 PageDesc.uHCPhysPageId = PGM_PAGE_GET_PAGEID(pPage); 83 PageDesc.HCPhys = PGM_PAGE_GET_HCPHYS(pPage); 84 PageDesc.GCPhys = GCPhys; 85 86 rc = GMMR0SharedModuleCheckPage(pGVM, pModule, idxRegion, idxPage, &PageDesc); 87 if (rc == VINF_SUCCESS) 88 { 89 /* Any change for this page? */ 90 if (PageDesc.uHCPhysPageId != NIL_GMM_PAGEID) 91 { 92 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED); 93 94 Log(("PGMR0SharedModuleCheck: shared page gc virt=%RGv phys %RGp host %RHp->%RHp\n", pRegions[idxRegion].GCRegionAddr + idxPage * PAGE_SIZE, PageDesc.GCPhys, PGM_PAGE_GET_HCPHYS(pPage), PageDesc.HCPhys)); 95 if (PageDesc.HCPhys != PGM_PAGE_GET_HCPHYS(pPage)) 96 { 97 bool fFlush = false; 98 99 /* Page was replaced by an existing shared version of it; clear all references first. */ 100 rc = pgmPoolTrackUpdateGCPhys(pVM, PageDesc.GCPhys, pPage, true /* clear the entries */, &fFlush); 101 Assert(rc == VINF_SUCCESS || (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3) && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL))); 102 if (rc == VINF_SUCCESS) 103 fFlushTLBs |= fFlush; 104 105 /* Update the physical address and page id now. */ 106 PGM_PAGE_SET_HCPHYS(pPage, PageDesc.HCPhys); 107 PGM_PAGE_SET_PAGEID(pPage, PageDesc.uHCPhysPageId); 108 109 /* Invalidate page map TLB entry for this page too. */ 110 PGMPhysInvalidatePageMapTLBEntry(pVM, PageDesc.GCPhys); 111 pVM->pgm.s.cReusedSharedPages++; 112 } 113 /* else nothing changed (== this page is now a shared page), so no need to flush anything. */ 114 115 pVM->pgm.s.cSharedPages++; 116 pVM->pgm.s.cPrivatePages--; 117 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_SHARED); 118 } 119 } 120 else 121 break; 103 122 } 104 else105 paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;106 123 } 107 else108 paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;109 124 110 125 idxPage++; … … 112 127 cbRegion -= PAGE_SIZE; 113 128 } 114 115 if (fValidChanges)116 {117 rc = GMMR0SharedModuleCheckRange(pGVM, pModule, idxRegion, idxPage, paPageDesc);118 AssertRC(rc);119 if (RT_FAILURE(rc))120 break;121 122 for (unsigned i = 0; i < idxPage; i++)123 {124 /* Any change for this page? */125 if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID)126 {127 /** todo: maybe cache these to prevent the nth lookup. */128 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPageDesc[i].GCPhys);129 if (!pPage)130 {131 /* Should never happen. */132 AssertFailed();133 rc = VERR_PGM_PHYS_INVALID_PAGE_ID;134 goto end;135 }136 Assert(PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED);137 138 Log(("PGMR0SharedModuleCheck: shared page gc virt=%RGv phys %RGp host %RHp->%RHp\n", pRegions[idxRegion].GCRegionAddr + i * PAGE_SIZE, paPageDesc[i].GCPhys, PGM_PAGE_GET_HCPHYS(pPage), paPageDesc[i].HCPhys));139 if (paPageDesc[i].HCPhys != PGM_PAGE_GET_HCPHYS(pPage))140 {141 bool fFlush = false;142 143 /* Page was replaced by an existing shared version of it; clear all references first. */144 rc = pgmPoolTrackUpdateGCPhys(pVM, paPageDesc[i].GCPhys, pPage, true /* clear the entries */, &fFlush);145 if (RT_FAILURE(rc))146 {147 AssertRC(rc);148 goto end;149 }150 Assert(rc == VINF_SUCCESS || (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3) && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)));151 if (rc == VINF_SUCCESS)152 fFlushTLBs |= fFlush;153 154 /* Update the physical address and page id now. */155 PGM_PAGE_SET_HCPHYS(pPage, paPageDesc[i].HCPhys);156 PGM_PAGE_SET_PAGEID(pPage, paPageDesc[i].uHCPhysPageId);157 158 /* Invalidate page map TLB entry for this page too. */159 PGMPhysInvalidatePageMapTLBEntry(pVM, paPageDesc[i].GCPhys);160 pVM->pgm.s.cReusedSharedPages++;161 }162 /* else nothing changed (== this page is now a shared page), so no need to flush anything. */163 164 pVM->pgm.s.cSharedPages++;165 pVM->pgm.s.cPrivatePages--;166 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_SHARED);167 }168 }169 }170 else171 rc = VINF_SUCCESS; /* nothing to do. */172 129 } 173 130 174 end:175 131 pgmUnlock(pVM); 176 132 if (fFlushTLBs) 177 133 PGM_INVL_ALL_VCPU_TLBS(pVM); 178 179 if (paPageDesc)180 RTMemFree(paPageDesc);181 134 182 135 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.