PGMSharedPage.cpp revision e1ccf9621a538102c214b259c612c41e2460fc5e
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/* $Id$ */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/** @file
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * PGM - Page Manager and Monitor, Shared page handling
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/*
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Copyright (C) 2006-2010 Oracle Corporation
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * available from http://www.virtualbox.org. This file is free software;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * you can redistribute it and/or modify it under the terms of the GNU
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * General Public License (GPL) as published by the Free Software
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/*******************************************************************************
e99772f9bf09219c532812c859fbeea513c67e65vboxsync* Header Files *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync*******************************************************************************/
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#define LOG_GROUP LOG_GROUP_PGM_SHARED
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <VBox/pgm.h>
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#include <VBox/stam.h>
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#include "PGMInternal.h"
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include "PGMInline.h"
62b88df0b51ed81807d485b371b90aff7dfd7beevboxsync#include <VBox/vm.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <VBox/sup.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <VBox/param.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <VBox/err.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <VBox/log.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/assert.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/asm.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/string.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#include <iprt/mem.h>
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Registers a new shared module for the VM
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns VBox status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pVM VM handle
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param enmGuestOS Guest OS type
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pszModuleName Module name
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pszVersion Module version
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param GCBaseAddr Module base address
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cbModule Module size
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cRegions Number of shared region descriptors
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pRegions Shared region(s)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncVMMR3DECL(int) PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule,
e99772f9bf09219c532812c859fbeea513c67e65vboxsync unsigned cRegions, VMMDEVSHAREDREGIONDESC *pRegions)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#ifdef VBOX_WITH_PAGE_SHARING
e99772f9bf09219c532812c859fbeea513c67e65vboxsync PGMMREGISTERSHAREDMODULEREQ pReq;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync Log(("PGMR3SharedModuleRegister family=%d name=%s version=%s base=%RGv size=%x cRegions=%d\n", enmGuestOS, pszModuleName, pszVersion, GCBaseAddr, cbModule, cRegions));
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Sanity check. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(cRegions < VMMDEVSHAREDREGIONDESC_MAX, VERR_INVALID_PARAMETER);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq = (PGMMREGISTERSHAREDMODULEREQ)RTMemAllocZ(RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[cRegions]));
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pReq, VERR_NO_MEMORY);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq->enmGuestOS = enmGuestOS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq->GCBaseAddr = GCBaseAddr;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq->cbModule = cbModule;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq->cRegions = cRegions;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync for (unsigned i = 0; i < cRegions; i++)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq->aRegions[i] = pRegions[i];
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if ( RTStrCopy(pReq->szName, sizeof(pReq->szName), pszModuleName) != VINF_SUCCESS
e99772f9bf09219c532812c859fbeea513c67e65vboxsync || RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion) != VINF_SUCCESS)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTMemFree(pReq);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VERR_BUFFER_OVERFLOW;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = GMMR3RegisterSharedModule(pVM, pReq);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTMemFree(pReq);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (RT_FAILURE(rc))
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VERR_NOT_IMPLEMENTED;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Unregisters a shared module for the VM
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns VBox status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pVM VM handle
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pszModuleName Module name
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pszVersion Module version
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param GCBaseAddr Module base address
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param cbModule Module size
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncVMMR3DECL(int) PGMR3SharedModuleUnregister(PVM pVM, char *pszModuleName, char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#ifdef VBOX_WITH_PAGE_SHARING
e99772f9bf09219c532812c859fbeea513c67e65vboxsync PGMMUNREGISTERSHAREDMODULEREQ pReq;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync Log(("PGMR3SharedModuleUnregister name=%s version=%s base=%RGv size=%x\n", pszModuleName, pszVersion, GCBaseAddr, cbModule));
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq = (PGMMUNREGISTERSHAREDMODULEREQ)RTMemAllocZ(sizeof(*pReq));
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertReturn(pReq, VERR_NO_MEMORY);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq->GCBaseAddr = GCBaseAddr;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pReq->cbModule = cbModule;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if ( RTStrCopy(pReq->szName, sizeof(pReq->szName), pszModuleName) != VINF_SUCCESS
e99772f9bf09219c532812c859fbeea513c67e65vboxsync || RTStrCopy(pReq->szVersion, sizeof(pReq->szVersion), pszVersion) != VINF_SUCCESS)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTMemFree(pReq);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VERR_BUFFER_OVERFLOW;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = GMMR3UnregisterSharedModule(pVM, pReq);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTMemFree(pReq);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VERR_NOT_IMPLEMENTED;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#ifdef VBOX_WITH_PAGE_SHARING
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Rendezvous callback that will be called once.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns VBox strict status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pVM VM handle.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pVCpu The VMCPU handle for the calling EMT.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pvUser Not used;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstatic DECLCALLBACK(VBOXSTRICTRC) pgmR3SharedModuleRegRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Flush all pending handy page operations before changing any shared page assignments. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = PGMR3PhysAllocateHandyPages(pVM);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertRC(rc);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Lock it here as we can't deal with busy locks in this ring-0 path. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pgmLock(pVM);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = GMMR3CheckSharedModules(pVM);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pgmUnlock(pVM);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Shared module check helper (called on the way out).
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pVM The VM handle.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncstatic DECLCALLBACK(void) pgmR3CheckSharedModulesHelper(PVM pVM)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, NULL);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync AssertRC(rc);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Check all registered modules for changes.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns VBox status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pVM VM handle
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncVMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#ifdef VBOX_WITH_PAGE_SHARING
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Queue the actual registration as we are under the IOM lock right now. Perform this operation on the way out. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VMR3ReqCallNoWait(pVM, VMMGetCpuId(pVM), (PFNRT)pgmR3CheckSharedModulesHelper, 1, pVM);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VERR_NOT_IMPLEMENTED;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync/**
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * Query the state of a page in a shared module
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @returns VBox status code.
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pVM VM handle
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param GCPtrPage Page address
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param pfShared Shared status (out)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync * @param puPageFlags Page flags (out)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync */
e99772f9bf09219c532812c859fbeea513c67e65vboxsyncVMMR3DECL(int) PGMR3SharedModuleGetPageState(PVM pVM, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *puPageFlags)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync{
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#if defined(VBOX_WITH_PAGE_SHARING) && defined(DEBUG)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync /* Debug only API for the page fusion testcase. */
e99772f9bf09219c532812c859fbeea513c67e65vboxsync RTGCPHYS GCPhys;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync uint64_t fFlags;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pgmLock(pVM);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync int rc = PGMGstGetPage(VMMGetCpu(pVM), GCPtrPage, &fFlags, &GCPhys);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync switch (rc)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case VINF_SUCCESS:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync if (pPage)
e99772f9bf09219c532812c859fbeea513c67e65vboxsync {
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *pfShared = PGM_PAGE_IS_SHARED(pPage);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *puPageFlags = fFlags;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case VERR_PAGE_NOT_PRESENT:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case VERR_PAGE_TABLE_NOT_PRESENT:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case VERR_PAGE_MAP_LEVEL4_NOT_PRESENT:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync case VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *pfShared = false;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync *puPageFlags = 0;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync rc = VINF_SUCCESS;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync default:
e99772f9bf09219c532812c859fbeea513c67e65vboxsync break;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync }
e99772f9bf09219c532812c859fbeea513c67e65vboxsync
e99772f9bf09219c532812c859fbeea513c67e65vboxsync pgmUnlock(pVM);
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return rc;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#else
e99772f9bf09219c532812c859fbeea513c67e65vboxsync return VERR_NOT_IMPLEMENTED;
e99772f9bf09219c532812c859fbeea513c67e65vboxsync#endif
e99772f9bf09219c532812c859fbeea513c67e65vboxsync}
e99772f9bf09219c532812c859fbeea513c67e65vboxsync