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