PGMAllHandler.cpp revision e4a93d2f3ca0b165b618c27d37d984b05d24bed8
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * PGM - Page Manager / Monitor, Access Handlers.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Copyright (C) 2006-2010 Oracle Corporation
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * available from http://www.virtualbox.org. This file is free software;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * you can redistribute it and/or modify it under the terms of the GNU
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * General Public License (GPL) as published by the Free Software
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/*******************************************************************************
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync* Header Files *
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync*******************************************************************************/
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync/*******************************************************************************
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync* Internal Functions *
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync*******************************************************************************/
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncstatic int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncstatic void pgmHandlerPhysicalDeregisterNotifyREM(PVM pVM, PPGMPHYSHANDLER pCur);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncstatic void pgmHandlerPhysicalResetRamFlags(PVM pVM, PPGMPHYSHANDLER pCur);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Register a access handler for a physical range.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @returns VBox status code.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @retval VINF_SUCCESS when successfully installed.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @retval VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * flagged together with a pool clearing.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @retval VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * one. A debug assertion is raised.
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync * @param pVM VM Handle.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param enmType Handler type. Any of the PGMPHYSHANDLERTYPE_PHYSICAL* enums.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param GCPhys Start physical address.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param GCPhysLast Last physical address. (inclusive)
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pfnHandlerR3 The R3 handler.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pvUserR3 User argument to the R3 handler.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pfnHandlerR0 The R0 handler.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pvUserR0 User argument to the R0 handler.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pfnHandlerRC The RC handler.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pvUserRC User argument to the RC handler. This can be a value
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * less that 0x10000 or a (non-null) pointer that is
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * automatically relocatated.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pszDesc Pointer to description string. This must not be freed.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsyncVMMDECL(int) PGMHandlerPhysicalRegisterEx(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC,
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync Log(("PGMHandlerPhysicalRegisterEx: enmType=%d GCPhys=%RGp GCPhysLast=%RGp pfnHandlerR3=%RHv pvUserR3=%RHv pfnHandlerR0=%RHv pvUserR0=%RHv pfnHandlerGC=%RRv pvUserGC=%RRv pszDesc=%s\n",
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync enmType, GCPhys, GCPhysLast, pfnHandlerR3, pvUserR3, pfnHandlerR0, pvUserR0, pfnHandlerRC, pvUserRC, R3STRING(pszDesc)));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Validate input.
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync AssertMsgReturn(GCPhys < GCPhysLast, ("GCPhys >= GCPhysLast (%#x >= %#x)\n", GCPhys, GCPhysLast), VERR_INVALID_PARAMETER);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Simplification in PGMPhysRead among other places. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertMsgReturn(!(GCPhys & PAGE_OFFSET_MASK), ("%RGp\n", GCPhys), VERR_INVALID_PARAMETER);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertMsgReturn((GCPhysLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK, ("%RGp\n", GCPhysLast), VERR_INVALID_PARAMETER);
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync AssertMsgFailed(("Invalid input enmType=%d!\n", enmType));
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync || MMHyperR3ToRC(pVM, MMHyperRCToR3(pVM, pvUserRC)) == pvUserRC,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync || MMHyperR3ToR0(pVM, MMHyperR0ToR3(pVM, pvUserR0)) == pvUserR0,
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertPtrReturn(pfnHandlerR3, VERR_INVALID_POINTER);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertReturn(pfnHandlerR0, VERR_INVALID_PARAMETER);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertReturn(pfnHandlerRC, VERR_INVALID_PARAMETER);
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync * We require the range to be within registered ram.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * There is no apparent need to support ranges which cover more than one ram range.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync PPGMRAMRANGE pRam = pVM->pgm.s.CTX_SUFF(pRamRanges);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Allocate and initialize the new entry.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc = MMHyperAlloc(pVM, sizeof(*pNew), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync pNew->cPages = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK_FULL) + PAGE_SIZE) >> PAGE_SHIFT;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Try insert into list.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pNew->Core))
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pNew, pRam);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync REMNotifyHandlerPhysicalRegister(pVM, enmType, GCPhys, GCPhysLast - GCPhys + 1, !!pfnHandlerR3);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync REMR3NotifyHandlerPhysicalRegister(pVM, enmType, GCPhys, GCPhysLast - GCPhys + 1, !!pfnHandlerR3);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync Log(("PGMHandlerPhysicalRegisterEx: returns %Rrc (%RGp-%RGp)\n", rc, GCPhys, GCPhysLast));
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp pszDesc=%s\n", GCPhys, GCPhysLast, pszDesc));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * Sets ram range flags and attempts updating shadow PTs.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @returns VBox status code.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @retval VINF_SUCCESS when shadow PTs was successfully updated.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @retval VINF_PGM_SYNC_CR3 when the shadow PTs could be updated because
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * the guest page aliased or/and mapped by multiple PTs. FFs set.
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync * @param pVM The VM handle.
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync * @param pCur The physical handler.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * @param pRam The RAM range.
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsyncstatic int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam)
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync * Iterate the guest ram pages updating the flags and flushing PT entries
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync * mapping the page.
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync bool fFlushTLBs = false;
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync const unsigned uState = pgmHandlerPhysicalCalcState(pCur);
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync uint32_t i = (pCur->Core.Key - pRam->GCPhys) >> PAGE_SHIFT;
87f68d052aecda193e89e8f41ec147606c7f4e0bvboxsync AssertMsg(pCur->enmType != PGMPHYSHANDLERTYPE_MMIO || PGM_PAGE_IS_MMIO(pPage),
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync ("%RGp %R[pgmpage]\n", pRam->GCPhys + (i << PAGE_SHIFT), pPage));
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync /* Only do upgrades. */
5c2e23084fe3d3163d8f441b99cfd9d2f76b6b2avboxsync int rc2 = pgmPoolTrackUpdateGCPhys(pVM, pRam->GCPhys + (i << PAGE_SHIFT), pPage, false /* allow updates of PTEs (instead of flushing) */, &fFlushTLBs);
if (--cPages == 0)
if (fFlushTLBs)
Log(("pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs: doesn't flush guest TLBs. rc=%Rrc; sync flags=%x VMCPU_FF_PGM_SYNC_CR3=%d\n", rc, VMMGetCpu(pVM)->pgm.s.fSyncFlags, VMCPU_FF_ISSET(VMMGetCpu(pVM), VMCPU_FF_PGM_SYNC_CR3)));
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
return VINF_SUCCESS;
return VERR_PGM_HANDLER_NOT_FOUND;
if ( pPage
if ( pPage
#ifndef IN_RING3
REMNotifyHandlerPhysicalDeregister(pVM, pCur->enmType, GCPhysStart, GCPhysLast - GCPhysStart + 1, !!pCur->pfnHandlerR3, fRestoreAsRAM);
REMR3NotifyHandlerPhysicalDeregister(pVM, pCur->enmType, GCPhysStart, GCPhysLast - GCPhysStart + 1, !!pCur->pfnHandlerR3, fRestoreAsRAM);
DECLINLINE(void) pgmHandlerPhysicalRecalcPageState(PPGM pPGM, RTGCPHYS GCPhys, bool fAbove, PPGMRAMRANGE *ppRamHint)
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTX_SUFF(pTrees)->PhysHandlers, GCPhys, fAbove);
if ( !pCur
bool fFlushTLBs = false;
# ifdef IN_RC
(We don't flip MMIO to RAM though, that's PGMPhys.cpp's job.) */
AssertMsg(pCur->enmType != PGMPHYSHANDLERTYPE_MMIO || PGM_PAGE_IS_MMIO(pPage), ("%RGp %R[pgmpage]\n", GCPhys, pPage));
if (--cPages == 0)
* For all return codes other than VERR_PGM_HANDLER_NOT_FOUND and VINF_SUCCESS the range is deregistered
VMMDECL(int) PGMHandlerPhysicalModify(PVM pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast)
int rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhysCurrent);
if (pCur)
if ( pRam
#ifndef IN_RING3
return VINF_SUCCESS;
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
return rc;
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
pNew->cPages = (pNew->Core.KeyLast - (pNew->Core.Key & X86_PTE_PAE_PG_MASK_FULL) + PAGE_SIZE) >> PAGE_SHIFT;
pCur->cPages = (pCur->Core.KeyLast - (pCur->Core.Key & X86_PTE_PAE_PG_MASK_FULL) + PAGE_SIZE) >> PAGE_SHIFT;
return VINF_SUCCESS;
AssertMsgFailed(("outside range: %RGp-%RGp split %RGp\n", pCur->Core.Key, pCur->Core.KeyLast, GCPhysSplit));
return rc;
int rc;
PPGMPHYSHANDLER pCur1 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys1);
PPGMPHYSHANDLER pCur2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
PPGMPHYSHANDLER pCur3 = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
pCur1->cPages = (pCur1->Core.KeyLast - (pCur1->Core.Key & X86_PTE_PAE_PG_MASK_FULL) + PAGE_SIZE) >> PAGE_SHIFT;
return VINF_SUCCESS;
return rc;
int rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
case PGMPHYSHANDLERTYPE_MMIO: /* NOTE: Only use when clearing MMIO ranges with aliased MMIO2 pages! */
STAM_COUNTER_INC(&pVM->pgm.s.CTX_SUFF(pStats)->CTX_MID_Z(Stat,PhysHandlerReset)); /**@Todo move out of switch */
while (cLeft-- > 0)
pgmHandlerPhysicalResetAliasedPage(pVM, pPage, pRam->GCPhys + ((RTGCPHYS)(uintptr_t)(pPage - &pRam->aPages[0]) << PAGE_SHIFT));
pPage++;
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VERR_PGM_HANDLER_NOT_FOUND;
VMMDECL(int) PGMHandlerPhysicalPageAlias(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTGCPHYS GCPhysPageRemap)
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
AssertReturnStmt((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK, pgmUnlock(pVM), VERR_INVALID_PARAMETER);
return VINF_PGM_HANDLER_ALREADY_ALIASED;
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VERR_PGM_HANDLER_NOT_FOUND;
VMMDECL(int) PGMHandlerPhysicalPageAliasHC(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTHCPHYS HCPhysPageRemap)
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
AssertReturnStmt((pCur->Core.KeyLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK, pgmUnlock(pVM), VERR_INVALID_PARAMETER);
return VINF_PGM_HANDLER_ALREADY_ALIASED;
* IOM read and write functions. Access through PGMPhysRead/Write will crash the process.
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VERR_PGM_HANDLER_NOT_FOUND;
if (pCur)
if (!pCur)
AssertFailed();
return bRet;
PPGMVIRTHANDLER pCur = (PPGMVIRTHANDLER)RTAvlroGCPtrGet(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, GCPtr);
int pgmHandlerVirtualFindByPhysAddr(PVM pVM, RTGCPHYS GCPhys, PPGMVIRTHANDLER *ppVirt, unsigned *piPage)
pCur = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, GCPhys);
if (pCur)
LogFlow(("PHYS2VIRT: found match for %RGp -> %RGv *piPage=%#x\n", GCPhys, (*ppVirt)->Core.Key, *piPage));
return VINF_SUCCESS;
return VERR_PGM_HANDLER_NOT_FOUND;
/** @todo Deal with partial overlapping. (Unlikly situation, so I'm too lazy to do anything about it now.) */
* and I'm too lazy to implement this now as it will require sorting the list and stuff like that. */
PPGMPHYS2VIRTHANDLER pHead = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key);
LogRel(("pgmHandlerVirtualInsertAliased: %RGp-%RGp\n", pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast));
PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pHead + (pHead->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
Log(("pgmHandlerVirtualInsertAliased: %RGp-%RGp offNextAlias=%#RX32\n", pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias));
* when there have been registration/deregistrations). For this reason this
AssertReleaseMsg(RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key) == &pPhys2Virt->Core,
pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias, R3STRING(pCur->pszDesc)));
offPage = 0;
static DECLCALLBACK(int) pgmHandlerVirtualDumpPhysPagesCallback(PAVLROGCPHYSNODECORE pNode, void *pvUser)
Log(("PHYS2VIRT: Range %RGp-%RGp for virtual handler: %s\n", pCur->Core.Key, pCur->Core.KeyLast, pVirt->pszDesc));
#ifdef VBOX_STRICT
typedef struct PGMAHAFIS
unsigned uVirtStateFound;
unsigned uVirtState;
unsigned cErrors;
static DECLCALLBACK(int) pgmHandlerVirtualVerifyOneByPhysAddr(PAVLROGCPTRNODECORE pNode, void *pvUser)
case PGMVIRTHANDLERTYPE_WRITE:
case PGMVIRTHANDLERTYPE_ALL:
if ( (pVirt->aPhysToVirt[0].Core.Key & PAGE_OFFSET_MASK) != ((RTGCUINTPTR)pVirt->Core.Key & PAGE_OFFSET_MASK)
if ( (pVirt->aPhysToVirt[pVirt->cPages - 1].Core.KeyLast & PAGE_OFFSET_MASK) != ((RTGCUINTPTR)pVirt->Core.KeyLast & PAGE_OFFSET_MASK)
pVirt->aPhysToVirt[pVirt->cPages - 1].Core.KeyLast, pVirt->Core.KeyLast, R3STRING(pVirt->pszDesc)));
if (!pPage)
AssertMsgFailed(("virt handler state mismatch. pPage=%R[pgmpage] GCPhysGst=%RGp iPage=%#x %RGv state=%d expected>=%d %s\n",
pPage, GCPhysGst, iPage, GCPtr, PGM_PAGE_GET_HNDL_VIRT_STATE(pPage), uState, R3STRING(pVirt->pszDesc)));
PPGMPHYSHANDLER pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pPGM->CTX_SUFF(pTrees)->PhysHandlers, State.GCPhys);
if (!pPhys)
pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTX_SUFF(pTrees)->PhysHandlers, State.GCPhys, true);
if ( pPhys
if (pPhys)
PPGMPHYSHANDLER pPhys2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTX_SUFF(pTrees)->PhysHandlers,
if ( !pPhys2
#ifdef IN_RING3
AssertMsgFailed(("ram range vs phys handler mismatch. no handler for GCPhys=%RGp\n", State.GCPhys));
PPGMPHYS2VIRTHANDLER pPhys2Virt = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGetBestFit(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers,
if ( !pPhys2Virt
pPhys2Virt = (PPGMPHYS2VIRTHANDLER)((uintptr_t)pPhys2Virt + (pPhys2Virt->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
RTAvlroGCPtrDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, true, pgmHandlerVirtualVerifyOneByPhysAddr, &State);
AssertMsgFailed(("ram range vs virt handler flags mismatch. GCPhys=%RGp uVirtState=%#x uVirtStateFound=%#x\n",
RTAvlroGCPtrDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, true, pgmHandlerVirtualVerifyOne, &State);