PGMAllHandler.cpp revision 7d7781c2167838d939abeace6ff2998832ef55be
236b2935f217749893b7034e59da3e3568928acevboxsync * PGM - Page Manager / Monitor, Access Handlers.
236b2935f217749893b7034e59da3e3568928acevboxsync * Copyright (C) 2006-2007 innotek GmbH
236b2935f217749893b7034e59da3e3568928acevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
236b2935f217749893b7034e59da3e3568928acevboxsync * available from http://www.virtualbox.org. This file is free software;
236b2935f217749893b7034e59da3e3568928acevboxsync * you can redistribute it and/or modify it under the terms of the GNU
236b2935f217749893b7034e59da3e3568928acevboxsync * General Public License (GPL) as published by the Free Software
236b2935f217749893b7034e59da3e3568928acevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
236b2935f217749893b7034e59da3e3568928acevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
236b2935f217749893b7034e59da3e3568928acevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
236b2935f217749893b7034e59da3e3568928acevboxsync/*******************************************************************************
236b2935f217749893b7034e59da3e3568928acevboxsync* Header Files *
236b2935f217749893b7034e59da3e3568928acevboxsync*******************************************************************************/
236b2935f217749893b7034e59da3e3568928acevboxsync/*******************************************************************************
236b2935f217749893b7034e59da3e3568928acevboxsync* Internal Functions *
2ac3892cdc8b16a0dee55e8b4510b8ecea83c95fvboxsync*******************************************************************************/
2ac3892cdc8b16a0dee55e8b4510b8ecea83c95fvboxsyncstatic int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam);
2ac3892cdc8b16a0dee55e8b4510b8ecea83c95fvboxsyncstatic void pgmHandlerPhysicalDeregisterNotifyREM(PVM pVM, PPGMPHYSHANDLER pCur);
2ac3892cdc8b16a0dee55e8b4510b8ecea83c95fvboxsyncstatic void pgmHandlerPhysicalResetRamFlags(PVM pVM, PPGMPHYSHANDLER pCur);
2ac3892cdc8b16a0dee55e8b4510b8ecea83c95fvboxsync * Register a access handler for a physical range.
2ac3892cdc8b16a0dee55e8b4510b8ecea83c95fvboxsync * @returns VBox status code.
2ac3892cdc8b16a0dee55e8b4510b8ecea83c95fvboxsync * @retval VINF_SUCCESS when successfully installed.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @retval VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * flagged together with a pool clearing.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @retval VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * one. A debug assertion is raised.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pVM VM Handle.
236b2935f217749893b7034e59da3e3568928acevboxsync * @param enmType Handler type. Any of the PGMPHYSHANDLERTYPE_PHYSICAL* enums.
236b2935f217749893b7034e59da3e3568928acevboxsync * @param GCPhys Start physical address.
236b2935f217749893b7034e59da3e3568928acevboxsync * @param GCPhysLast Last physical address. (inclusive)
236b2935f217749893b7034e59da3e3568928acevboxsync * @param pfnHandlerR3 The R3 handler.
236b2935f217749893b7034e59da3e3568928acevboxsync * @param pvUserR3 User argument to the R3 handler.
236b2935f217749893b7034e59da3e3568928acevboxsync * @param pfnHandlerR0 The R0 handler.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pvUserR0 User argument to the R0 handler.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pfnHandlerGC The GC handler.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pvUserGC User argument to the GC handler.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * This must be a GC pointer because it will be relocated!
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * @param pszDesc Pointer to description string. This must not be freed.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsyncPGMDECL(int) PGMHandlerPhysicalRegisterEx(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
157093a77f2752732368338110cb50fa6cd7717fvboxsync R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3,
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0,
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync GCPTRTYPE(PFNPGMGCPHYSHANDLER) pfnHandlerGC, RTGCPTR pvUserGC,
eca46116c06b850c8c6be84678ba1f9dbdb3f9ddvboxsync Log(("PGMHandlerPhysicalRegisterEx: enmType=%d GCPhys=%VGp GCPhysLast=%VGp pfnHandlerR3=%VHv pvUserR3=%VHv pfnHandlerR0=%VHv pvUserR0=%VHv pfnHandlerGC=%VGv pvUserGC=%VGv pszDesc=%s\n",
eca46116c06b850c8c6be84678ba1f9dbdb3f9ddvboxsync enmType, GCPhys, GCPhysLast, pfnHandlerR3, pvUserR3, pfnHandlerR0, pvUserR0, pfnHandlerGC, pvUserGC, HCSTRING(pszDesc)));
eca46116c06b850c8c6be84678ba1f9dbdb3f9ddvboxsync * Validate input.
eca46116c06b850c8c6be84678ba1f9dbdb3f9ddvboxsync AssertMsgFailed(("GCPhys >= GCPhysLast (%#x >= %#x)\n", GCPhys, GCPhysLast));
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync AssertMsgFailed(("Invalid input enmType=%d!\n", enmType));
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync && MMHyperHC2GC(pVM, MMHyperGC2HC(pVM, pvUserGC)) != pvUserGC)
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync AssertMsgFailed(("Not GC pointer! pvUserGC=%VGv\n", pvUserGC));
bc5cd42756b3f98351040bbfccc08dd9bacd103avboxsync AssertReturn(pfnHandlerR3 || pfnHandlerR0 || pfnHandlerGC, VERR_INVALID_PARAMETER);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * We require the range to be within registered ram.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * There is no apparent need to support ranges which cover more than one ram range.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync PPGMRAMRANGE pRam = CTXALLSUFF(pVM->pgm.s.pRamRanges);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync * If this is an MMIO registration, we'll just add a range for it.
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync int rc = PGMR3PhysRegister(pVM, NULL, GCPhys, cb, MM_RAM_FLAGS_RESERVED | MM_RAM_FLAGS_MMIO, NULL, pszDesc);
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync /* search again. */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync#endif /* IN_RING3 */
5067a9619d7131c54d4ebb371d9dac91abdd34f6vboxsync AssertMsgFailed(("No RAM range for %VGp-%VGp\n", GCPhys, GCPhysLast));
return rc;
#ifndef IN_RING3
return rc;
AssertMsgFailed(("Conflict! GCPhys=%VGp GCPhysLast=%VGp pszDesc=%s\n", GCPhys, GCPhysLast, pszDesc));
static int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam)
bool fFlushTLBs = false;
#ifdef IN_RING3
return rc2;
#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
if (u16)
else if (u16 != ((MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT)) | MM_RAM_FLAGS_IDX_OVERFLOWED))
fFlushTLBs = true;
fFlushTLBs = true;
if (--cPages == 0)
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTXSUFF(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->CTXSUFF(pTrees)->PhysHandlers, GCPhys, fAbove);
if ( !pCur
if (--cPages == 0)
* For all return codes other than VERR_PGM_HANDLER_NOT_FOUND and VINF_SUCCESS the range is deregistered
PGMDECL(int) PGMHandlerPhysicalModify(PVM pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast)
int rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhysCurrent);
if (pCur)
if ( pRam
#ifndef IN_RING3
return VINF_SUCCESS;
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
return rc;
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
pNew->cPages = (pNew->Core.KeyLast - (pNew->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
pCur->cPages = (pCur->Core.KeyLast - (pCur->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
return VINF_SUCCESS;
AssertMsgFailed(("outside range: %VGp-%VGp split %VGp\n", pCur->Core.Key, pCur->Core.KeyLast, GCPhysSplit));
return rc;
int rc;
PPGMPHYSHANDLER pCur1 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys1);
if (pCur1)
PPGMPHYSHANDLER pCur2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys2);
if (pCur2)
PPGMPHYSHANDLER pCur3 = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys2);
pCur1->cPages = (pCur1->Core.KeyLast - (pCur1->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
return VINF_SUCCESS;
return rc;
int rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
case PGMPHYSHANDLERTYPE_MMIO:
return rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VERR_PGM_HANDLER_NOT_FOUND;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
return VINF_SUCCESS;
return VERR_INVALID_PARAMETER;
return VERR_PGM_HANDLER_NOT_FOUND;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
int pgmHandlerVirtualFindByPhysAddr(PVM pVM, RTGCPHYS GCPhys, PPGMVIRTHANDLER *ppVirt, unsigned *piPage)
pCur = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysRangeGet(&CTXSUFF(pVM->pgm.s.pTrees)->PhysToVirtHandlers, GCPhys);
if (pCur)
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.) */
PPGMPHYS2VIRTHANDLER pHead = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(pTrees)->PhysToVirtHandlers, pPhys2Virt->Core.Key);
if (!pHead)
#ifdef IN_RING3
LogRel(("pgmHandlerVirtualInsertAliased: %VGp-%VGp\n", pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast));
* and I'm too lazy to implement this now as it will require sorting the list and stuff like that. */
PPGMPHYS2VIRTHANDLER pNext = (PPGMPHYS2VIRTHANDLER)((intptr_t)pHead + (pHead->offNextAlias & PGMPHYS2VIRTHANDLER_OFF_MASK));
Log(("pgmHandlerVirtualInsertAliased: %VGp-%VGp offNextAlias=%#RX32\n", pPhys2Virt->Core.Key, pPhys2Virt->Core.KeyLast, pPhys2Virt->offNextAlias));
unsigned fFlags;
case PGMVIRTHANDLERTYPE_EIP:
case PGMVIRTHANDLERTYPE_WRITE: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE; break;
case PGMVIRTHANDLERTYPE_ALL: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_ALL; break;
AssertReleaseMsg(RTAvlroGCPhysGet(&pVM->pgm.s.CTXSUFF(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 %VGp-%VGp for virtual handler: %s\n", pCur->Core.Key, pCur->Core.KeyLast, pVirt->pszDesc));
#ifdef VBOX_STRICT
typedef struct PGMAHAFIS
unsigned cErrors;
unsigned fFlagsFound;
unsigned fFlags;
case PGMVIRTHANDLERTYPE_EIP:
case PGMVIRTHANDLERTYPE_WRITE: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE; break;
case PGMVIRTHANDLERTYPE_ALL: pState->fFlagsFound |= MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_ALL; break;
if ( (pState->fFlags & (MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL))
&& (pVirt->aPhysToVirt[0].Core.Key & PAGE_OFFSET_MASK) != ((RTGCUINTPTR)pVirt->GCPtr & PAGE_OFFSET_MASK))
unsigned fFlags;
case PGMVIRTHANDLERTYPE_EIP:
case PGMVIRTHANDLERTYPE_WRITE: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE; break;
case PGMVIRTHANDLERTYPE_ALL: fFlags = MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_ALL; break;
if (!pPage)
AssertMsgFailed(("virt handler flags mismatch. HCPhys=%VHp fFlags=%#x GCPhysGst=%VGp iPage=%#x %VGv %s\n",
PPGMPHYSHANDLER pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pPGM->CTXSUFF(pTrees)->PhysHandlers, State.GCPhys);
if (!pPhys)
pPhys = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTXSUFF(pTrees)->PhysHandlers, State.GCPhys, true);
if ( pPhys
if (pPhys)
PPGMPHYSHANDLER pPhys2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pPGM->CTXSUFF(pTrees)->PhysHandlers,
if ( !pPhys2
#ifdef IN_RING3
&& (pPage->HCPhys & (MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2)) != (MM_RAM_FLAGS_ROM | MM_RAM_FLAGS_MMIO2))
AssertMsgFailed(("ram range vs phys handler mismatch. no handler for GCPhys=%RGp\n", State.GCPhys));
State.fFlags = pPage->HCPhys & (MM_RAM_FLAGS_VIRTUAL_HANDLER | MM_RAM_FLAGS_VIRTUAL_WRITE | MM_RAM_FLAGS_VIRTUAL_ALL); /// @todo PAGE FLAGS
RTAvlroGCPtrDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->VirtHandlers, true, pgmVirtHandlerVerifyOneByPhysAddr, &State);
AssertMsgFailed(("ram range vs virt handler flags mismatch. GCPhys=%RGp fFlags=%#x fFlagsFound=%#x\n",
RTAvlroGCPtrDoWithAll(CTXSUFF(&pVM->pgm.s.pTrees)->VirtHandlers, true, pgmVirtHandlerVerifyOne, &State);