Changeset 29168 in vbox for trunk/src/VBox/VMM
- Timestamp:
- May 6, 2010 4:01:48 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 61241
- Location:
- trunk/src/VBox/VMM/VMMR0
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/GMMR0.cpp
r29138 r29168 214 214 struct GMMPAGESHARED 215 215 { 216 /** The reference count. */ 217 uint32_t cRefs; 216 /** The guest page frame number. (Max addressable: 2 ^ 44 - 16) */ 217 uint32_t pfn; 218 /** The reference count (64K VMs). */ 219 uint32_t cRefs : 16; 218 220 /** Reserved. Checksum or something? Two hGVMs for forking? */ 219 uint32_t u30Reserved : 30;221 uint32_t u30Reserved : 14; 220 222 /** The page state. */ 221 223 uint32_t u2State : 2; … … 2402 2404 if (RT_UNLIKELY(pGVM->gmm.s.Allocated.cBasePages < cPages)) 2403 2405 { 2404 Log((" gmmR0FreePages: allocated=%#llx cPages=%#x!\n", pGVM->gmm.s.Allocated.cBasePages, cPages));2406 Log(("GMMR0FreeLargePage: allocated=%#llx cPages=%#x!\n", pGVM->gmm.s.Allocated.cBasePages, cPages)); 2405 2407 RTSemFastMutexRelease(pGMM->Mtx); 2406 2408 return VERR_GMM_ATTEMPT_TO_FREE_TOO_MUCH; … … 3188 3190 } 3189 3191 3192 /** 3193 * Check if a chunk is mapped into the specified VM 3194 * 3195 * @returns mapped yes/no 3196 * @param pGVM Pointer to the Global VM structure. 3197 * @param pChunk Pointer to the chunk to be mapped. 3198 * @param ppvR3 Where to store the ring-3 address of the mapping. 3199 */ 3200 static int gmmR0IsChunkMapped(PGVM pGVM, PGMMCHUNK pChunk, PRTR3PTR ppvR3) 3201 { 3202 /* 3203 * Check to see if the chunk is already mapped. 3204 */ 3205 for (uint32_t i = 0; i < pChunk->cMappings; i++) 3206 { 3207 Assert(pChunk->paMappings[i].pGVM && pChunk->paMappings[i].MapObj != NIL_RTR0MEMOBJ); 3208 if (pChunk->paMappings[i].pGVM == pGVM) 3209 { 3210 *ppvR3 = RTR0MemObjAddressR3(pChunk->paMappings[i].MapObj); 3211 return true; 3212 } 3213 } 3214 *ppvR3 = NULL; 3215 return false; 3216 } 3190 3217 3191 3218 /** … … 3405 3432 if (!pRecVM) 3406 3433 { 3407 pRecVM = (PGMMSHAREDMODULEPERVM)RTMemAllocZ( sizeof(*pRecVM));3434 pRecVM = (PGMMSHAREDMODULEPERVM)RTMemAllocZ(RT_OFFSETOF(GMMSHAREDMODULEPERVM, aRegions[cRegions])); 3408 3435 if (!pRecVM) 3409 3436 { … … 3420 3447 pRecVM->aRegions[i].cbRegion = pRegions[i].cbRegion; 3421 3448 pRecVM->aRegions[i].u32Alignment = 0; 3422 pRecVM->aRegions[i].paHCPhys AndPageID = 0; /* uninitialized. */3449 pRecVM->aRegions[i].paHCPhysPageID = NULL; /* uninitialized. */ 3423 3450 } 3424 3451 … … 3432 3459 3433 3460 /* Check if this module is already globally registered. */ 3434 PGMMSHAREDMODULE p Rec= (PGMMSHAREDMODULE)RTAvlGCPtrGet(&pGMM->pGlobalSharedModuleTree, GCBaseAddr);3435 if (!p Rec)3461 PGMMSHAREDMODULE pGlobalModule = (PGMMSHAREDMODULE)RTAvlGCPtrGet(&pGMM->pGlobalSharedModuleTree, GCBaseAddr); 3462 if (!pGlobalModule) 3436 3463 { 3437 3464 Assert(fNewModule); 3438 3465 Assert(!pRecVM->fCollision); 3439 3466 3440 p Rec= (PGMMSHAREDMODULE)RTMemAllocZ(RT_OFFSETOF(GMMSHAREDMODULE, aRegions[cRegions]));3441 if (!p Rec)3467 pGlobalModule = (PGMMSHAREDMODULE)RTMemAllocZ(RT_OFFSETOF(GMMSHAREDMODULE, aRegions[cRegions])); 3468 if (!pGlobalModule) 3442 3469 { 3443 3470 AssertFailed(); … … 3446 3473 } 3447 3474 3448 p Rec->Core.Key = GCBaseAddr;3449 p Rec->cbModule = cbModule;3475 pGlobalModule->Core.Key = GCBaseAddr; 3476 pGlobalModule->cbModule = cbModule; 3450 3477 /* Input limit already safe; no need to check again. */ 3451 3478 /** todo replace with RTStrCopy */ 3452 strcpy(p Rec->szName, pszModuleName);3453 strcpy(p Rec->szVersion, pszVersion);3454 3455 p Rec->cRegions = cRegions;3479 strcpy(pGlobalModule->szName, pszModuleName); 3480 strcpy(pGlobalModule->szVersion, pszVersion); 3481 3482 pGlobalModule->cRegions = cRegions; 3456 3483 3457 3484 for (unsigned i = 0; i < cRegions; i++) 3458 3485 { 3459 p Rec->aRegions[i].GCRegionAddr = pRegions[i].GCRegionAddr;3460 p Rec->aRegions[i].cbRegion = pRegions[i].cbRegion;3461 p Rec->aRegions[i].u32Alignment = 0;3462 p Rec->aRegions[i].paHCPhysAndPageID = 0; /* uninitialized. */3486 pGlobalModule->aRegions[i].GCRegionAddr = pRegions[i].GCRegionAddr; 3487 pGlobalModule->aRegions[i].cbRegion = pRegions[i].cbRegion; 3488 pGlobalModule->aRegions[i].u32Alignment = 0; 3489 pGlobalModule->aRegions[i].paHCPhysPageID = NULL; /* uninitialized. */ 3463 3490 } 3464 3491 3465 3492 /* Save reference. */ 3466 pRecVM->p SharedModule = pRec;3493 pRecVM->pGlobalModule = pGlobalModule; 3467 3494 pRecVM->fCollision = false; 3468 p Rec->cUsers++;3495 pGlobalModule->cUsers++; 3469 3496 rc = VINF_SUCCESS; 3470 3497 } 3471 3498 else 3472 3499 { 3473 Assert(p Rec->cUsers > 0);3500 Assert(pGlobalModule->cUsers > 0); 3474 3501 3475 3502 /* Make sure the name and version are identical. */ 3476 3503 /** todo replace with RTStrNCmp */ 3477 if ( !strcmp(p Rec->szName, pszModuleName)3478 && !strcmp(p Rec->szVersion, pszVersion))3504 if ( !strcmp(pGlobalModule->szName, pszModuleName) 3505 && !strcmp(pGlobalModule->szVersion, pszVersion)) 3479 3506 { 3480 3507 Assert(!pRecVM->fCollision); 3481 3508 3482 3509 /* Save reference. */ 3483 pRecVM->p SharedModule = pRec;3510 pRecVM->pGlobalModule = pGlobalModule; 3484 3511 pRecVM->fCollision = false; 3485 3512 if (fNewModule) 3486 p Rec->cUsers++;3513 pGlobalModule->cUsers++; 3487 3514 rc = VINF_SUCCESS; 3488 3515 } … … 3568 3595 /* Force pRec to go out of scope after freeing it. */ 3569 3596 { 3570 PGMMSHAREDMODULE pRec = pRecVM->p SharedModule;3597 PGMMSHAREDMODULE pRec = pRecVM->pGlobalModule; 3571 3598 Assert(pRec); 3572 3599 Assert(pRec->cUsers); … … 3577 3604 /* @todo free shared pages. */ 3578 3605 for (unsigned i = 0; i < pRec->cRegions; i++) 3579 if (pRec->aRegions[i].paHCPhys AndPageID)3580 RTMemFree(pRec->aRegions[i].paHCPhys AndPageID);3606 if (pRec->aRegions[i].paHCPhysPageID) 3607 RTMemFree(pRec->aRegions[i].paHCPhysPageID); 3581 3608 3582 3609 RTMemFree(pRec); 3583 3610 } 3584 3611 } 3585 3612 /* Free all the shared pages we refence here. */ 3586 3613 for (unsigned i = 0; i < pRecVM->cRegions; i++) 3587 if (pRecVM->aRegions[i].paHCPhysAndPageID) 3588 RTMemFree(pRecVM->aRegions[i].paHCPhysAndPageID); 3614 { 3615 PGMMSHAREDREGIONDESC pRegion = &pRecVM->aRegions[i]; 3616 3617 if (pRegion->paHCPhysPageID) 3618 { 3619 unsigned cPages = pRegion->cbRegion >> PAGE_SHIFT; 3620 3621 for (unsigned j = 0; j < cPages; j++) 3622 { 3623 if (pRegion->paHCPhysPageID[j] != NIL_GMM_PAGEID) 3624 { 3625 GMMFREEPAGEDESC PageDesc; 3626 3627 PageDesc.idPage = pRegion->paHCPhysPageID[j]; 3628 rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE); 3629 AssertRC(rc); 3630 } 3631 } 3632 3633 RTMemFree(pRecVM->aRegions[i].paHCPhysPageID); 3634 } 3635 } 3589 3636 RTMemFree(pRecVM); 3590 3637 … … 3627 3674 * Checks specified shared module range for changes 3628 3675 * 3676 * Performs the following tasks: 3677 * - if a shared page is new, then it changes the GMM page type to shared and returns it in the paHCPhysPageID array 3678 * - 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 paHCPhysPageID array 3679 * 3629 3680 * @returns VBox status code. 3630 3681 * @param pVM VM handle … … 3633 3684 * @param idxRegion Region index 3634 3685 * @param cPages Number of entries in the paHCPhysAndPageID array 3635 * @param pa HCPhysAndPageID Host physical address and the Page ID array3636 */ 3637 GMMR0DECL(int) GMMR0SharedModuleCheckRange(PVM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq, unsigned idxRegion, unsigned cPages, PRTHCPHYS paHCPhysAndPageID)3686 * @param paPageDesc Page descriptor array (in/out) 3687 */ 3688 GMMR0DECL(int) GMMR0SharedModuleCheckRange(PVM pVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq, unsigned idxRegion, unsigned cPages, PGMMSHAREDPAGEDESC paPageDesc) 3638 3689 { 3639 3690 AssertReturn(idxRegion < pReq->cRegions, VERR_INVALID_PARAMETER); … … 3657 3708 if (GMM_CHECK_SANITY_UPON_ENTERING(pGMM)) 3658 3709 { 3659 PGMMSHAREDMODULEPERVM pRecVM = (PGMMSHAREDMODULEPERVM)RTAvlGCPtrGet(&pGVM->gmm.s.pSharedModuleTree, pReq->GCBaseAddr); 3660 if (!pRecVM) 3661 { 3710 PGMMSHAREDMODULEPERVM pLocalModule = (PGMMSHAREDMODULEPERVM)RTAvlGCPtrGet(&pGVM->gmm.s.pSharedModuleTree, pReq->GCBaseAddr); 3711 if ( !pLocalModule 3712 || pLocalModule->fCollision) 3713 { 3714 Assert(!pLocalModule); 3662 3715 rc = VERR_PGM_SHARED_MODULE_NOT_FOUND; 3663 3716 goto end; 3664 3717 } 3665 3718 PGMMSHAREDREGIONDESC pLocalRegion = &pLocalModule->aRegions[idxRegion]; 3719 if (!pLocalRegion->paHCPhysPageID) 3720 { 3721 /* First time; create a page descriptor array. */ 3722 pLocalRegion->paHCPhysPageID = (uint32_t *)RTMemAlloc(cPages * sizeof(*pLocalRegion->paHCPhysPageID)); 3723 if (!pLocalRegion->paHCPhysPageID) 3724 { 3725 AssertFailed(); 3726 rc = VERR_NO_MEMORY; 3727 goto end; 3728 } 3729 /* Invalidate all descriptors. */ 3730 for (unsigned i = 0; i < cPages; i++) 3731 pLocalRegion->paHCPhysPageID[i] = NIL_GMM_PAGEID; 3732 } 3733 3734 PGMMSHAREDMODULE pGlobalModule = pLocalModule->pGlobalModule; 3735 PGMMSHAREDREGIONDESC pGlobalRegion = &pGlobalModule->aRegions[idxRegion]; 3736 3737 if (!pGlobalRegion->paHCPhysPageID) 3738 { 3739 /* First time; create a page descriptor array. */ 3740 pGlobalRegion->paHCPhysPageID = (uint32_t *)RTMemAlloc(cPages * sizeof(*pGlobalRegion->paHCPhysPageID)); 3741 if (!pGlobalRegion->paHCPhysPageID) 3742 { 3743 AssertFailed(); 3744 rc = VERR_NO_MEMORY; 3745 goto end; 3746 } 3747 /* Invalidate all descriptors. */ 3748 for (unsigned i = 0; i < cPages; i++) 3749 pGlobalRegion->paHCPhysPageID[i] = NIL_GMM_PAGEID; 3750 } 3751 3752 /* Check all pages in the region. */ 3666 3753 for (unsigned i = 0; i < cPages; i++) 3667 3754 { 3755 /* Valid page present? */ 3756 if (paPageDesc[i].uPageId != NIL_GMM_PAGEID) 3757 { 3758 /* We've seen this shared page for the first time? */ 3759 if (pGlobalRegion->paHCPhysPageID[i] == NIL_GMM_PAGEID) 3760 { 3761 Assert(pLocalRegion->paHCPhysPageID[i] == NIL_GMM_PAGEID); 3762 3763 /* Easy case: just change the internal page type. */ 3764 PGMMPAGE pPage = gmmR0GetPage(pGMM, paPageDesc[i].uPageId); 3765 if (!pPage) 3766 { 3767 AssertFailed(); 3768 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3769 goto end; 3770 } 3771 Assert(paPageDesc[i].HCPhys == (pPage->Private.pfn << 12)); 3772 pPage->Shared.pfn = pPage->Private.pfn; /* same location */ 3773 pPage->Shared.cRefs = 1; 3774 pPage->Common.u2State = GMM_PAGE_STATE_SHARED; 3775 3776 /* Keep track of these references. */ 3777 pLocalRegion->paHCPhysPageID[i] = paPageDesc[i].uPageId; 3778 pGlobalRegion->paHCPhysPageID[i] = paPageDesc[i].uPageId; 3779 } 3780 else 3781 { 3782 Assert(pLocalRegion->paHCPhysPageID[i] != pGlobalRegion->paHCPhysPageID[i]); 3783 3784 PGMMPAGE pPage = gmmR0GetPage(pGMM, paPageDesc[i].uPageId); 3785 if (!pPage) 3786 { 3787 AssertFailed(); 3788 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 3789 goto end; 3790 } 3791 Assert(pPage->Common.u2State == GMM_PAGE_STATE_SHARED); 3792 3793 PGMMCHUNK pChunk = gmmR0GetChunk(pGMM, paPageDesc[i].uPageId >> GMM_CHUNKID_SHIFT); 3794 Assert(pChunk); /* can't fail as gmmR0GetPage succeeded. */ 3795 uint8_t *pbR3Page, *pbR3Chunk; 3796 3797 /* Get the virtual address of the physical page; map the chunk into the VM process if not already done. */ 3798 if (!gmmR0IsChunkMapped(pGVM, pChunk, (PRTR3PTR)&pbR3Chunk)) 3799 { 3800 rc = gmmR0MapChunk(pGMM, pGVM, pChunk, (PRTR3PTR)&pbR3Chunk); 3801 if (rc != VINF_SUCCESS) 3802 { 3803 AssertRC(rc); 3804 goto end; 3805 } 3806 } 3807 pbR3Page = pbR3Chunk + ((paPageDesc[i].uPageId & GMM_PAGEID_IDX_MASK) << PAGE_SHIFT); 3808 3809 /* Free the old local page. */ 3810 GMMFREEPAGEDESC PageDesc; 3811 3812 PageDesc.idPage = pLocalRegion->paHCPhysPageID[i]; 3813 rc = gmmR0FreePages(pGMM, pGVM, 1, &PageDesc, GMMACCOUNT_BASE); 3814 AssertRC(rc); 3815 3816 /* Pass along the new physical address & page id. */ 3817 paPageDesc[i].HCPhys = (pPage->Private.pfn << 12); 3818 paPageDesc[i].uPageId = pGlobalRegion->paHCPhysPageID[i]; 3819 3820 pLocalRegion->paHCPhysPageID[i] = pGlobalRegion->paHCPhysPageID[i]; 3821 } 3822 } 3823 #ifdef LOG_ENABLED 3824 else 3825 if (pLocalRegion->paHCPhysPageID[i] != NIL_GMM_PAGEID) 3826 { 3827 /* Page was removed. */ 3828 Log(("GMMR0SharedModuleCheckRange: page id %x not present anymore\n", pLocalRegion->paHCPhysPageID[i])); 3829 } 3830 #endif 3668 3831 } 3669 3832 -
trunk/src/VBox/VMM/VMMR0/GMMR0Internal.h
r29138 r29168 49 49 /** Alignment. */ 50 50 uint32_t u32Alignment; 51 /** Pointer to physical page addressarray. */52 PRTHCPHYS paHCPhysAndPageID;51 /** Pointer to physical page id array. */ 52 uint32_t *paHCPhysPageID; 53 53 } GMMSHAREDREGIONDESC; 54 54 /** Pointer to a GMMSHAREDREGIONDESC. */ … … 85 85 typedef struct GMMSHAREDMODULEPERVM 86 86 { 87 /* Tree node. */87 /** Tree node. */ 88 88 AVLGCPTRNODECORE Core; 89 89 90 /* Pointer to global shared module info. */91 PGMMSHAREDMODULE p SharedModule;90 /** Pointer to global shared module info. */ 91 PGMMSHAREDMODULE pGlobalModule; 92 92 93 /* Set if another VM registered a different shared module at the same base address. */93 /** Set if another VM registered a different shared module at the same base address. */ 94 94 bool fCollision; 95 /** Align at 8 byte boundary*/96 bool abAlignment[7];95 /** Alignment. */ 96 bool bAlignment; 97 97 98 /** Number of regions in the aRegions array. */98 /** Number of regions. */ 99 99 unsigned cRegions; 100 101 100 /** Shared region descriptor(s). */ 102 101 GMMSHAREDREGIONDESC aRegions[1]; -
trunk/src/VBox/VMM/VMMR0/PGMR0.cpp
r29138 r29168 313 313 VMMR0DECL(int) PGMR0SharedModuleCheck(PVM pVM, PVMCPU pVCpu, PGMMREGISTERSHAREDMODULEREQ pReq) 314 314 { 315 int rc = VINF_SUCCESS; 316 PRTHCPHYS paHCPhysAndPageID = NULL; 317 uint32_t cbPreviousRegion = 0; 315 int rc = VINF_SUCCESS; 316 PGMMSHAREDPAGEDESC paPageDesc = NULL; 317 uint32_t cbPreviousRegion = 0; 318 bool fFlushTLBs = false; 318 319 319 320 /* … … 338 339 if (cbPreviousRegion < cbRegion) 339 340 { 340 if (pa HCPhysAndPageID)341 RTMemFree(pa HCPhysAndPageID);342 343 pa HCPhysAndPageID = (PRTHCPHYS)RTMemAlloc((cbRegion << PAGE_SHIFT) * sizeof(*paHCPhysAndPageID));344 if (!pa HCPhysAndPageID)341 if (paPageDesc) 342 RTMemFree(paPageDesc); 343 344 paPageDesc = (PGMMSHAREDPAGEDESC)RTMemAlloc((cbRegion << PAGE_SHIFT) * sizeof(*paPageDesc)); 345 if (!paPageDesc) 345 346 { 346 347 AssertFailed(); … … 365 366 { 366 367 fValidChanges = true; 367 paHCPhysAndPageID[idxPage] = pPage->HCPhysAndPageID; 368 paPageDesc[idxPage].uPageId = PGM_PAGE_GET_PAGEID(pPage); 369 paPageDesc[idxPage].HCPhys = PGM_PAGE_GET_HCPHYS(pPage); 370 paPageDesc[idxPage].GCPhys = GCPhys; 368 371 } 369 372 else 370 pa HCPhysAndPageID[idxPage] = NIL_RTHCPHYS;373 paPageDesc[idxPage].uPageId = NIL_GMM_PAGEID; 371 374 } 372 375 else 373 pa HCPhysAndPageID[idxPage] = NIL_RTHCPHYS;376 paPageDesc[idxPage].uPageId = NIL_GMM_PAGEID; 374 377 375 378 idxPage++; … … 380 383 if (fValidChanges) 381 384 { 382 rc = GMMR0SharedModuleCheckRange(pVM, pVCpu->idCpu, pReq, i, idxPage, pa HCPhysAndPageID);385 rc = GMMR0SharedModuleCheckRange(pVM, pVCpu->idCpu, pReq, i, idxPage, paPageDesc); 383 386 AssertRC(rc); 384 387 if (RT_FAILURE(rc)) 385 388 break; 389 390 for (unsigned i = 0; i < idxPage; i++) 391 { 392 /* Any change for this page? */ 393 if (paPageDesc[i].uPageId != NIL_GMM_PAGEID) 394 { 395 /** todo: maybe cache these to prevent the nth lookup. */ 396 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPageDesc[idxPage].GCPhys); 397 if (!pPage) 398 { 399 /* Should never happen. */ 400 AssertFailed(); 401 rc = VERR_PGM_PHYS_INVALID_PAGE_ID; 402 goto end; 403 } 404 Assert(!PGM_PAGE_IS_SHARED(pPage)); 405 406 if (paPageDesc[idxPage].HCPhys != PGM_PAGE_GET_HCPHYS(pPage)) 407 { 408 bool fFlush = false; 409 410 /* Page was replaced by an existing shared version of it; dereference the page first. */ 411 rc = pgmPoolTrackUpdateGCPhys(pVM, paPageDesc[idxPage].GCPhys, pPage, true /* clear the entries */, &fFlush); 412 if (RT_FAILURE(rc)) 413 { 414 AssertRC(rc); 415 goto end; 416 } 417 Assert(rc == VINF_SUCCESS || (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3) && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL))); 418 if (rc = VINF_SUCCESS) 419 fFlushTLBs |= fFlush; 420 421 /* Update the physical address and page id now. */ 422 PGM_PAGE_SET_HCPHYS(pPage, paPageDesc[idxPage].HCPhys); 423 PGM_PAGE_SET_PAGEID(pPage, paPageDesc[idxPage].uPageId); 424 } 425 /* else nothing changed (== this page is now a shared page), so no need to flush anything. */ 426 427 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_SHARED); 428 } 429 } 386 430 } 387 431 } … … 389 433 end: 390 434 pgmUnlock(pVM); 391 if (paHCPhysAndPageID) 392 RTMemFree(paHCPhysAndPageID); 435 if (fFlushTLBs) 436 PGM_INVL_ALL_VCPU_TLBS(pVM); 437 438 if (paPageDesc) 439 RTMemFree(paPageDesc); 393 440 394 441 return rc;
Note:
See TracChangeset
for help on using the changeset viewer.