GMM.cpp revision 5e0d5717f4742e9fc86690c4406e0af249336bbf
65fea56f17cd614bc8908264df980a62e1931468vboxsync/* $Id$ */
65fea56f17cd614bc8908264df980a62e1931468vboxsync/** @file
65fea56f17cd614bc8908264df980a62e1931468vboxsync * GMM - Global Memory Manager, ring-3 request wrappers.
65fea56f17cd614bc8908264df980a62e1931468vboxsync */
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync/*
65fea56f17cd614bc8908264df980a62e1931468vboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
65fea56f17cd614bc8908264df980a62e1931468vboxsync *
65fea56f17cd614bc8908264df980a62e1931468vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
65fea56f17cd614bc8908264df980a62e1931468vboxsync * available from http://www.virtualbox.org. This file is free software;
65fea56f17cd614bc8908264df980a62e1931468vboxsync * you can redistribute it and/or modify it under the terms of the GNU
65fea56f17cd614bc8908264df980a62e1931468vboxsync * General Public License (GPL) as published by the Free Software
65fea56f17cd614bc8908264df980a62e1931468vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
65fea56f17cd614bc8908264df980a62e1931468vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
65fea56f17cd614bc8908264df980a62e1931468vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
65fea56f17cd614bc8908264df980a62e1931468vboxsync *
65fea56f17cd614bc8908264df980a62e1931468vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
65fea56f17cd614bc8908264df980a62e1931468vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
65fea56f17cd614bc8908264df980a62e1931468vboxsync * additional information or have any questions.
65fea56f17cd614bc8908264df980a62e1931468vboxsync */
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync/*******************************************************************************
65fea56f17cd614bc8908264df980a62e1931468vboxsync* Header Files *
65fea56f17cd614bc8908264df980a62e1931468vboxsync*******************************************************************************/
65fea56f17cd614bc8908264df980a62e1931468vboxsync#define LOG_GROUP LOG_GROUP_GMM
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <VBox/gmm.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <VBox/vmm.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <VBox/vm.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <VBox/sup.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <VBox/err.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <VBox/param.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <iprt/assert.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <VBox/log.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync#include <iprt/mem.h>
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync/**
65fea56f17cd614bc8908264df980a62e1931468vboxsync * @see GMMR0InitialReservation
65fea56f17cd614bc8908264df980a62e1931468vboxsync */
65fea56f17cd614bc8908264df980a62e1931468vboxsyncGMMR3DECL(int) GMMR3InitialReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages,
65fea56f17cd614bc8908264df980a62e1931468vboxsync GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority)
65fea56f17cd614bc8908264df980a62e1931468vboxsync{
65fea56f17cd614bc8908264df980a62e1931468vboxsync GMMINITIALRESERVATIONREQ Req;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.Hdr.cbReq = sizeof(Req);
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.cBasePages = cBasePages;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.cShadowPages = cShadowPages;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.cFixedPages = cFixedPages;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.enmPolicy = enmPolicy;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.enmPriority = enmPriority;
65fea56f17cd614bc8908264df980a62e1931468vboxsync return VMMR3CallR0(pVM, VMMR0_DO_GMM_INITIAL_RESERVATION, 0, &Req.Hdr);
65fea56f17cd614bc8908264df980a62e1931468vboxsync}
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync/**
65fea56f17cd614bc8908264df980a62e1931468vboxsync * @see GMMR0UpdateReservation
65fea56f17cd614bc8908264df980a62e1931468vboxsync */
65fea56f17cd614bc8908264df980a62e1931468vboxsyncGMMR3DECL(int) GMMR3UpdateReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages)
65fea56f17cd614bc8908264df980a62e1931468vboxsync{
65fea56f17cd614bc8908264df980a62e1931468vboxsync GMMUPDATERESERVATIONREQ Req;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.Hdr.cbReq = sizeof(Req);
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.cBasePages = cBasePages;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.cShadowPages = cShadowPages;
65fea56f17cd614bc8908264df980a62e1931468vboxsync Req.cFixedPages = cFixedPages;
65fea56f17cd614bc8908264df980a62e1931468vboxsync return VMMR3CallR0(pVM, VMMR0_DO_GMM_UPDATE_RESERVATION, 0, &Req.Hdr);
65fea56f17cd614bc8908264df980a62e1931468vboxsync}
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync
65fea56f17cd614bc8908264df980a62e1931468vboxsync/**
65fea56f17cd614bc8908264df980a62e1931468vboxsync * Prepares a GMMR0AllocatePages request.
65fea56f17cd614bc8908264df980a62e1931468vboxsync *
65fea56f17cd614bc8908264df980a62e1931468vboxsync * @returns VINF_SUCCESS or VERR_NO_TMP_MEMORY.
65fea56f17cd614bc8908264df980a62e1931468vboxsync * @param pVM Pointer to the shared VM structure.
65fea56f17cd614bc8908264df980a62e1931468vboxsync * @param[out] ppReq Where to store the pointer to the request packet.
65fea56f17cd614bc8908264df980a62e1931468vboxsync * @param cPages The number of pages that's to be allocated.
65fea56f17cd614bc8908264df980a62e1931468vboxsync * @param enmAccount The account to charge.
65fea56f17cd614bc8908264df980a62e1931468vboxsync */
65fea56f17cd614bc8908264df980a62e1931468vboxsyncGMMR3DECL(int) GMMR3AllocatePagesPrepare(PVM pVM, PGMMALLOCATEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount)
65fea56f17cd614bc8908264df980a62e1931468vboxsync{
65fea56f17cd614bc8908264df980a62e1931468vboxsync uint32_t cb = RT_OFFSETOF(GMMALLOCATEPAGESREQ, aPages[cPages]);
65fea56f17cd614bc8908264df980a62e1931468vboxsync PGMMALLOCATEPAGESREQ pReq = (PGMMALLOCATEPAGESREQ)RTMemTmpAllocZ(cb);
if (!pReq)
return VERR_NO_TMP_MEMORY;
pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
pReq->Hdr.cbReq = cb;
pReq->enmAccount = enmAccount;
pReq->cPages = cPages;
NOREF(pVM);
*ppReq = pReq;
return VINF_SUCCESS;
}
/**
* Performs a GMMR0AllocatePages request.
* This will call VMSetError on failure.
*
* @returns VBox status code.
* @param pVM Pointer to the shared VM structure.
* @param pReq Pointer to the request (returned by GMMR3AllocatePagesPrepare).
*/
GMMR3DECL(int) GMMR3AllocatePagesPerform(PVM pVM, PGMMALLOCATEPAGESREQ pReq)
{
for (unsigned i = 0; ; i++)
{
int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_ALLOCATE_PAGES, 0, &pReq->Hdr);
if (RT_SUCCESS(rc))
{
#ifdef LOG_ENABLED
for (uint32_t iPage = 0; iPage < pReq->cPages; iPage++)
Log3(("GMMR3AllocatePagesPerform: idPage=%#x HCPhys=%RHp\n",
pReq->aPages[iPage].idPage, pReq->aPages[iPage].HCPhysGCPhys));
#endif
return rc;
}
if (rc != VERR_GMM_SEED_ME)
return VMSetError(pVM, rc, RT_SRC_POS,
N_("GMMR0AllocatePages failed to allocate %u pages"),
pReq->cPages);
Assert(i < pReq->cPages);
/*
* Seed another chunk.
*/
void *pvChunk;
rc = SUPR3PageAlloc(GMM_CHUNK_SIZE >> PAGE_SHIFT, &pvChunk);
if (RT_FAILURE(rc))
return VMSetError(pVM, rc, RT_SRC_POS,
N_("Out of memory (SUPR3PageAlloc) seeding a %u pages allocation request"),
pReq->cPages);
rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_SEED_CHUNK, (uintptr_t)pvChunk, NULL);
if (RT_FAILURE(rc))
return VMSetError(pVM, rc, RT_SRC_POS, N_("GMM seeding failed"));
}
}
/**
* Cleans up a GMMR0AllocatePages request.
* @param pReq Pointer to the request (returned by GMMR3AllocatePagesPrepare).
*/
GMMR3DECL(void) GMMR3AllocatePagesCleanup(PGMMALLOCATEPAGESREQ pReq)
{
RTMemTmpFree(pReq);
}
/**
* Prepares a GMMR0FreePages request.
*
* @returns VINF_SUCCESS or VERR_NO_TMP_MEMORY.
* @param pVM Pointer to the shared VM structure.
* @param[out] ppReq Where to store the pointer to the request packet.
* @param cPages The number of pages that's to be freed.
* @param enmAccount The account to charge.
*/
GMMR3DECL(int) GMMR3FreePagesPrepare(PVM pVM, PGMMFREEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount)
{
uint32_t cb = RT_OFFSETOF(GMMFREEPAGESREQ, aPages[cPages]);
PGMMFREEPAGESREQ pReq = (PGMMFREEPAGESREQ)RTMemTmpAllocZ(cb);
if (!pReq)
return VERR_NO_TMP_MEMORY;
pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
pReq->Hdr.cbReq = cb;
pReq->enmAccount = enmAccount;
pReq->cPages = cPages;
NOREF(pVM);
*ppReq = pReq;
return VINF_SUCCESS;
}
/**
* Re-prepares a GMMR0FreePages request.
*
* @returns VINF_SUCCESS or VERR_NO_TMP_MEMORY.
* @param pVM Pointer to the shared VM structure.
* @param pReq A request buffer previously returned by
* GMMR3FreePagesPrepare().
* @param cPages The number of pages originally passed to
* GMMR3FreePagesPrepare().
* @param enmAccount The account to charge.
*/
GMMR3DECL(void) GMMR3FreePagesRePrep(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cPages, GMMACCOUNT enmAccount)
{
Assert(pReq->Hdr.u32Magic == SUPVMMR0REQHDR_MAGIC);
pReq->Hdr.cbReq = RT_OFFSETOF(GMMFREEPAGESREQ, aPages[cPages]);
pReq->enmAccount = enmAccount;
pReq->cPages = cPages;
NOREF(pVM);
}
/**
* Performs a GMMR0FreePages request.
* This will call VMSetError on failure.
*
* @returns VBox status code.
* @param pVM Pointer to the shared VM structure.
* @param pReq Pointer to the request (returned by GMMR3FreePagesPrepare).
* @param cActualPages The number of pages actually freed.
*/
GMMR3DECL(int) GMMR3FreePagesPerform(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cActualPages)
{
/*
* Adjust the request if we ended up with fewer pages than anticipated.
*/
if (cActualPages != pReq->cPages)
{
AssertReturn(cActualPages < pReq->cPages, VERR_INTERNAL_ERROR);
if (!cActualPages)
return VINF_SUCCESS;
pReq->cPages = cActualPages;
pReq->Hdr.cbReq = RT_OFFSETOF(GMMFREEPAGESREQ, aPages[cActualPages]);
}
/*
* Do the job.
*/
int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_FREE_PAGES, 0, &pReq->Hdr);
if (RT_SUCCESS(rc))
return rc;
AssertRC(rc);
return VMSetError(pVM, rc, RT_SRC_POS,
N_("GMMR0FreePages failed to free %u pages"),
pReq->cPages);
}
/**
* Cleans up a GMMR0FreePages request.
* @param pReq Pointer to the request (returned by GMMR3FreePagesPrepare).
*/
GMMR3DECL(void) GMMR3FreePagesCleanup(PGMMFREEPAGESREQ pReq)
{
RTMemTmpFree(pReq);
}
/**
* Frees allocated pages, for bailing out on failure.
*
* This will not call VMSetError on failure but will use AssertLogRel instead.
*
* @param pVM Pointer to the shared VM structure.
* @param pAllocReq The allocation request to undo.
*/
GMMR3DECL(void) GMMR3FreeAllocatedPages(PVM pVM, GMMALLOCATEPAGESREQ const *pAllocReq)
{
uint32_t cb = RT_OFFSETOF(GMMFREEPAGESREQ, aPages[pAllocReq->cPages]);
PGMMFREEPAGESREQ pReq = (PGMMFREEPAGESREQ)RTMemTmpAllocZ(cb);
AssertLogRelReturnVoid(pReq);
pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
pReq->Hdr.cbReq = cb;
pReq->enmAccount = pAllocReq->enmAccount;
pReq->cPages = pAllocReq->cPages;
uint32_t iPage = pAllocReq->cPages;
while (iPage-- > 0)
{
Assert(pAllocReq->aPages[iPage].idPage != NIL_GMM_PAGEID);
pReq->aPages[iPage].idPage = pAllocReq->aPages[iPage].idPage;
}
int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_FREE_PAGES, 0, &pReq->Hdr);
AssertLogRelRC(rc);
RTMemTmpFree(pReq);
}
#if 0 /* impractical */
GMMR3DECL(int) GMMR3BalloonedPages(PVM pVM, uint32_t cBalloonedPages, uint32_t cPagesToFree, PGMMFREEPAGEDESC paPages, bool fCompleted)
{
GMMBALLOONEDPAGESREQ Req;
Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
Req.Hdr.cbReq = sizeof(Req);
return VMMR3CallR0(pVM, VMMR0_DO_GMM_BALLOONED_PAGES, 0, &Req.Hdr);
}
#endif
/**
* @see GMMR0DeflatedBalloon
*/
GMMR3DECL(int) GMMR3DeflatedBalloon(PVM pVM, uint32_t cPages)
{
return VMMR3CallR0(pVM, VMMR0_DO_GMM_DEFLATED_BALLOON, cPages, NULL);
}
/**
* @see GMMR0MapUnmapChunk
*/
GMMR3DECL(int) GMMR3MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3)
{
GMMMAPUNMAPCHUNKREQ Req;
Req.Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
Req.Hdr.cbReq = sizeof(Req);
Req.idChunkMap = idChunkMap;
Req.idChunkUnmap = idChunkUnmap;
Req.pvR3 = NULL;
int rc = VMMR3CallR0(pVM, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
if (RT_SUCCESS(rc) && ppvR3)
*ppvR3 = Req.pvR3;
return rc;
}
/**
* @see GMMR0SeedChunk
*/
GMMR3DECL(int) GMMR3SeedChunk(PVM pVM, RTR3PTR pvR3)
{
return VMMR3CallR0(pVM, VMMR0_DO_GMM_SEED_CHUNK, (uintptr_t)pvR3, NULL);
}