Changeset 29468 in vbox for trunk/src/VBox/VMM/VMMR0
- Timestamp:
- May 14, 2010 12:16:44 PM (15 years ago)
- Location:
- trunk/src/VBox/VMM/VMMR0
- Files:
-
- 1 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR0/PGMR0.cpp
r29424 r29468 302 302 } 303 303 304 #ifdef VBOX_WITH_PAGE_SHARING305 /**306 * Check a registered module for shared page changes307 *308 * @returns The following VBox status codes.309 *310 * @param pVM The VM handle.311 * @param idCpu VCPU id312 * @param pModule Module description313 * @param pGVM Pointer to the GVM instance data.314 */315 VMMR0DECL(int) PGMR0SharedModuleCheckRegion(PVM pVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, PGVM pGVM)316 {317 int rc = VINF_SUCCESS;318 PGMMSHAREDPAGEDESC paPageDesc = NULL;319 uint32_t cbPreviousRegion = 0;320 bool fFlushTLBs = false;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));324 325 pgmLock(pVM);326 327 /* Check every region of the shared module. */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;335 unsigned idxPage = 0;336 bool fValidChanges = false;337 338 if (cbPreviousRegion < cbRegion)339 {340 if (paPageDesc)341 RTMemFree(paPageDesc);342 343 paPageDesc = (PGMMSHAREDPAGEDESC)RTMemAlloc((cbRegion >> PAGE_SHIFT) * sizeof(*paPageDesc));344 if (!paPageDesc)345 {346 AssertFailed();347 rc = VERR_NO_MEMORY;348 goto end;349 }350 cbPreviousRegion = cbRegion;351 }352 353 while (cbRegion)354 {355 RTGCPHYS GCPhys;356 uint64_t fFlags;357 358 rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys);359 if ( rc == VINF_SUCCESS360 && !(fFlags & X86_PTE_RW)) /* important as we make assumptions about this below! */361 {362 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);363 if ( pPage364 && !PGM_PAGE_IS_SHARED(pPage))365 {366 fValidChanges = true;367 paPageDesc[idxPage].uHCPhysPageId = PGM_PAGE_GET_PAGEID(pPage);368 paPageDesc[idxPage].HCPhys = PGM_PAGE_GET_HCPHYS(pPage);369 paPageDesc[idxPage].GCPhys = GCPhys;370 }371 else372 paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;373 }374 else375 paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;376 377 idxPage++;378 GCRegion += PAGE_SIZE;379 cbRegion -= PAGE_SIZE;380 }381 382 if (fValidChanges)383 {384 rc = GMMR0SharedModuleCheckRange(pGVM, pModule, i, idxPage, paPageDesc);385 AssertRC(rc);386 if (RT_FAILURE(rc))387 break;388 389 for (unsigned i = 0; i < idxPage; i++)390 {391 /* Any change for this page? */392 if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID)393 {394 /** todo: maybe cache these to prevent the nth lookup. */395 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPageDesc[i].GCPhys);396 if (!pPage)397 {398 /* Should never happen. */399 AssertFailed();400 rc = VERR_PGM_PHYS_INVALID_PAGE_ID;401 goto end;402 }403 Assert(!PGM_PAGE_IS_SHARED(pPage));404 405 Log(("PGMR0SharedModuleCheck: shared page gc phys %RGp host %RHp->%RHp\n", paPageDesc[i].GCPhys, PGM_PAGE_GET_HCPHYS(pPage), paPageDesc[i].HCPhys));406 if (paPageDesc[i].HCPhys != PGM_PAGE_GET_HCPHYS(pPage))407 {408 bool fFlush = false;409 410 /* Page was replaced by an existing shared version of it; clear all references first. */411 rc = pgmPoolTrackUpdateGCPhys(pVM, paPageDesc[i].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[i].HCPhys);423 PGM_PAGE_SET_PAGEID(pPage, paPageDesc[i].uHCPhysPageId);424 425 /* Invalidate page map TLB entry for this page too. */426 PGMPhysInvalidatePageMapTLBEntry(pVM, paPageDesc[i].GCPhys);427 }428 /* else nothing changed (== this page is now a shared page), so no need to flush anything. */429 430 pVM->pgm.s.cSharedPages++;431 pVM->pgm.s.cPrivatePages--;432 PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_SHARED);433 }434 }435 }436 else437 rc = VINF_SUCCESS; /* nothing to do. */438 }439 440 end:441 pgmUnlock(pVM);442 if (fFlushTLBs)443 PGM_INVL_ALL_VCPU_TLBS(pVM);444 445 if (paPageDesc)446 RTMemFree(paPageDesc);447 448 return rc;449 }450 #endif451 452 #if 0453 /**454 * Shared module registration helper (called on the way out).455 *456 * @param pVM The VM handle.457 * @param pReq Registration request info458 */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_SUCCESS488 && !(fFlags & X86_PTE_RW))489 {490 PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);491 if ( pPage492 && !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
Note:
See TracChangeset
for help on using the changeset viewer.