MMHyper.cpp revision fb5e37303b228a79c05cabfce2fe0fedfe32ed8a
682a27d94b9116c719038882487b99053985f91avboxsync * MM - Memory Monitor(/Manager) - Hypervisor Memory Area.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006 InnoTek Systemberatung GmbH
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * available from http://www.virtualbox.org. This file is free software;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * you can redistribute it and/or modify it under the terms of the GNU
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * General Public License as published by the Free Software Foundation,
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * If you received this file as part of a commercial VirtualBox
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * distribution, then only the terms of your commercial VirtualBox
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * license agreement apply instead of the previous paragraph.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync/*******************************************************************************
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync* Header Files *
682a27d94b9116c719038882487b99053985f91avboxsync*******************************************************************************/
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync/*******************************************************************************
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync* Internal Functions *
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync*******************************************************************************/
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncstatic DECLCALLBACK(bool) mmR3HyperRelocateCallback(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncstatic int mmR3HyperMap(PVM pVM, const size_t cb, const char *pszDesc, PRTGCPTR pGCPtr, PMMLOOKUPHYPER *ppLookup);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncstatic int mmR3HyperHeapCreate(PVM pVM, const size_t cb, PMMHYPERHEAP *ppHeap);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncstatic int mmR3HyperHeapMap(PVM pVM, PMMHYPERHEAP pHeap, PRTGCPTR ppHeapGC);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsyncstatic DECLCALLBACK(void) mmR3HyperInfoHma(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs);
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * Initializes the hypvervisor related MM stuff without
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * calling down to PGM.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * PGM is not initialized at this point, PGM relies on
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * the heap to initialize.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * @returns VBox status.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Decide Hypervisor mapping in the guest context
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * And setup various hypervisor area and heap parameters.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync pVM->mm.s.pvHyperAreaGC = (RTGCPTR)MM_HYPER_AREA_ADDRESS;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertRelease(RT_ALIGN_T(pVM->mm.s.pvHyperAreaGC, 1 << X86_PD_SHIFT, RTGCPTR) == pVM->mm.s.pvHyperAreaGC);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = CFGMR3QueryU32(CFGMR3GetChild(CFGMR3GetRoot(pVM), "MM"), "cbHyperHeap", &cbHyperHeap);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync if (rc == VERR_CFGM_NO_PARENT || rc == VERR_CFGM_VALUE_NOT_FOUND)
683bc538c5d6598479b7da2ad464939422d449d6vboxsync * Allocate the hypervisor heap.
4b4dcfe69a693fa32dd64da3d9ea88e996ca1bf5vboxsync * (This must be done before we start adding memory to the
4b4dcfe69a693fa32dd64da3d9ea88e996ca1bf5vboxsync * hypervisor static area because lookup records are allocated from it.)
4b4dcfe69a693fa32dd64da3d9ea88e996ca1bf5vboxsync rc = mmR3HyperHeapCreate(pVM, cbHyperHeap, &pVM->mm.s.pHyperHeapHC);
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Make a small head fence to fend of accidental sequential access.
4c953c3c459d80bc3e31a0a65a9dc0463f340e6bvboxsync * Map the VM structure into the hypervisor space.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync rc = MMR3HyperMapHCPhys(pVM, pVM, pVM->HCPhysVM, sizeof(VM), "VM", &pVM->pVMGC);
7525834c8ff7d6665778b83fb9d0585624ee7ae9vboxsync /* Reserve a page for fencing. */
4c953c3c459d80bc3e31a0a65a9dc0463f340e6bvboxsync * Map the heap into the hypervisor space.
4c953c3c459d80bc3e31a0a65a9dc0463f340e6bvboxsync rc = mmR3HyperHeapMap(pVM, pVM->mm.s.pHyperHeapHC, &pVM->mm.s.pHyperHeapGC);
4c953c3c459d80bc3e31a0a65a9dc0463f340e6bvboxsync * Register info handlers.
4c953c3c459d80bc3e31a0a65a9dc0463f340e6bvboxsync DBGFR3InfoRegisterInternal(pVM, "hma", "Show the layout of the Hypervisor Memory Area.", mmR3HyperInfoHma);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("mmr3HyperInit: returns VINF_SUCCESS\n"));
4c953c3c459d80bc3e31a0a65a9dc0463f340e6bvboxsync /* Caller will do proper cleanup. */
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync * Finalizes the HMA mapping.
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync * This is called later during init, most (all) HMA allocations should be done
f1301dd8b6870b5a25c7dbdd46e0a0671bb62031vboxsync * by the time this function is called.
683bc538c5d6598479b7da2ad464939422d449d6vboxsync * @returns VBox status.
4b4dcfe69a693fa32dd64da3d9ea88e996ca1bf5vboxsync * Adjust and create the HMA mapping.
4b4dcfe69a693fa32dd64da3d9ea88e996ca1bf5vboxsync while ((RTINT)pVM->mm.s.offHyperNextStatic + 64*_1K < (RTINT)pVM->mm.s.cbHyperArea - _4M)
4b4dcfe69a693fa32dd64da3d9ea88e996ca1bf5vboxsync int rc = PGMR3MapPT(pVM, pVM->mm.s.pvHyperAreaGC, pVM->mm.s.cbHyperArea,
4b4dcfe69a693fa32dd64da3d9ea88e996ca1bf5vboxsync mmR3HyperRelocateCallback, NULL, "Hypervisor Memory Area");
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync * Do all the delayed mappings.
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((uintptr_t)pVM->mm.s.pHyperHeapHC + pVM->mm.s.offLookupHyper);
d09ef734532edd0e40ffe9a471e0a31152572065vboxsync RTGCPTR GCPtr = pVM->mm.s.pvHyperAreaGC + pLookup->off;
c785dbab313731d1f4662b4684c0808cc14703dbvboxsync rc = mmr3MapLocked(pVM, pLookup->u.Locked.pLockedMem, GCPtr, 0, cPages, 0);
d09ef734532edd0e40ffe9a471e0a31152572065vboxsync rc = PGMMap(pVM, GCPtr, pLookup->u.HCPhys.HCPhys, pLookup->cb, 0);
d09ef734532edd0e40ffe9a471e0a31152572065vboxsync rc = PGMPhysGCPhys2HCPhys(pVM, GCPhys + off, &HCPhys);
d09ef734532edd0e40ffe9a471e0a31152572065vboxsync rc = PGMMap(pVM, GCPtr + off, HCPhys, PAGE_SIZE, 0);
c448f9b0b8382e4665c9700488002c45a9b3f137vboxsync /* do nothing here since these are either fences or managed by someone else using PGM. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("rc=%Vrc cb=%d GCPtr=%VGv enmType=%d pszDesc=%s\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc, pLookup->cb, pLookup->enmType, pLookup->pszDesc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup = (PMMLOOKUPHYPER)((uintptr_t)pLookup + pLookup->offNext);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("MMR3HyperInitFinalize: returns VINF_SUCCESS\n"));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Callback function which will be called when PGM is trying to find
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * a new location for the mapping.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * The callback is called in two modes, 1) the check mode and 2) the relocate mode.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * In 1) the callback should say if it objects to a suggested new location. If it
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * accepts the new location, it is called again for doing it's relocation.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @returns true if the location is ok.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @returns false if another location should be found.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM The VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param GCPtrOld The old virtual address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param GCPtrNew The new virtual address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param enmMode Used to indicate the callback mode.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pvUser User argument. Ignored.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @remark The return value is no a failure indicator, it's an acceptance
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * indicator. Relocation can not fail!
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic DECLCALLBACK(bool) mmR3HyperRelocateCallback(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Verify location - all locations are good for us.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync return true;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Execute the relocation.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Accepted!
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync AssertMsg(GCPtrOld == pVM->mm.s.pvHyperAreaGC, ("GCPtrOld=%#x pVM->mm.s.pvHyperAreaGC=%#x\n", GCPtrOld, pVM->mm.s.pvHyperAreaGC));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync Log(("Relocating the hypervisor from %#x to %#x\n", GCPtrOld, GCPtrNew));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* relocate our selves and the VM structure. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* relocate the rest. */
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync return true;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("Invalid relocation mode %d\n", enmMode));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync return false;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Maps contiguous HC physical memory into the hypervisor region in the GC.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @return VBox status code.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * @param pVM VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pvHC Host context address of the memory. Must be page aligned!
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param HCPhys Host context physical address of the memory to be mapped. Must be page aligned!
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb Size of the memory. Will be rounded up to nearest page.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pszDesc Description.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * @param pGCPtr Where to store the GC address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(int) MMR3HyperMapHCPhys(PVM pVM, void *pvHC, RTHCPHYS HCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("MMR3HyperMapHCPhys: pvHc=%p HCPhys=%VHp cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", pvHC, HCPhys, (int)cb, pszDesc, pszDesc, pGCPtr));
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * Validate input.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertReturn(RT_ALIGN_P(pvHC, PAGE_SIZE) == pvHC, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertReturn(RT_ALIGN_T(HCPhys, PAGE_SIZE, RTHCPHYS) == HCPhys, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Add the memory to the hypervisor area.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = mmR3HyperMap(pVM, cbAligned, pszDesc, &GCPtr, &pLookup);
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * Update the page table.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * Maps contiguous GC physical memory into the hypervisor region in the GC.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @return VBox status code.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM VM handle.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * @param GCPhys Guest context physical address of the memory to be mapped. Must be page aligned!
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb Size of the memory. Will be rounded up to nearest page.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pszDesc Mapping description.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pGCPtr Where to store the GC address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(int) MMR3HyperMapGCPhys(PVM pVM, RTGCPHYS GCPhys, size_t cb, const char *pszDesc, PRTGCPTR pGCPtr)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("MMR3HyperMapGCPhys: GCPhys=%VGp cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", GCPhys, (int)cb, pszDesc, pszDesc, pGCPtr));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Validate input.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertReturn(RT_ALIGN_T(GCPhys, PAGE_SIZE, RTGCPHYS) == GCPhys, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertReturn(pszDesc && *pszDesc, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Add the memory to the hypervisor area.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * Update the page table.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = PGMPhysGCPhys2HCPhys(pVM, GCPhys + off, &HCPhys);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("rc=%Vrc GCPhys=%VGv off=%#x %s\n", rc, GCPhys, off, pszDesc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = PGMMap(pVM, GCPtr + off, HCPhys, PAGE_SIZE, 0);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("rc=%Vrc GCPhys=%VGv off=%#x %s\n", rc, GCPhys, off, pszDesc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Locks and Maps HC virtual memory into the hypervisor region in the GC.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @return VBox status code.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pvHC Host context address of the memory (may be not page aligned).
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb Size of the memory. Will be rounded up to nearest page.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param fFree Set this if MM is responsible for freeing the memory using SUPPageFree.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * @param pszDesc Mapping description.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pGCPtr Where to store the GC address corresponding to pvHC.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(int) MMR3HyperMapHCRam(PVM pVM, void *pvHC, size_t cb, bool fFree, const char *pszDesc, PRTGCPTR pGCPtr)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("MMR3HyperMapHCRam: pvHc=%p cb=%d fFree=%d pszDesc=%p:{%s} pGCPtr=%p\n", pvHC, (int)cb, fFree, pszDesc, pszDesc, pGCPtr));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Validate input.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Page align address and size.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync void *pvHCPage = (void *)((uintptr_t)pvHC & PAGE_BASE_HC_MASK);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Add the memory to the hypervisor area.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Lock the heap memory and tell PGM about the locked pages.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = mmr3LockMem(pVM, pvHCPage, cb, fFree ? MM_LOCKED_TYPE_HYPER : MM_LOCKED_TYPE_HYPER_NOFREE, &pLockedMem);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* map the stuff into guest address space. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = mmr3MapLocked(pVM, pLockedMem, GCPtr, 0, ~(size_t)0, 0);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* done. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Don't care about failure clean, we're screwed if this fails anyway. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Reserves a hypervisor memory area.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Most frequent usage is fence pages and dynamically mappings like the guest PD and PDPTR.
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * @return VBox status code.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb Size of the memory. Will be rounded up to nearest page.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pszDesc Mapping description.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pGCPtr Where to store the assigned GC address. Optional.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(int) MMR3HyperReserve(PVM pVM, unsigned cb, const char *pszDesc, PRTGCPTR pGCPtr)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("MMR3HyperMapHCRam: cb=%d pszDesc=%p:{%s} pGCPtr=%p\n", (int)cb, pszDesc, pszDesc, pGCPtr));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Validate input.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Add the memory to the hypervisor area.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = mmR3HyperMap(pVM, cb, pszDesc, &GCPtr, &pLookup);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Adds memory to the hypervisor memory arena.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @return VBox status code.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM The VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb Size of the memory. Will be rounded up to neares page.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pszDesc The description of the memory.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pGCPtr Where to store the GC address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param ppLookup Where to store the pointer to the lookup record.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @remark We assume the threading structure of VBox imposes natural
24b9d11a24f96f5da0351475e0b6486ec4cb0d30vboxsync * serialization of most functions, this one included.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic int mmR3HyperMap(PVM pVM, const size_t cb, const char *pszDesc, PRTGCPTR pGCPtr, PMMLOOKUPHYPER *ppLookup)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Validate input.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync const uint32_t cbAligned = RT_ALIGN(cb, PAGE_SIZE);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync if (pVM->mm.s.offHyperNextStatic + cbAligned >= pVM->mm.s.cbHyperArea) /* don't use the last page, it's a fence. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("Out of static mapping space in the HMA! offHyperAreaGC=%x cbAligned=%x\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Allocate lookup record.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = MMHyperAlloc(pVM, sizeof(*pLookup), 1, MM_TAG_MM, (void **)&pLookup);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Initialize it and insert it.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pVM->mm.s.offLookupHyper = (char *)pLookup - (char *)pVM->mm.s.pHyperHeapHC;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Mapping. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync *pGCPtr = pVM->mm.s.pvHyperAreaGC + pVM->mm.s.offHyperNextStatic;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Return pointer. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync LogFlow(("mmR3HyperMap: returns %Vrc *pGCPtr=%VGv\n", rc, *pGCPtr));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Allocates a new heap.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @returns VBox status code.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM The VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb The size of the new heap.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param ppHeap Where to store the heap pointer on successful return.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic int mmR3HyperHeapCreate(PVM pVM, const size_t cb, PMMHYPERHEAP *ppHeap)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Allocate the hypervisor heap.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync const uint32_t cbAligned = RT_ALIGN_Z(cb, PAGE_SIZE);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertReturn(cbAligned >= cb, VERR_INVALID_PARAMETER);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = SUPPageAlloc(cbAligned >> PAGE_SHIFT, &pv);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Initialize the heap and first free chunk.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pHeap->pbHeapHC = (uint8_t *)pHeap + MMYPERHEAP_HDR_SIZE;
ebd35513cc8c7c67273191d51285629d77a1f736vboxsync //pHeap->pbHeapGC = 0; // set by mmR3HyperHeapMap()
ebd35513cc8c7c67273191d51285629d77a1f736vboxsync pHeap->cbFree = pHeap->cbHeap - sizeof(MMHYPERCHUNK);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync //pHeap->offFreeHead = 0;
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync //pHeap->offFreeTail = 0;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync //pHeap->HyperHeapStatTree = 0;
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync PMMHYPERCHUNKFREE pFree = (PMMHYPERCHUNKFREE)pHeap->pbHeapHC;
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync //pFree->core.offNext = 0;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync MMHYPERCHUNK_SET_TYPE(&pFree->core, MMHYPERCHUNK_FLAGS_FREE);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pFree->core.offHeap = -(int32_t)MMYPERHEAP_HDR_SIZE;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync //pFree->offNext = 0;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync //pFree->offPrev = 0;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync STAMR3Register(pVM, &pHeap->cbHeap, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, "/MM/HyperHeap/cbHeap", STAMUNIT_BYTES, "The heap size.");
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync STAMR3Register(pVM, &pHeap->cbFree, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, "/MM/HyperHeap/cbFree", STAMUNIT_BYTES, "The free space.");
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("SUPPageAlloc(%d,) -> %Vrc\n", cbAligned >> PAGE_SHIFT, rc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Allocates a new heap.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic int mmR3HyperHeapMap(PVM pVM, PMMHYPERHEAP pHeap, PRTGCPTR ppHeapGC)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = MMR3HyperMapHCRam(pVM, pHeap, pHeap->cbHeap + MMYPERHEAP_HDR_SIZE, true, "Heap", ppHeapGC);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* Reserve a page for fencing. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Destroys a heap.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic int mmR3HyperHeapDestroy(PVM pVM, PMMHYPERHEAP pHeap)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* all this is dealt with when unlocking and freeing locked memory. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Allocates memory in the Hypervisor (GC VMM) area which never will
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * be freed and doesn't have any offset based relation to other heap blocks.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * The latter means that two blocks allocated by this API will not have the
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * same relative position to each other in GC and HC. In short, never use
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * this API for allocating nodes for an offset based AVL tree!
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * The returned memory is of course zeroed.
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync * @returns VBox status code.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM The VM to operate on.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb Number of bytes to allocate.
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync * @param uAlignment Required memory alignment in bytes.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Values are 0,8,16,32 and PAGE_SIZE.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * 0 -> default alignment, i.e. 8 bytes.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param enmTag The statistics tag.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param ppv Where to store the address to the allocated
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @remark This is assumed not to be used at times when serialization is required.
4f4b2d99ad789c62e8d25156869ee7ea741de8d0vboxsyncMMDECL(int) MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsg(cb >= 8, ("Hey! Do you really mean to allocate less than 8 bytes?! cb=%d\n", cb));
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync AssertMsg(cb <= _4M, ("Allocating more than 4MB!? (cb=%#x) HMA limit might need adjusting if you allocate more.\n", cb));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Choose between allocating a new chunk of HMA memory
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * and the heap. We will only do BIG allocations from HMA.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = MMHyperAlloc(pVM, cb, uAlignment, enmTag, ppv);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync Log2(("MMR3HyperAllocOnceNoRel: cb=%#x uAlignment=%#x returns %Rrc and *ppv=%p\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Validate alignment.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("Invalid alignment %u\n", uAlignment));
48d832e07616531bbb720d9c98103c83b561ebb6vboxsync * Allocate the pages and the HMA space.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync rc = MMR3HyperMapHCRam(pVM, pvPages, cb, true, mmR3GetTagName(enmTag), &GCPtr);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync Log2(("MMR3HyperAllocOnceNoRel: cb=%#x uAlignment=%#x returns VINF_SUCCESS and *ppv=%p\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync Log2(("MMR3HyperAllocOnceNoRel: cb=%#x uAlignment=%#x returns %Rrc\n", cb, uAlignment, rc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("Failed to allocate %d bytes!\n", cb));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Convert hypervisor HC virtual address to HC physical address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @returns HC physical address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM VM Handle
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pvHC Host context physical address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(RTHCPHYS) MMR3HyperHCVirt2HCPhys(PVM pVM, void *pvHC)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((char*)pVM->mm.s.pHyperHeapHC + pVM->mm.s.offLookupHyper);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync unsigned off = (char *)pvHC - (char *)pLookup->u.Locked.pvHC;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync return (pLookup->u.Locked.pLockedMem->aPhysPages[off >> PAGE_SHIFT].Phys & X86_PTE_PAE_PG_MASK) | (off & PAGE_OFFSET_MASK);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync unsigned off = (char *)pvHC - (char *)pLookup->u.HCPhys.pvHC;
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /* can convert these kind of records. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("enmType=%d\n", pLookup->enmType));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup = (PMMLOOKUPHYPER)((char *)pLookup + pLookup->offNext);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("pvHC=%p is not inside the hypervisor memory area!\n", pvHC));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#if 0 /* unused, not implemented */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Convert hypervisor HC physical address to HC virtual address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @returns HC virtual address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM VM Handle
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param HCPhys Host context physical address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(void *) MMR3HyperHCPhys2HCVirt(PVM pVM, RTHCPHYS HCPhys)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync int rc = MMR3HyperHCPhys2HCVirtEx(pVM, HCPhys, &pv);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync AssertMsgFailed(("Invalid address HCPhys=%x rc=%d\n", HCPhys, rc));
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Convert hypervisor HC physical address to HC virtual address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @returns VBox status.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM VM Handle
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param HCPhys Host context physical address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param ppv Where to store the HC virtual address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(int) MMR3HyperHCPhys2HCVirtEx(PVM pVM, RTHCPHYS HCPhys, void **ppv)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Linear search.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync /** @todo implement when actually used. */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync#endif /* unused, not implemented */
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Read hypervisor memory from GC virtual address.
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync * @returns VBox status.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pvDst Destination address (HC of course).
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync * @param GCPtr GC virtual address.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param cb Number of bytes to read.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncMMR3DECL(int) MMR3HyperReadGCVirt(PVM pVM, void *pvDst, RTGCPTR GCPtr, size_t cb)
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync if (GCPtr - pVM->mm.s.pvHyperAreaGC >= pVM->mm.s.cbHyperArea)
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * Info handler for 'hma', it dumps the list of lookup records for the hypervisor memory area.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pVM The VM handle.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pHlp Callback functions for doing output.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync * @param pszArgs Argument string. Optional and specific to the handler.
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsyncstatic DECLCALLBACK(void) mmR3HyperInfoHma(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync pHlp->pfnPrintf(pHlp, "Hypervisor Memory Area (HMA) Layout: Base %VGv, 0x%08x bytes\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync PMMLOOKUPHYPER pLookup = (PMMLOOKUPHYPER)((char*)pVM->mm.s.pHyperHeapHC + pVM->mm.s.offLookupHyper);
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pHlp->pfnPrintf(pHlp, "%VGv-%VGv %VHv LOCKED %-*s %s\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup->u.Locked.pLockedMem->eType == MM_LOCKED_TYPE_HYPER_NOFREE
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pHlp->pfnPrintf(pHlp, "%VGv-%VGv %VHv HCPHYS %VHp %s\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pHlp->pfnPrintf(pHlp, "%VGv-%VGv %*s GCPHYS %VGp%*s %s\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup->u.GCPhys.GCPhys, RT_ABS(sizeof(RTHCPHYS) - sizeof(RTGCPHYS)) * 2, "",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pHlp->pfnPrintf(pHlp, "%VGv-%VGv %*s DYNAMIC %*s %s\n",
3c3a5ab35783f4d31cb5d3a15db9daadeb804daavboxsync pLookup->off + pVM->mm.s.pvHyperAreaGC + pLookup->cb,
810e2dff19cb2bda7ee6f98fa1a9e25ca1bb32d8vboxsync AssertMsgFailed(("enmType=%d\n", pLookup->enmType));