PGMPhys.cpp revision f3e9d2446012445807621d8dd95afb2c8cad2789
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * PGM - Page Manager and Monitor, Physical Memory Addressing.
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * Copyright (C) 2006-2007 Oracle Corporation
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * available from http://www.virtualbox.org. This file is free software;
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * you can redistribute it and/or modify it under the terms of the GNU
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * General Public License (GPL) as published by the Free Software
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
94872a0e88ab4f38c786fcf617ddeb4b63a76957vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync/*******************************************************************************
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync* Header Files *
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync*******************************************************************************/
78a072e1b56619e3230735ae073668311232ec94vboxsync/*******************************************************************************
cc260ed3418d1fd2771d0395f818f76808b60238vboxsync* Defined Constants And Macros *
78a072e1b56619e3230735ae073668311232ec94vboxsync*******************************************************************************/
78a072e1b56619e3230735ae073668311232ec94vboxsync/** The number of pages to free in one batch. */
94c538a65fbdfa1ea06f4fe0a65599c1ab0fed58vboxsync/*******************************************************************************
d0318084c32279bf313f47358242cd61ada858d6vboxsync* Internal Functions *
94c538a65fbdfa1ea06f4fe0a65599c1ab0fed58vboxsync*******************************************************************************/
d5d45608052fd506e4114bf112df6efae7fcd8a7vboxsyncstatic DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser);
d5d45608052fd506e4114bf112df6efae7fcd8a7vboxsyncstatic int pgmPhysFreePage(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t *pcPendingPages, PPGMPAGE pPage, RTGCPHYS GCPhys);
78a072e1b56619e3230735ae073668311232ec94vboxsync * PGMR3PhysReadU8-64
78a072e1b56619e3230735ae073668311232ec94vboxsync * PGMR3PhysWriteU8-64
78a072e1b56619e3230735ae073668311232ec94vboxsync * EMT worker for PGMR3PhysReadExternal.
78a072e1b56619e3230735ae073668311232ec94vboxsyncstatic DECLCALLBACK(int) pgmR3PhysReadExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, void *pvBuf, size_t cbRead)
78a072e1b56619e3230735ae073668311232ec94vboxsync * Write to physical memory, external users.
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * @returns VBox status code.
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync * @retval VINF_SUCCESS.
c3d2b15ad840b405062f4c2c6b127d6fc107c7b2vboxsync * @param pVM VM Handle.
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * @param GCPhys Physical address to write to.
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * @param pvBuf What to write.
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * @param cbWrite How many bytes to write.
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * @thread Any but EMTs.
67927207a2d6bb545eb655ef14cdb090b1957120vboxsyncVMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync AssertMsgReturn(cbRead > 0, ("don't even think about reading zero bytes!\n"), VINF_SUCCESS);
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync LogFlow(("PGMR3PhysReadExternal: %RGp %d\n", GCPhys, cbRead));
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * Copy loop on ram ranges.
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync /* Find range. */
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync /* Inside range or not? */
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * Must work our way thru this page by page.
223a6730e81629b0bf552ccc31f119a998cc8e27vboxsync * If the page has an ALL access handler, we'll have to
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync * delegate the job to EMT.
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysReadExternalEMT, 4,
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync * Simple stuff, go ahead.
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync const void *pvSrc;
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync int rc = pgmPhysGCPhys2CCPtrInternalReadOnly(pVM, pPage, pRam->GCPhys + off, &pvSrc);
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync /* next page */
6804e4c1c12ab612ad6257a4922309c476c204e5vboxsync } /* walk pages in ram range. */
78a072e1b56619e3230735ae073668311232ec94vboxsync LogFlow(("PGMPhysRead: Unassigned %RGp size=%u\n", GCPhys, cbRead));
78a072e1b56619e3230735ae073668311232ec94vboxsync * Unassigned address space.
78a072e1b56619e3230735ae073668311232ec94vboxsync } /* Ram range walk */
78a072e1b56619e3230735ae073668311232ec94vboxsync * EMT worker for PGMR3PhysWriteExternal.
78a072e1b56619e3230735ae073668311232ec94vboxsyncstatic DECLCALLBACK(int) pgmR3PhysWriteExternalEMT(PVM pVM, PRTGCPHYS pGCPhys, const void *pvBuf, size_t cbWrite)
78a072e1b56619e3230735ae073668311232ec94vboxsync /** @todo VERR_EM_NO_MEMORY */
78a072e1b56619e3230735ae073668311232ec94vboxsync * Write to physical memory, external users.
1637773d6c473e4ab75812805ef00226f3a397c0vboxsync * @returns VBox status code.
1637773d6c473e4ab75812805ef00226f3a397c0vboxsync * @retval VINF_SUCCESS.
1637773d6c473e4ab75812805ef00226f3a397c0vboxsync * @retval VERR_EM_NO_MEMORY.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pVM VM Handle.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param GCPhys Physical address to write to.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pvBuf What to write.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param cbWrite How many bytes to write.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pszWho Who is writing. For tracking down who is writing
78a072e1b56619e3230735ae073668311232ec94vboxsync * after we've saved the state.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @thread Any but EMTs.
78a072e1b56619e3230735ae073668311232ec94vboxsyncVMMDECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, const char *pszWho)
78a072e1b56619e3230735ae073668311232ec94vboxsync ("Calling PGMR3PhysWriteExternal after pgmR3Save()! GCPhys=%RGp cbWrite=%#x pszWho=%s\n",
78a072e1b56619e3230735ae073668311232ec94vboxsync AssertMsgReturn(cbWrite > 0, ("don't even think about writing zero bytes!\n"), VINF_SUCCESS);
78a072e1b56619e3230735ae073668311232ec94vboxsync LogFlow(("PGMR3PhysWriteExternal: %RGp %d\n", GCPhys, cbWrite));
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync * Copy loop on ram ranges, stop when we hit something difficult.
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync /* Find range. */
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync /* Inside range or not? */
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync * Must work our way thru this page by page.
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync * Is the page problematic, we have to do the work on the EMT.
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync * Allocating writable pages and access handlers are
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync * problematic, write monitored pages are simple and can be
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync * dealth with here.
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync || PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED)
78a072e1b56619e3230735ae073668311232ec94vboxsync if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
78a072e1b56619e3230735ae073668311232ec94vboxsync return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysWriteExternalEMT, 4,
78a072e1b56619e3230735ae073668311232ec94vboxsync * Simple stuff, go ahead.
f001a45ec92f71f1e4c1015485fc1ddf84e8059cvboxsync int rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, pRam->GCPhys + off, &pvDst);
78a072e1b56619e3230735ae073668311232ec94vboxsync AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternal failed on %RGp / %R[pgmpage] -> %Rrc\n",
f001a45ec92f71f1e4c1015485fc1ddf84e8059cvboxsync /* next page */
78a072e1b56619e3230735ae073668311232ec94vboxsync } /* walk pages in ram range */
78a072e1b56619e3230735ae073668311232ec94vboxsync * Unassigned address space, skip it.
78a072e1b56619e3230735ae073668311232ec94vboxsync } /* Ram range walk */
78a072e1b56619e3230735ae073668311232ec94vboxsync * VMR3ReqCall worker for PGMR3PhysGCPhys2CCPtrExternal to make pages writable.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @returns see PGMR3PhysGCPhys2CCPtrExternal
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pVM The VM handle.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pGCPhys Pointer to the guest physical address.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param ppv Where to store the mapping address.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pLock Where to store the lock.
78a072e1b56619e3230735ae073668311232ec94vboxsyncstatic DECLCALLBACK(int) pgmR3PhysGCPhys2CCPtrDelegated(PVM pVM, PRTGCPHYS pGCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
78a072e1b56619e3230735ae073668311232ec94vboxsync * Just hand it to PGMPhysGCPhys2CCPtr and check that it's not a page with
78a072e1b56619e3230735ae073668311232ec94vboxsync * an access handler after it succeeds.
78a072e1b56619e3230735ae073668311232ec94vboxsync rc = PGMPhysGCPhys2CCPtr(pVM, *pGCPhys, ppv, pLock);
78a072e1b56619e3230735ae073668311232ec94vboxsync int rc2 = pgmPhysPageQueryTlbe(&pVM->pgm.s, *pGCPhys, &pTlbe);
78a072e1b56619e3230735ae073668311232ec94vboxsync /* We *must* flush any corresponding pgm pool page here, otherwise we'll
78a072e1b56619e3230735ae073668311232ec94vboxsync * not be informed about writes and keep bogus gst->shw mappings around.
78a072e1b56619e3230735ae073668311232ec94vboxsync /** @todo r=bird: return VERR_PGM_PHYS_PAGE_RESERVED here if it still has
78a072e1b56619e3230735ae073668311232ec94vboxsync * active handlers, see the PGMR3PhysGCPhys2CCPtrExternal docs. */
78a072e1b56619e3230735ae073668311232ec94vboxsync * Requests the mapping of a guest page into ring-3, external threads.
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * When you're done with the page, call PGMPhysReleasePageMappingLock() ASAP to
f001a45ec92f71f1e4c1015485fc1ddf84e8059cvboxsync * release it.
78a072e1b56619e3230735ae073668311232ec94vboxsync * This API will assume your intention is to write to the page, and will
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * therefore replace shared and zero pages. If you do not intend to modify the
78a072e1b56619e3230735ae073668311232ec94vboxsync * page, use the PGMR3PhysGCPhys2CCPtrReadOnlyExternal() API.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @returns VBox status code.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @retval VINF_SUCCESS on success.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical
78a072e1b56619e3230735ae073668311232ec94vboxsync * backing or if the page has any active access handlers. The caller
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * must fall back on using PGMR3PhysWriteExternal.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pVM The VM handle.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param GCPhys The guest physical address of the page that should be mapped.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param ppv Where to store the address corresponding to GCPhys.
78a072e1b56619e3230735ae073668311232ec94vboxsync * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * @remark Avoid calling this API from within critical sections (other than the
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * PGM one) because of the deadlock risk when we have to delegating the
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * task to an EMT.
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * @thread Any.
78a072e1b56619e3230735ae073668311232ec94vboxsyncVMMR3DECL(int) PGMR3PhysGCPhys2CCPtrExternal(PVM pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock)
78a072e1b56619e3230735ae073668311232ec94vboxsync * Query the Physical TLB entry for the page (may fail).
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync rc = pgmPhysPageQueryTlbe(&pVM->pgm.s, GCPhys, &pTlbe);
78a072e1b56619e3230735ae073668311232ec94vboxsync * If the page is shared, the zero page, or being write monitored
78a072e1b56619e3230735ae073668311232ec94vboxsync * it must be converted to an page that's writable if possible.
78a072e1b56619e3230735ae073668311232ec94vboxsync * We can only deal with write monitored pages here, the rest have
78a072e1b56619e3230735ae073668311232ec94vboxsync * to be on an EMT.
78a072e1b56619e3230735ae073668311232ec94vboxsync || PGM_PAGE_GET_STATE(pPage) != PGM_PAGE_STATE_ALLOCATED
78a072e1b56619e3230735ae073668311232ec94vboxsync if ( PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_WRITE_MONITORED
78a072e1b56619e3230735ae073668311232ec94vboxsync return VMR3ReqCallWait(pVM, VMCPUID_ANY, (PFNRT)pgmR3PhysGCPhys2CCPtrDelegated, 4,
78a072e1b56619e3230735ae073668311232ec94vboxsync * Now, just perform the locking and calculate the return address.
78a072e1b56619e3230735ae073668311232ec94vboxsync else if (cLocks != PGM_PAGE_GET_WRITE_LOCKS(pPage))
59bb2da0ef97dc8c9d0821ac921728f515623ac5vboxsync AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent write locked state!\n", GCPhys, pPage));
59bb2da0ef97dc8c9d0821ac921728f515623ac5vboxsync pMap->cRefs++; /* Extra ref to prevent it from going away. */
78a072e1b56619e3230735ae073668311232ec94vboxsync *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & PAGE_OFFSET_MASK));
78a072e1b56619e3230735ae073668311232ec94vboxsync pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_WRITE;
36dd9dabf3f64468206cb74145b51245cf7fde54vboxsync * Requests the mapping of a guest page into ring-3, external threads.
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * When you're done with the page, call PGMPhysReleasePageMappingLock() ASAP to
67927207a2d6bb545eb655ef14cdb090b1957120vboxsync * release it.
e3197fda68ad1e45cc3004f5b58a326a5270aa8fvboxsync * @returns VBox status code.
e3197fda68ad1e45cc3004f5b58a326a5270aa8fvboxsync * @retval VINF_SUCCESS on success.
e3197fda68ad1e45cc3004f5b58a326a5270aa8fvboxsync * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * backing or if the page as an active ALL access handler. The caller
e3197fda68ad1e45cc3004f5b58a326a5270aa8fvboxsync * must fall back on using PGMPhysRead.
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address.
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * @param pVM The VM handle.
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * @param GCPhys The guest physical address of the page that should be mapped.
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * @param ppv Where to store the address corresponding to GCPhys.
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * @param pLock Where to store the lock information that PGMPhysReleasePageMappingLock needs.
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * @remark Avoid calling this API from within critical sections (other than
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * the PGM one) because of the deadlock risk.
3f6d4775faa373634b2f3fc2a90fc517733f6fd6vboxsync * @thread Any.
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsyncVMMR3DECL(int) PGMR3PhysGCPhys2CCPtrReadOnlyExternal(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock)
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * Query the Physical TLB entry for the page (may fail).
60a6d709c252770b3830c85deac9c493625e3f52vboxsync rc = pgmPhysPageQueryTlbe(&pVM->pgm.s, GCPhys, &pTlbe);
f06e830c9fdbc3d9e89867d4429404c5446bc513vboxsync /* MMIO pages doesn't have any readable backing. */
40fa6228bd9ab763bc67b51fe6290802e954eb8cvboxsync * Now, just perform the locking and calculate the return address.
40fa6228bd9ab763bc67b51fe6290802e954eb8cvboxsync AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent readonly locked state!\n", GCPhys, pPage));
40fa6228bd9ab763bc67b51fe6290802e954eb8cvboxsync pMap->cRefs++; /* Extra ref to prevent it from going away. */
40fa6228bd9ab763bc67b51fe6290802e954eb8cvboxsync *ppv = (void *)((uintptr_t)pTlbe->pv | (uintptr_t)(GCPhys & PAGE_OFFSET_MASK));
40fa6228bd9ab763bc67b51fe6290802e954eb8cvboxsync pLock->uPageAndType = (uintptr_t)pPage | PGMPAGEMAPLOCK_TYPE_READ;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * Relinks the RAM ranges using the pSelfRC and pSelfR0 pointers.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * Called when anything was relocated.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pVM Pointer to the shared VM structure.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync for (pCur = pVM->pgm.s.pRamRangesR3; pCur; pCur = pCur->pNextR3)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert((pCur->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pCur->pSelfR0 == MMHyperCCToR0(pVM, pCur));
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert((pCur->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pCur->pSelfRC == MMHyperCCToRC(pVM, pCur));
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert((pCur->GCPhysLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK);
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert(pCur->cb == pCur->GCPhysLast - pCur->GCPhys + 1);
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync for (PPGMRAMRANGE pCur2 = pVM->pgm.s.pRamRangesR3; pCur2; pCur2 = pCur2->pNextR3)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync || strcmp(pCur2->pszDesc, pCur->pszDesc)); /** @todo fix MMIO ranges!! */
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * Links a new RAM range into the list.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pVM Pointer to the shared VM structure.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pNew Pointer to the new list entry.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pPrev Pointer to the previous list entry. If NULL, insert as head.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsyncstatic void pgmR3PhysLinkRamRange(PVM pVM, PPGMRAMRANGE pNew, PPGMRAMRANGE pPrev)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync AssertMsg(pNew->pszDesc, ("%RGp-%RGp\n", pNew->GCPhys, pNew->GCPhysLast));
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert((pNew->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pNew->pSelfR0 == MMHyperCCToR0(pVM, pNew));
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert((pNew->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pNew->pSelfRC == MMHyperCCToRC(pVM, pNew));
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync PPGMRAMRANGE pRam = pPrev ? pPrev->pNextR3 : pVM->pgm.s.pRamRangesR3;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync pNew->pNextR0 = pRam ? pRam->pSelfR0 : NIL_RTR0PTR;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync pNew->pNextRC = pRam ? pRam->pSelfRC : NIL_RTRCPTR;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * Unlink an existing RAM range from the list.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pVM Pointer to the shared VM structure.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pRam Pointer to the new list entry.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pPrev Pointer to the previous list entry. If NULL, insert as head.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsyncstatic void pgmR3PhysUnlinkRamRange2(PVM pVM, PPGMRAMRANGE pRam, PPGMRAMRANGE pPrev)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert(pPrev ? pPrev->pNextR3 == pRam : pVM->pgm.s.pRamRangesR3 == pRam);
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync Assert((pRam->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pRam->pSelfR0 == MMHyperCCToR0(pVM, pRam));
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync Assert((pRam->fFlags & PGM_RAM_RANGE_FLAGS_FLOATING) || pRam->pSelfRC == MMHyperCCToRC(pVM, pRam));
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync pPrev->pNextR0 = pNext ? pNext->pSelfR0 : NIL_RTR0PTR;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync pPrev->pNextRC = pNext ? pNext->pSelfRC : NIL_RTRCPTR;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync pVM->pgm.s.pRamRangesR0 = pNext ? pNext->pSelfR0 : NIL_RTR0PTR;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync pVM->pgm.s.pRamRangesRC = pNext ? pNext->pSelfRC : NIL_RTRCPTR;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * Unlink an existing RAM range from the list.
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * @param pVM Pointer to the shared VM structure.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pRam Pointer to the new list entry.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsyncstatic void pgmR3PhysUnlinkRamRange(PVM pVM, PPGMRAMRANGE pRam)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync /* find prev. */
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * Frees a range of pages, replacing them with ZERO pages of the specified type.
144b558460813c947bcc0845c183df352b251f35vboxsync * @returns VBox status code.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pVM The VM handle.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param pRam The RAM range in which the pages resides.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param GCPhys The address of the first page.
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync * @param GCPhysLast The address of the last page.
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param uType The page type to replace then with.
144b558460813c947bcc0845c183df352b251f35vboxsyncstatic int pgmR3PhysFreePageRange(PVM pVM, PPGMRAMRANGE pRam, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, uint8_t uType)
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync int rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
144b558460813c947bcc0845c183df352b251f35vboxsync /* Iterate the pages. */
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync PPGMPAGE pPageDst = &pRam->aPages[(GCPhys - pRam->GCPhys) >> PAGE_SHIFT];
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync uint32_t cPagesLeft = ((GCPhysLast - GCPhys) >> PAGE_SHIFT) + 1;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync while (cPagesLeft-- > 0)
60a6d709c252770b3830c85deac9c493625e3f52vboxsync rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPageDst, GCPhys);
60a6d709c252770b3830c85deac9c493625e3f52vboxsync AssertLogRelRCReturn(rc, rc); /* We're done for if this goes wrong. */
60a6d709c252770b3830c85deac9c493625e3f52vboxsync rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
60a6d709c252770b3830c85deac9c493625e3f52vboxsync#if HC_ARCH_BITS == 64 && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD))
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * Rendezvous callback used by PGMR3ChangeMemBalloon that changes the memory balloon size
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * This is only called on one of the EMTs while the other ones are waiting for
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * it to complete this function.
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @returns VINF_SUCCESS (VBox strict status code).
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param pVM The VM handle.
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param pVCpu The VMCPU for the EMT we're being called on. Unused.
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param pvUser User parameter
60a6d709c252770b3830c85deac9c493625e3f52vboxsyncstatic DECLCALLBACK(VBOXSTRICTRC) pgmR3PhysChangeMemBalloonRendezvous(PVM pVM, PVMCPU pVCpu, void *pvUser)
60a6d709c252770b3830c85deac9c493625e3f52vboxsync Log(("pgmR3PhysChangeMemBalloonRendezvous: %s %x pages\n", (fInflate) ? "inflate" : "deflate", cPages));
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Flush the PGM pool cache as we might have stale references to pages that we just freed. */
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Replace pages with ZERO pages. */
60a6d709c252770b3830c85deac9c493625e3f52vboxsync rc = GMMR3FreePagesPrepare(pVM, &pReq, PGMPHYS_FREE_PAGE_BATCH_SIZE, GMMACCOUNT_BASE);
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Iterate the pages. */
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync for (unsigned i = 0; i < cPages; i++)
60a6d709c252770b3830c85deac9c493625e3f52vboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPhysPage[i]);
b0cec57d51e48736a3303366c728c3f025e8e81bvboxsync Log(("pgmR3PhysChangeMemBalloonRendezvous: invalid physical page %RGp pPage->u3Type=%d\n", paPhysPage[i], (pPage) ? pPage->uTypeY : 0));
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Flush the shadow PT if this page was previously used as a guest page table. */
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, paPhysPage[i]);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_BALLOONED);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync rc = GMMR3FreePagesPerform(pVM, pReq, cPendingPages);
59489fdd1d01841db09e7a0188ad86e1a8f91843vboxsync /* Iterate the pages. */
59489fdd1d01841db09e7a0188ad86e1a8f91843vboxsync for (unsigned i = 0; i < cPages; i++)
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPhysPage[i]);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync AssertBreak(pPage && pPage->uTypeY == PGMPAGETYPE_RAM);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync LogFlow(("Free ballooned page: %RGp\n", paPhysPage[i]));
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Change back to zero page. */
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Note that we currently do not map any ballooned pages in our shadow page tables, so no need to flush the pgm pool. */
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Notify GMM about the balloon change. */
60a6d709c252770b3830c85deac9c493625e3f52vboxsync rc = GMMR3BalloonedPages(pVM, (fInflate) ? GMMBALLOONACTION_INFLATE : GMMBALLOONACTION_DEFLATE, cPages);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync /* Flush the recompiler's TLB as well. */
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync CPUMSetChangedFlags(&pVM->aCpus[i], CPUM_CHANGED_GLOBAL_TLB_FLUSH);
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * Frees a range of ram pages, replacing them with ZERO pages; helper for PGMR3PhysFreeRamPages
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @returns VBox status code.
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param pVM The VM handle.
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param fInflate Inflate or deflate memory balloon
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * @param cPages Number of pages to free
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * @param paPhysPage Array of guest physical addresses
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsyncstatic DECLCALLBACK(void) pgmR3PhysChangeMemBalloonHelper(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync int rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync /* Made a copy in PGMR3PhysFreeRamPages; free it here. */
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * Inflate or deflate a memory balloon
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @returns VBox status code.
59489fdd1d01841db09e7a0188ad86e1a8f91843vboxsync * @param pVM The VM handle.
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param fInflate Inflate or deflate memory balloon
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param cPages Number of pages to free
60a6d709c252770b3830c85deac9c493625e3f52vboxsync * @param paPhysPage Array of guest physical addresses
60a6d709c252770b3830c85deac9c493625e3f52vboxsyncVMMR3DECL(int) PGMR3PhysChangeMemBalloon(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* This must match GMMR0Init; currently we only support memory ballooning on all 64-bit hosts except Mac OS X */
60a6d709c252770b3830c85deac9c493625e3f52vboxsync#if HC_ARCH_BITS == 64 && (defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD))
60a6d709c252770b3830c85deac9c493625e3f52vboxsync /* Older additions (ancient non-functioning balloon code) pass wrong physical addresses. */
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync AssertReturn(!(paPhysPage[0] & 0xfff), VERR_INVALID_PARAMETER);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync /* We own the IOM lock here and could cause a deadlock by waiting for another VCPU that is blocking on the IOM lock.
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * In the SMP case we post a request packet to postpone the job.
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync unsigned cbPhysPage = cPages * sizeof(paPhysPage[0]);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync RTGCPHYS *paPhysPageCopy = (RTGCPHYS *)RTMemAlloc(cbPhysPage);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync rc = VMR3ReqCallNoWait(pVM, VMCPUID_ANY_QUEUE, (PFNRT)pgmR3PhysChangeMemBalloonHelper, 4, pVM, fInflate, cPages, paPhysPageCopy);
60a6d709c252770b3830c85deac9c493625e3f52vboxsync rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3PhysChangeMemBalloonRendezvous, (void *)paUser);
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * Query the amount of free memory inside VMMR0
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * @returns VBox status code.
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * @param pVM The VM handle.
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * @param puTotalAllocSize Pointer to total allocated memory inside VMMR0 (in bytes)
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsync * @param puTotalFreeSize Pointer to total free (allocated but not used yet) memory inside VMMR0 (in bytes)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param puTotalBalloonSize Pointer to total ballooned memory inside VMMR0 (in bytes)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync * @param puTotalSharedSize Pointer to total shared memory inside VMMR0 (in bytes)
5142b6456c5cec38e0ee291e235201d4ac73f10bvboxsyncVMMR3DECL(int) PGMR3QueryVMMMemoryStats(PVM pVM, uint64_t *puTotalAllocSize, uint64_t *puTotalFreeSize, uint64_t *puTotalBalloonSize, uint64_t *puTotalSharedSize)
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync uint64_t cAllocPages = 0, cFreePages = 0, cBalloonPages = 0, cSharedPages = 0;
22ecc39cb2e9aeb958d702b60fd677e8df0cdc70vboxsync rc = GMMR3QueryHypervisorMemoryStats(pVM, &cAllocPages, &cFreePages, &cBalloonPages, &cSharedPages);
if (puTotalAllocSize)
if (puTotalFreeSize)
if (puTotalBalloonSize)
if (puTotalSharedSize)
Log(("PGMR3QueryVMMMemoryStats: all=%x free=%x ballooned=%x shared=%x\n", cAllocPages, cFreePages, cBalloonPages, cSharedPages));
return VINF_SUCCESS;
* @param puTotalFreeSize Pointer to total free (allocated but not used yet) memory inside the VM (in bytes)
VMMR3DECL(int) PGMR3QueryMemoryStats(PVM pVM, uint64_t *pulTotalMem, uint64_t *pulPrivateMem, uint64_t *puTotalSharedMem, uint64_t *puTotalZeroMem)
if (pulTotalMem)
if (pulPrivateMem)
if (puTotalSharedMem)
if (puTotalZeroMem)
Log(("PGMR3QueryMemoryStats: all=%x private=%x reused=%x zero=%x\n", pVM->pgm.s.cAllPages, pVM->pgm.s.cPrivatePages, pVM->pgm.s.cReusedSharedPages, pVM->pgm.s.cZeroPages));
return VINF_SUCCESS;
static void pgmR3PhysInitAndLinkRamRange(PVM pVM, PPGMRAMRANGE pNew, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
while (iPage-- > 0)
static DECLCALLBACK(bool) pgmR3PhysRamRangeRelocate(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)
switch (enmMode)
case PGMRELOCATECALL_SUGGEST:
case PGMRELOCATECALL_RELOCATE:
AssertFailedReturn(false);
? pszDesc
size_t const cChunkPages = RT_ALIGN_Z(RT_UOFFSETOF(PGMRAMRANGE, aPages[cRamPages]), PAGE_SIZE) >> PAGE_SHIFT;
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
NULL,
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
rc = PGMR3MapPT(pVM, GCPtrChunkMap, cbChunk, 0 /*fFlags*/, pgmR3PhysRamRangeRelocate, pNew, pszDescChunk);
return rc;
AssertMsgReturn(GCPhysLast > GCPhys, ("The range wraps! GCPhys=%RGp cb=%RGp\n", GCPhys, cb), VERR_INVALID_PARAMETER);
return rc;
while (cPagesLeft > 0)
rc = pgmR3PhysRegisterHighRamChunk(pVM, GCPhysChunk, cPagesInChunk, cbChunk, iChunk, pszDesc, &pPrev);
iChunk++;
pgmR3PhysInitAndLinkRamRange(pVM, pNew, GCPhys, GCPhysLast, NIL_RTRCPTR, NIL_RTR0PTR, pszDesc, pPrev);
return VINF_SUCCESS;
while (cLeft-- > 0)
case PGM_PAGE_STATE_ZERO:
LogRel(("PGM: RAM Pre-allocation failed at %RGp (in %s) with rc=%Rrc\n", GCPhys, pRam->pszDesc, rc));
return rc;
cPages++;
case PGM_PAGE_STATE_BALLOONED:
case PGM_PAGE_STATE_ALLOCATED:
case PGM_PAGE_STATE_SHARED:
pPage++;
return VINF_SUCCESS;
#ifdef VBOX_WITH_PAGE_SHARING
AssertMsg(((RTGCPHYS)iPage << PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << PAGE_SHIFT, pRam->cb));
while (iPage-- > 0)
case PGMPAGETYPE_RAM:
void *pvPage;
rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
case PGMPAGETYPE_MMIO2:
case PGMPAGETYPE_ROM:
case PGMPAGETYPE_MMIO:
AssertFailed();
while (iPage-- > 0)
case PGMPAGETYPE_RAM:
case PGM_PAGE_STATE_ZERO:
case PGM_PAGE_STATE_BALLOONED:
case PGM_PAGE_STATE_SHARED:
case PGM_PAGE_STATE_ALLOCATED:
void *pvPage;
case PGMPAGETYPE_MMIO2:
case PGMPAGETYPE_ROM_SHADOW:
case PGMPAGETYPE_ROM:
case PGMPAGETYPE_MMIO:
AssertFailed();
if (cPendingPages)
return VINF_SUCCESS;
#ifdef VBOX_WITH_PAGE_SHARING
AssertMsg(((RTGCPHYS)iPage << PAGE_SHIFT) == pRam->cb, ("%RGp %RGp\n", (RTGCPHYS)iPage << PAGE_SHIFT, pRam->cb));
while (iPage-- > 0)
case PGMPAGETYPE_RAM:
rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, pPage, pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT));
case PGMPAGETYPE_MMIO2:
case PGMPAGETYPE_ROM:
case PGMPAGETYPE_MMIO:
AssertFailed();
if (cPendingPages)
return VINF_SUCCESS;
int rc;
bool fRamExists = false;
while (cLeft-- > 0)
pPage++;
fRamExists = true;
if (fRamExists)
/** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
Log(("PGMR3PhysMMIORegister: Adding ad hoc MMIO range for %RGp-%RGp %s\n", GCPhys, GCPhysLast, pszDesc));
rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]), 16, MM_TAG_PGM_PHYS, (void **)&pNew);
while (iPage-- > 0)
&& !fRamExists)
return rc;
bool fAllMMIO = true;
while (cLeft-- > 0)
fAllMMIO = false;
pPage++;
if (fAllMMIO)
* Range match? It will all be within one range (see PGMAllHandler.cpp).
while (cLeft--)
AssertMsg(PGM_PAGE_IS_MMIO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
AssertMsg(PGM_PAGE_IS_ZERO(pPage), ("%RGp %R[pgmpage]\n", pRam->GCPhys + ((RTGCPHYS)iPage << PAGE_SHIFT), pPage));
/** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
return rc;
return pCur;
return NULL;
VMMR3DECL(int) PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cb, uint32_t fFlags, void **ppv, const char *pszDesc)
if (!pszDesc)
return VERR_NO_MEMORY;
void *pvPages;
while (iPage-- > 0)
return VINF_SUCCESS;
return rc;
unsigned cFound = 0;
while (pCur)
cFound++;
if (pPrev)
#ifdef VBOX_STRICT
bool fRamExists = false;
fRamExists = true;
if (fRamExists)
while (cPagesLeft-- > 0)
pPage++;
if (fRamExists)
while (cPagesLeft-- > 0)
pPageSrc++;
pPageDst++;
if (cPendingPages)
/** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
while (cPagesLeft-- > 0)
pPageSrc++;
return VINF_SUCCESS;
bool fInformREM;
while (cPagesLeft-- > 0)
pPageDst++;
fInformREM = false;
fInformREM = true;
/** todo; not entirely SMP safe; assuming for now the guest takes care of this internally (not touch mapped mmio while changing the mapping). */
if (fInformREM)
return VINF_SUCCESS;
VMMR3DECL(int) PGMR3PhysMMIO2GetHCPhys(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, PRTHCPHYS pHCPhys)
return VINF_SUCCESS;
VMMR3DECL(int) PGMR3PhysMMIO2MapKernel(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS off, RTGCPHYS cb,
return rc;
Log(("PGMR3PhysRomRegister: pDevIns=%p GCPhys=%RGp(-%RGp) cb=%RGp pvBinary=%p fFlags=%#x pszDesc=%s\n",
AssertReturn(!(fFlags & ~(PGMPHYS_ROM_FLAGS_SHADOWED | PGMPHYS_ROM_FLAGS_PERMANENT_BINARY)), VERR_INVALID_PARAMETER);
bool fRamExists = false;
fRamExists = true;
if (fRamExists)
while (cPagesLeft-- > 0)
pPage++;
if (cExtraBaseCost)
return rc;
return rc;
rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMROMRANGE, aPages[cPages]), 0, MM_TAG_PGM_PHYS, (void **)&pRomNew);
if (!fRamExists)
rc = MMHyperAlloc(pVM, RT_OFFSETOF(PGMRAMRANGE, aPages[cPages]), sizeof(PGMPAGE), MM_TAG_PGM_PHYS, (void **)&pRamNew);
if (!fRamExists)
void *pvDstPage;
if (pRomPrev)
return VINF_SUCCESS;
if (!fRamExists)
return rc;
static DECLCALLBACK(int) pgmR3PhysRomWriteHandler(PVM pVM, RTGCPHYS GCPhys, void *pvPhys, void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, void *pvUser)
Log5(("pgmR3PhysRomWriteHandler: %d %c %#08RGp %#04zx\n", pRomPage->enmProt, enmAccessType == PGMACCESSTYPE_READ ? 'R' : 'W', GCPhys, cbBuf));
return VINF_PGM_HANDLER_DO_DEFAULT;
return VINF_SUCCESS;
void *pvDstPage;
return rc;
rc = pgmPhysFreePage(pVM, pReq, &cPendingPages, &pRom->aPages[iPage].Shadow, pRom->GCPhys + (iPage << PAGE_SHIFT));
if (cPendingPages)
Assert(!PGM_PAGE_IS_ZERO(&pRom->aPages[iPage].Shadow) && !PGM_PAGE_IS_BALLOONED(&pRom->aPages[iPage].Shadow));
void *pvDstPage;
#ifdef VBOX_STRICT
void const *pvDstPage;
return VINF_SUCCESS;
if (!cb)
return VINF_SUCCESS;
bool fFlushTLB = false;
bool fChanges = false;
iPage++)
fChanges = true;
if (fChanges)
return rc2;
if (fFlushTLB)
return rc;
RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkAgeingRolloverCallback, pVM);
RTAvlU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pTree, true /*fFromLeft*/, pgmR3PhysChunkAgeingCallback, pVM);
typedef struct PGMR3PHYSCHUNKUNMAPCB
if (pChunk)
if (pChunk)
/* next with the same age - this version of the AVL API doesn't enumerate the list, so we have to do it. */
} while (pNode);
if (RTAvllU32DoWithAll(&pVM->pgm.s.ChunkR3Map.pAgeTree, true /*fFromLeft*/, pgmR3PhysChunkUnmapCandidateCallback, pVM))
return INT32_MAX;
int rc;
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)MMR3HeapAlloc(pVM, MM_TAG_PGM_CHUNK_MAPPING, sizeof(*pChunk));
PPGMCHUNKR3MAP pChunk = (PPGMCHUNKR3MAP)MMR3UkHeapAlloc(pVM, MM_TAG_PGM_CHUNK_MAPPING, sizeof(*pChunk), NULL);
rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /* use CPU id 0; it must be a valid one */, VMMR0_DO_GMM_MAP_UNMAP_CHUNK, 0, &Req.Hdr);
PPGMCHUNKR3MAP pUnmappedChunk = (PPGMCHUNKR3MAP)RTAvlU32Remove(&pVM->pgm.s.ChunkR3Map.pTree, Req.idChunkUnmap);
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
#ifdef VBOX_WITH_2X_4GB_ADDR_SPACE
return rc;
int rc;
return rc;
void *pv;
idPage++;
return rc;
* in EM.cpp and shouldn't be propagated outside TRPM, HWACCM, EM and
AssertMsgReturn(iClear <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d", iClear), VERR_INTERNAL_ERROR);
void *pvChunk;
void *pv;
AssertLogRelMsgBreak(RT_SUCCESS(rc), ("idPage=%#x HCPhysGCPhys=%RHp rc=%Rrc", pPage->idPage, pPage->HCPhysGCPhys, rc));
iClear++;
Log3(("PGMR3PhysAllocateHandyPages: idPage=%#x HCPhys=%RGp\n", pPage->idPage, pPage->HCPhysGCPhys));
pRam;
return rc;
static int pgmPhysFreePage(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t *pcPendingPages, PPGMPAGE pPage, RTGCPHYS GCPhys)
return VMSetError(pVM, VERR_PGM_PHYS_NOT_RAM, RT_SRC_POS, "GCPhys=%RGp type=%d", GCPhys, PGM_PAGE_GET_TYPE(pPage));
return VINF_SUCCESS;
return VMSetError(pVM, VERR_PGM_PHYS_INVALID_PAGE_ID, RT_SRC_POS, "GCPhys=%RGp idPage=%#x", GCPhys, pPage);
return VINF_SUCCESS;
*pcPendingPages = 0;
return rc;
/** @todo Handle TLB loads of virtual handlers so ./test.sh can be made to work
if (fWritable)
int rc2;
if (fWritable)
case PGM_PAGE_STATE_ALLOCATED:
case PGM_PAGE_STATE_BALLOONED:
AssertFailed();
case PGM_PAGE_STATE_ZERO:
case PGM_PAGE_STATE_SHARED:
Log6(("PGMR3PhysTlbGCPhys2Ptr: GCPhys=%RGp rc=%Rrc pPage=%R[pgmpage] *ppv=%p\n", GCPhys, rc, pPage, *ppv));
return rc;