PGMR0SharedPage.cpp revision 2fb42335a74fe26c4e2bccbf16f077015e42a5e1
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/* $Id$ */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/** @file
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * PGM - Page Manager and Monitor, Ring-0.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2007 Oracle Corporation
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * available from http://www.virtualbox.org. This file is free software;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * you can redistribute it and/or modify it under the terms of the GNU
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * General Public License (GPL) as published by the Free Software
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/*******************************************************************************
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync* Header Files *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync*******************************************************************************/
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#define LOG_GROUP LOG_GROUP_PGM_SHARED
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/pgm.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/gmm.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include "../PGMInternal.h"
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/vm.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include "../PGMInline.h"
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/log.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <VBox/err.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/assert.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#include <iprt/mem.h>
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync#ifdef VBOX_WITH_PAGE_SHARING
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync/**
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * Check a registered module for shared page changes
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @returns The following VBox status codes.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync *
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pVM The VM handle.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param idCpu VCPU id
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pModule Module description
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param cRegions Number of regions
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pRegions Region array
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync * @param pGVM Pointer to the GVM instance data.
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsyncVMMR0DECL(int) PGMR0SharedModuleCheck(PVM pVM, PGVM pGVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, uint32_t cRegions, PGMMSHAREDREGIONDESC pRegions)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync{
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync int rc = VINF_SUCCESS;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PGMMSHAREDPAGEDESC paPageDesc = NULL;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync uint32_t cbPreviousRegion = 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync bool fFlushTLBs = false;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PVMCPU pVCpu = &pVM->aCpus[idCpu];
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Log(("PGMR0SharedModuleCheck: check %s %s base=%RGv size=%x\n", pModule->szName, pModule->szVersion, pModule->Core.Key, pModule->cbModule));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync pgmLock(pVM);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Check every region of the shared module. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (unsigned idxRegion = 0; idxRegion < cRegions; idxRegion++)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert((pRegions[idxRegion].cbRegion & 0xfff) == 0);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert((pRegions[idxRegion].GCRegionAddr & 0xfff) == 0);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTGCPTR GCRegion = pRegions[idxRegion].GCRegionAddr;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync unsigned cbRegion = pRegions[idxRegion].cbRegion & ~0xfff;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync unsigned idxPage = 0;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync bool fValidChanges = false;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (cbPreviousRegion < cbRegion)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (paPageDesc)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTMemFree(paPageDesc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync paPageDesc = (PGMMSHAREDPAGEDESC)RTMemAlloc((cbRegion >> PAGE_SHIFT) * sizeof(*paPageDesc));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!paPageDesc)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertFailed();
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = VERR_NO_MEMORY;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync goto end;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync cbPreviousRegion = cbRegion;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync while (cbRegion)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync RTGCPHYS GCPhys;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync uint64_t fFlags;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
c77e7bff89c7639353778366984d51ff165ea0e3vboxsync rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if ( rc == VINF_SUCCESS
c77e7bff89c7639353778366984d51ff165ea0e3vboxsync && !(fFlags & X86_PTE_RW)) /* important as we make assumptions about this below! */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
c77e7bff89c7639353778366984d51ff165ea0e3vboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(!pPage || !PGM_PAGE_IS_BALLOONED(pPage));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if ( pPage
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync && pPage->uStateY == PGM_PAGE_STATE_ALLOCATED)
501e3e846528298f82146d5afa36830a3f9b1267vboxsync {
501e3e846528298f82146d5afa36830a3f9b1267vboxsync fValidChanges = true;
501e3e846528298f82146d5afa36830a3f9b1267vboxsync paPageDesc[idxPage].uHCPhysPageId = PGM_PAGE_GET_PAGEID(pPage);
501e3e846528298f82146d5afa36830a3f9b1267vboxsync paPageDesc[idxPage].HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
501e3e846528298f82146d5afa36830a3f9b1267vboxsync paPageDesc[idxPage].GCPhys = GCPhys;
501e3e846528298f82146d5afa36830a3f9b1267vboxsync }
f7f5cd7b1e530eb5636da51c974b48ae0c1775b3vboxsync else
501e3e846528298f82146d5afa36830a3f9b1267vboxsync paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;
501e3e846528298f82146d5afa36830a3f9b1267vboxsync }
501e3e846528298f82146d5afa36830a3f9b1267vboxsync else
501e3e846528298f82146d5afa36830a3f9b1267vboxsync paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;
501e3e846528298f82146d5afa36830a3f9b1267vboxsync
501e3e846528298f82146d5afa36830a3f9b1267vboxsync idxPage++;
501e3e846528298f82146d5afa36830a3f9b1267vboxsync GCRegion += PAGE_SIZE;
501e3e846528298f82146d5afa36830a3f9b1267vboxsync cbRegion -= PAGE_SIZE;
501e3e846528298f82146d5afa36830a3f9b1267vboxsync }
501e3e846528298f82146d5afa36830a3f9b1267vboxsync
501e3e846528298f82146d5afa36830a3f9b1267vboxsync if (fValidChanges)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = GMMR0SharedModuleCheckRange(pGVM, pModule, idxRegion, idxPage, paPageDesc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertRC(rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync break;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync for (unsigned i = 0; i < idxPage; i++)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Any change for this page? */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /** todo: maybe cache these to prevent the nth lookup. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPageDesc[i].GCPhys);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (!pPage)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Should never happen. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertFailed();
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync goto end;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(pPage->uStateY == PGM_PAGE_STATE_ALLOCATED);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync 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));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (paPageDesc[i].HCPhys != PGM_PAGE_GET_HCPHYS(pPage))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync bool fFlush = false;
be9fcc1751f2ee5d873be8510fed59aad8f39a19vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Page was replaced by an existing shared version of it; clear all references first. */
be9fcc1751f2ee5d873be8510fed59aad8f39a19vboxsync rc = pgmPoolTrackUpdateGCPhys(pVM, paPageDesc[i].GCPhys, pPage, true /* clear the entries */, &fFlush);
be9fcc1751f2ee5d873be8510fed59aad8f39a19vboxsync if (RT_FAILURE(rc))
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync {
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync AssertRC(rc);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync goto end;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync }
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync Assert(rc == VINF_SUCCESS || (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3) && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)));
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync if (rc == VINF_SUCCESS)
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync fFlushTLBs |= fFlush;
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Update the physical address and page id now. */
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PGM_PAGE_SET_HCPHYS(pPage, paPageDesc[i].HCPhys);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync PGM_PAGE_SET_PAGEID(pPage, paPageDesc[i].uHCPhysPageId);
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync
1c2c968fd241148110002d75b2c0fdeddc211e14vboxsync /* Invalidate page map TLB entry for this page too. */
PGMPhysInvalidatePageMapTLBEntry(pVM, paPageDesc[i].GCPhys);
pVM->pgm.s.cReusedSharedPages++;
}
/* else nothing changed (== this page is now a shared page), so no need to flush anything. */
pVM->pgm.s.cSharedPages++;
pVM->pgm.s.cPrivatePages--;
PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_SHARED);
}
}
}
else
rc = VINF_SUCCESS; /* nothing to do. */
}
end:
pgmUnlock(pVM);
if (fFlushTLBs)
PGM_INVL_ALL_VCPU_TLBS(pVM);
if (paPageDesc)
RTMemFree(paPageDesc);
return rc;
}
#endif