PGMAllHandler.cpp revision a04fd356c6a066fa94377352c941a49be7ab83b3
4ed92248676a091e0d73db61773d9059b36d0861stoddard * PGM - Page Manager / Monitor, Access Handlers.
4ed92248676a091e0d73db61773d9059b36d0861stoddard * Copyright (C) 2006-2013 Oracle Corporation
4ed92248676a091e0d73db61773d9059b36d0861stoddard * This file is part of VirtualBox Open Source Edition (OSE), as
4ed92248676a091e0d73db61773d9059b36d0861stoddard * available from http://www.virtualbox.org. This file is free software;
b4b458e66e24979631466a69c4bae3090a7e50fewrowe * you can redistribute it and/or modify it under the terms of the GNU
4ed92248676a091e0d73db61773d9059b36d0861stoddard * General Public License (GPL) as published by the Free Software
fa29e798c69385995c601ddfe75cbd5cf29244efwrowe * Foundation, in version 2 as it comes in the "COPYING" file of the
4ed92248676a091e0d73db61773d9059b36d0861stoddard * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
fa29e798c69385995c601ddfe75cbd5cf29244efwrowe * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
424303d026faabb9e9752310911d00fa737b603awrowe/*******************************************************************************
424303d026faabb9e9752310911d00fa737b603awrowe* Header Files *
424303d026faabb9e9752310911d00fa737b603awrowe*******************************************************************************/
4c35be7cad99269afb697fccc1b9ba85dd2ce702wrowe/*******************************************************************************
4c35be7cad99269afb697fccc1b9ba85dd2ce702wrowe* Internal Functions *
4c35be7cad99269afb697fccc1b9ba85dd2ce702wrowe*******************************************************************************/
4c35be7cad99269afb697fccc1b9ba85dd2ce702wrowestatic int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam);
4c35be7cad99269afb697fccc1b9ba85dd2ce702wrowestatic void pgmHandlerPhysicalDeregisterNotifyREM(PVM pVM, PPGMPHYSHANDLER pCur);
9cef38b3a87190d0c4dcd5b389573418af9de73cwrowestatic void pgmHandlerPhysicalResetRamFlags(PVM pVM, PPGMPHYSHANDLER pCur);
b56ce33e3fe5670a4562de222c60ade06fe1bce0wrowe * Register a access handler for a physical range.
6173077ec421fe85891d4b914c87175beb0a9293wrowe * @returns VBox status code.
c71d15c4b41b9d89e90e936d49b4e5a6db19244ewrowe * @retval VINF_SUCCESS when successfully installed.
6173077ec421fe85891d4b914c87175beb0a9293wrowe * @retval VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because
6173077ec421fe85891d4b914c87175beb0a9293wrowe * the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been
c71d15c4b41b9d89e90e936d49b4e5a6db19244ewrowe * flagged together with a pool clearing.
6173077ec421fe85891d4b914c87175beb0a9293wrowe * @retval VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing
6173077ec421fe85891d4b914c87175beb0a9293wrowe * one. A debug assertion is raised.
945f023c83c2d18bf5145a5b9af48fc3216fbef6wrowe * @param pVM Pointer to the VM.
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * @param enmType Handler type. Any of the PGMPHYSHANDLERTYPE_PHYSICAL* enums.
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * @param GCPhys Start physical address.
6166dacd3c3d034394c1f8c131919ea7452835a7wrowe * @param GCPhysLast Last physical address. (inclusive)
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * @param pfnHandlerR3 The R3 handler.
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * @param pvUserR3 User argument to the R3 handler.
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * @param pfnHandlerR0 The R0 handler.
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * @param pvUserR0 User argument to the R0 handler.
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe * @param pfnHandlerRC The RC handler.
b4b458e66e24979631466a69c4bae3090a7e50fewrowe * @param pvUserRC User argument to the RC handler. This can be a value
4c35be7cad99269afb697fccc1b9ba85dd2ce702wrowe * less that 0x10000 or a (non-null) pointer that is
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * automatically relocated.
fa3f183306fa2ec98249f2afec904d403643a015wrowe * @param pszDesc Pointer to description string. This must not be freed.
743aeb835754aadabaec38c00742899668eb9dd1wroweVMMDECL(int) PGMHandlerPhysicalRegisterEx(PVM pVM, PGMPHYSHANDLERTYPE enmType, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
fa3f183306fa2ec98249f2afec904d403643a015wrowe R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3,
a78b700fa90213df137e4178a9bd9c81aadd39d3wrowe R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0,
4c35be7cad99269afb697fccc1b9ba85dd2ce702wrowe RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC,
945f023c83c2d18bf5145a5b9af48fc3216fbef6wrowe Log(("PGMHandlerPhysicalRegisterEx: enmType=%d GCPhys=%RGp GCPhysLast=%RGp pfnHandlerR3=%RHv pvUserR3=%RHv pfnHandlerR0=%RHv pvUserR0=%RHv pfnHandlerGC=%RRv pvUserGC=%RRv pszDesc=%s\n",
549b1f3d6860ae792e6a8c8d3a483140bdb857a5wrowe enmType, GCPhys, GCPhysLast, pfnHandlerR3, pvUserR3, pfnHandlerR0, pvUserR0, pfnHandlerRC, pvUserRC, R3STRING(pszDesc)));
945f023c83c2d18bf5145a5b9af48fc3216fbef6wrowe * Validate input.
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe AssertMsgReturn(GCPhys < GCPhysLast, ("GCPhys >= GCPhysLast (%#x >= %#x)\n", GCPhys, GCPhysLast), VERR_INVALID_PARAMETER);
9cef38b3a87190d0c4dcd5b389573418af9de73cwrowe /* Simplification for PGMPhysRead, PGMR0Trap0eHandlerNPMisconfig and others. */
032eeda9f618fa26f635c9e8dfd854c17e76262fwrowe AssertMsgReturn(!(GCPhys & PAGE_OFFSET_MASK), ("%RGp\n", GCPhys), VERR_INVALID_PARAMETER);
9cef38b3a87190d0c4dcd5b389573418af9de73cwrowe AssertMsgReturn((GCPhysLast & PAGE_OFFSET_MASK) == PAGE_OFFSET_MASK, ("%RGp\n", GCPhysLast), VERR_INVALID_PARAMETER);
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe AssertMsgFailed(("Invalid input enmType=%d!\n", enmType));
92fb4b4faaea055db085fc0864950c2a5edd0de2jwoolley || MMHyperR3ToRC(pVM, MMHyperRCToR3(pVM, pvUserRC)) == pvUserRC,
b56ce33e3fe5670a4562de222c60ade06fe1bce0wrowe || MMHyperR3ToR0(pVM, MMHyperR0ToR3(pVM, pvUserR0)) == pvUserR0,
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe AssertReturn(pfnHandlerRC || HMIsEnabled(pVM), VERR_INVALID_PARAMETER);
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe * We require the range to be within registered ram.
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe * There is no apparent need to support ranges which cover more than one ram range.
cfab5b5b6dc82c578597b582f76491c96b86eeb7wrowe AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
413043ed189411cd1c673fc4911b583cb85c2c39wrowe * Allocate and initialize the new entry.
cfab5b5b6dc82c578597b582f76491c96b86eeb7wrowe int rc = MMHyperAlloc(pVM, sizeof(*pNew), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew);
cfab5b5b6dc82c578597b582f76491c96b86eeb7wrowe pNew->cPages = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
f397bb616fba8b3a5a9b3c57a5c89ad0e254b673mturk * Try insert into list.
6b441c81aae632befd971e634b4a36780c71d18ewrowe if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pNew->Core))
6b441c81aae632befd971e634b4a36780c71d18ewrowe rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pNew, pRam);
7ffdcdd65e145ef18d9193d89bffff10c5da4961wrowe REMNotifyHandlerPhysicalRegister(pVM, enmType, GCPhys, GCPhysLast - GCPhys + 1, !!pfnHandlerR3);
7ffdcdd65e145ef18d9193d89bffff10c5da4961wrowe REMR3NotifyHandlerPhysicalRegister(pVM, enmType, GCPhys, GCPhysLast - GCPhys + 1, !!pfnHandlerR3);
9cef38b3a87190d0c4dcd5b389573418af9de73cwrowe Log(("PGMHandlerPhysicalRegisterEx: returns %Rrc (%RGp-%RGp)\n", rc, GCPhys, GCPhysLast));
50feafa397d01128b8cf94ad1602d3d78e1a4169wrowe DBGFR3Info(pVM->pUVM, "handlers", "phys nostats", NULL);
ea0acbc141b3ca2ef21666bd23bfea9af9a758aawrowe AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp pszDesc=%s\n", GCPhys, GCPhysLast, pszDesc));
50feafa397d01128b8cf94ad1602d3d78e1a4169wrowe * Sets ram range flags and attempts updating shadow PTs.
98086904a5df1d6127b49bf06af39f23ff844889wrowe * @returns VBox status code.
98086904a5df1d6127b49bf06af39f23ff844889wrowe * @retval VINF_SUCCESS when shadow PTs was successfully updated.
b4b458e66e24979631466a69c4bae3090a7e50fewrowe * @retval VINF_PGM_SYNC_CR3 when the shadow PTs could be updated because
b4b458e66e24979631466a69c4bae3090a7e50fewrowe * the guest page aliased or/and mapped by multiple PTs. FFs set.
b4b458e66e24979631466a69c4bae3090a7e50fewrowe * @param pVM Pointer to the VM.
b4b458e66e24979631466a69c4bae3090a7e50fewrowe * @param pCur The physical handler.
b4b458e66e24979631466a69c4bae3090a7e50fewrowe * @param pRam The RAM range.
549b1f3d6860ae792e6a8c8d3a483140bdb857a5wrowestatic int pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(PVM pVM, PPGMPHYSHANDLER pCur, PPGMRAMRANGE pRam)
549b1f3d6860ae792e6a8c8d3a483140bdb857a5wrowe * Iterate the guest ram pages updating the flags and flushing PT entries
4ed92248676a091e0d73db61773d9059b36d0861stoddard * mapping the page.
549b1f3d6860ae792e6a8c8d3a483140bdb857a5wrowe bool fFlushTLBs = false;
4ed92248676a091e0d73db61773d9059b36d0861stoddard const unsigned uState = pgmHandlerPhysicalCalcState(pCur);
4ed92248676a091e0d73db61773d9059b36d0861stoddard uint32_t i = (pCur->Core.Key - pRam->GCPhys) >> PAGE_SHIFT;
b4b458e66e24979631466a69c4bae3090a7e50fewrowe AssertMsg(pCur->enmType != PGMPHYSHANDLERTYPE_MMIO || PGM_PAGE_IS_MMIO(pPage),
945f023c83c2d18bf5145a5b9af48fc3216fbef6wrowe ("%RGp %R[pgmpage]\n", pRam->GCPhys + (i << PAGE_SHIFT), pPage));
945f023c83c2d18bf5145a5b9af48fc3216fbef6wrowe /* Only do upgrades. */
50feafa397d01128b8cf94ad1602d3d78e1a4169wrowe int rc2 = pgmPoolTrackUpdateGCPhys(pVM, pRam->GCPhys + (i << PAGE_SHIFT), pPage,
4ed92248676a091e0d73db61773d9059b36d0861stoddard false /* allow updates of PTEs (instead of flushing) */, &fFlushTLBs);
d7f2b79379c5a3b849bf3d5dacf7180805ecba1fwrowe Log(("pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs: flushing guest TLBs; rc=%d\n", rc));
d7f2b79379c5a3b849bf3d5dacf7180805ecba1fwrowe 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)));
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * Register a physical page access handler.
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * @returns VBox status code.
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * @param pVM Pointer to the VM.
413043ed189411cd1c673fc4911b583cb85c2c39wrowe * @param GCPhys Start physical address.
413043ed189411cd1c673fc4911b583cb85c2c39wroweVMMDECL(int) PGMHandlerPhysicalDeregister(PVM pVM, RTGCPHYS GCPhys)
7a9d2ce2e2f592e97c0d4819e0e6567efcc4ba7bwrowe * Find the handler.
0b64c3e5c7379284f90efc7193f16b373df39fe1wrowe PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
c3200c488bb3f941a88d5bed94abef0f46946bd3wrowe LogFlow(("PGMHandlerPhysicalDeregister: Removing Range %RGp-%RGp %s\n",
0b64c3e5c7379284f90efc7193f16b373df39fe1wrowe pCur->Core.Key, pCur->Core.KeyLast, R3STRING(pCur->pszDesc)));
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * Clear the page bits, notify the REM about this change and clear
14d27a22a8fdb25e6e82d8af853a63bd4c6bd894wrowe * the cache.
14d5b1a7866541c4eb974f2d213d2aea59743c95wrowe AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe * Shared code with modify.
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowestatic void pgmHandlerPhysicalDeregisterNotifyREM(PVM pVM, PPGMPHYSHANDLER pCur)
14d5b1a7866541c4eb974f2d213d2aea59743c95wrowe * Page align the range.
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * Since we've reset (recalculated) the physical handler state of all pages
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * we can make use of the page states to figure out whether a page should be
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * included in the REM notification or not.
483ed5892604266e702d65db4d0b2b621c488a09wrowe && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_NONE)
0b64c3e5c7379284f90efc7193f16b373df39fe1wrowe RTGCPHYS GCPhys = (GCPhysStart + (PAGE_SIZE - 1)) & X86_PTE_PAE_PG_MASK;
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe Assert(!pPage || PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO); /* these are page aligned atm! */
c639d9d16cb8ac0ea8163c8c46e34ef9c6810ce2wrowe && PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) != PGM_PAGE_HNDL_PHYS_STATE_NONE)
c639d9d16cb8ac0ea8163c8c46e34ef9c6810ce2wrowe RTGCPHYS GCPhys = (GCPhysLast & X86_PTE_PAE_PG_MASK) - 1;
483ed5892604266e702d65db4d0b2b621c488a09wrowe Assert(!pPage || PGM_PAGE_GET_TYPE(pPage) != PGMPAGETYPE_MMIO); /* these are page aligned atm! */
58b8ccdd4dbf4b314e016de6eeebfe45be45451end * Tell REM.
255d4d329b2d41e4ac0c3ade5cfe528a078ef682wrowe && pCur->enmType != PGMPHYSHANDLERTYPE_MMIO; /** @todo this isn't entirely correct. */
483ed5892604266e702d65db4d0b2b621c488a09wrowe REMNotifyHandlerPhysicalDeregister(pVM, pCur->enmType, GCPhysStart, GCPhysLast - GCPhysStart + 1, !!pCur->pfnHandlerR3, fRestoreAsRAM);
1e83c8de3aa48b316b28057d53995272baf1260cwrowe REMR3NotifyHandlerPhysicalDeregister(pVM, pCur->enmType, GCPhysStart, GCPhysLast - GCPhysStart + 1, !!pCur->pfnHandlerR3, fRestoreAsRAM);
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * pgmHandlerPhysicalResetRamFlags helper that checks for other handlers on
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * edge pages.
1e83c8de3aa48b316b28057d53995272baf1260cwroweDECLINLINE(void) pgmHandlerPhysicalRecalcPageState(PVM pVM, RTGCPHYS GCPhys, bool fAbove, PPGMRAMRANGE *ppRamHint)
24b0a59507af2a3621f586fa2a2aafc3640aa3d2nd * Look for other handlers.
1e83c8de3aa48b316b28057d53995272baf1260cwrowe PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGetBestFit(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys, fAbove);
0e6bee8eb9112f77eb50766e58424afac61104d9wrowe || ((fAbove ? pCur->Core.Key : pCur->Core.KeyLast) >> PAGE_SHIFT) != (GCPhys >> PAGE_SHIFT))
1e83c8de3aa48b316b28057d53995272baf1260cwrowe unsigned uThisState = pgmHandlerPhysicalCalcState(pCur);
995f5596d461cdd916f9ae5b7b4dcd27efbc3c2fwrowe /* next? */
1e83c8de3aa48b316b28057d53995272baf1260cwrowe if ((GCPhysNext >> PAGE_SHIFT) != (GCPhys >> PAGE_SHIFT))
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * Update if we found something that is a higher priority
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * state than the current.
522c5d883dd6489e5b3583c52502365e09d64382mturk int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, ppRamHint);
2d7d2ccd828d0424f046b62d57e5551cf8ee293fwrowe /* This should normally not be necessary. */
483ed5892604266e702d65db4d0b2b621c488a09wrowe rc = pgmPoolTrackUpdateGCPhys(pVM, GCPhys, pPage, false /*fFlushPTEs*/, &fFlushTLBs);
483ed5892604266e702d65db4d0b2b621c488a09wrowe * Resets an aliased page.
fa3f183306fa2ec98249f2afec904d403643a015wrowe * @param pVM The VM.
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * @param pPage The page.
743aeb835754aadabaec38c00742899668eb9dd1wrowe * @param GCPhysPage The page address in case it comes in handy.
1e83c8de3aa48b316b28057d53995272baf1260cwrowe * @param fDoAccounting Whether to perform accounting. (Only set during
743aeb835754aadabaec38c00742899668eb9dd1wrowe * reset where pgmR3PhysRamReset doesn't have the
a8f3504993ae9a401b6fc87c7a00b716b112e3d0wrowe * handler structure handy.)
1e83c8de3aa48b316b28057d53995272baf1260cwrowevoid pgmHandlerPhysicalResetAliasedPage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhysPage, bool fDoAccounting)
c82ccb99a59cb210c31b096a567e393e59d558f3colm Assert(PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO);
1e83c8de3aa48b316b28057d53995272baf1260cwrowe Assert(PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_DISABLED);
c639d9d16cb8ac0ea8163c8c46e34ef9c6810ce2wrowe * Flush any shadow page table references *first*.
1e83c8de3aa48b316b28057d53995272baf1260cwrowe bool fFlushTLBs = false;
91884afe32b87f355822244b8c123ea5b770368fwrowe int rc = pgmPoolTrackUpdateGCPhys(pVM, GCPhysPage, pPage, true /*fFlushPTEs*/, &fFlushTLBs);
b56ce33e3fe5670a4562de222c60ade06fe1bce0wrowe * Make it an MMIO/Zero page.
b56ce33e3fe5670a4562de222c60ade06fe1bce0wrowe PGM_PAGE_SET_HCPHYS(pVM, pPage, pVM->pgm.s.HCPhysZeroPg);
c639d9d16cb8ac0ea8163c8c46e34ef9c6810ce2wrowe PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_ALL);
c639d9d16cb8ac0ea8163c8c46e34ef9c6810ce2wrowe /* Flush its TLB entry. */
b56ce33e3fe5670a4562de222c60ade06fe1bce0wrowe * Do accounting for pgmR3PhysRamReset.
b56ce33e3fe5670a4562de222c60ade06fe1bce0wrowe PPGMPHYSHANDLER pHandler = pgmHandlerPhysicalLookup(pVM, GCPhysPage);
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe * Resets ram range flags.
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe * @returns VBox status code.
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe * @retval VINF_SUCCESS when shadow PTs was successfully updated.
9cef38b3a87190d0c4dcd5b389573418af9de73cwrowe * @param pVM Pointer to the VM.
634c70c6512b0ae61fb1ee130266e6e9af170803wrowe * @param pCur The physical handler.
d7f2b79379c5a3b849bf3d5dacf7180805ecba1fwrowe * @remark We don't start messing with the shadow page tables, as we've
d7f2b79379c5a3b849bf3d5dacf7180805ecba1fwrowe * already got code in Trap0e which deals with out of sync handler
ea0acbc141b3ca2ef21666bd23bfea9af9a758aawrowe * flags (originally conceived for global pages).
d7f2b79379c5a3b849bf3d5dacf7180805ecba1fwrowestatic void pgmHandlerPhysicalResetRamFlags(PVM pVM, PPGMPHYSHANDLER pCur)
9cef38b3a87190d0c4dcd5b389573418af9de73cwrowe * Iterate the guest ram pages updating the state.
945f023c83c2d18bf5145a5b9af48fc3216fbef6wrowe int rc = pgmPhysGetPageWithHintEx(pVM, GCPhys, &pPage, &pRamHint);
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe /* Reset MMIO2 for MMIO pages to MMIO, since this aliasing is our business.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe (We don't flip MMIO to RAM though, that's PGMPhys.cpp's job.) */
14d27a22a8fdb25e6e82d8af853a63bd4c6bd894wrowe if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO)
6bc96ef510ce100bfdeefd80b8f05c010373ed13wrowe pgmHandlerPhysicalResetAliasedPage(pVM, pPage, GCPhys, false /*fDoAccounting*/);
a04a085d201d1620c077ba6ecaa7022b417b1cd5tdonovan AssertMsg(pCur->enmType != PGMPHYSHANDLERTYPE_MMIO || PGM_PAGE_IS_MMIO(pPage), ("%RGp %R[pgmpage]\n", GCPhys, pPage));
721a5708aab94cd3587ecff3c5775c985efb7125wrowe PGM_PAGE_SET_HNDL_PHYS_STATE(pPage, PGM_PAGE_HNDL_PHYS_STATE_NONE);
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe if (--cPages == 0)
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * Check for partial start and end pages.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe pgmHandlerPhysicalRecalcPageState(pVM, pCur->Core.Key - 1, false /* fAbove */, &pRamHint);
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe if ((pCur->Core.KeyLast & PAGE_OFFSET_MASK) != PAGE_OFFSET_MASK)
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe pgmHandlerPhysicalRecalcPageState(pVM, pCur->Core.KeyLast + 1, true /* fAbove */, &pRamHint);
bf03ef02d5f0f64ee0e91f3c4007154897d4dd34mturk * Modify a physical page access handler.
483ed5892604266e702d65db4d0b2b621c488a09wrowe * Modification can only be done to the range it self, not the type or anything else.
483ed5892604266e702d65db4d0b2b621c488a09wrowe * @returns VBox status code.
483ed5892604266e702d65db4d0b2b621c488a09wrowe * For all return codes other than VERR_PGM_HANDLER_NOT_FOUND and VINF_SUCCESS the range is deregistered
ee8892ba26f52316734c59d8002ab349c2e3fdbdcolm * and a new registration must be performed!
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * @param pVM Pointer to the VM.
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe * @param GCPhysCurrent Current location.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * @param GCPhys New location.
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wrowe * @param GCPhysLast New last location.
7c11b20dfccedb7381518b3cc3cc9ef9e6731cb1wroweVMMDECL(int) PGMHandlerPhysicalModify(PVM pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast)
c639d9d16cb8ac0ea8163c8c46e34ef9c6810ce2wrowe * Remove it.
483ed5892604266e702d65db4d0b2b621c488a09wrowe PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhysCurrent);
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * Clear the ram flags. (We're gonna move or free it!)
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe && pCur->enmType != PGMPHYSHANDLERTYPE_MMIO; /** @todo this isn't entirely correct. */
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * Validate the new range, modify and reinsert.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * We require the range to be within registered ram.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * There is no apparent need to support ranges which cover more than one ram range.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe pCur->cPages = (GCPhysLast - (GCPhys & X86_PTE_PAE_PG_MASK) + 1) >> PAGE_SHIFT;
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe if (RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pCur->Core))
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * Set ram flags, flush shadow PT entries and finally tell REM about this.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe rc = pgmHandlerPhysicalSetRamFlagsAndFlushShadowPTs(pVM, pCur, pRam);
a21b3b9d8ebb12fd51fa1d17e44d5644a35a9a5fnd REMNotifyHandlerPhysicalModify(pVM, enmType, GCPhysCurrent, GCPhys, cb,
522c5d883dd6489e5b3583c52502365e09d64382mturk REMR3NotifyHandlerPhysicalModify(pVM, enmType, GCPhysCurrent, GCPhys, cb,
483ed5892604266e702d65db4d0b2b621c488a09wrowe Log(("PGMHandlerPhysicalModify: GCPhysCurrent=%RGp -> GCPhys=%RGp GCPhysLast=%RGp\n",
483ed5892604266e702d65db4d0b2b621c488a09wrowe AssertMsgFailed(("Conflict! GCPhys=%RGp GCPhysLast=%RGp\n", GCPhys, GCPhysLast));
752c83c97683b1fb9879ba874593a135155a043cwrowe AssertMsgFailed(("No RAM range for %RGp-%RGp\n", GCPhys, GCPhysLast));
752c83c97683b1fb9879ba874593a135155a043cwrowe AssertMsgFailed(("Invalid range %RGp-%RGp\n", GCPhys, GCPhysLast));
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * Invalid new location, flush the cache and free it.
c639d9d16cb8ac0ea8163c8c46e34ef9c6810ce2wrowe * We've only gotta notify REM and free the memory.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhysCurrent));
37e7fdce0a4809a6c4cd3c102fc4668a6659ca95wrowe * Changes the callbacks associated with a physical access handler.
25813a71353f3b45ca1ddda037b395cced603564slive * @returns VBox status code.
424303d026faabb9e9752310911d00fa737b603awrowe * @param pVM Pointer to the VM.
424303d026faabb9e9752310911d00fa737b603awrowe * @param GCPhys Start physical address.
0bfd482e54583b43b826299aa6c9853f703191edwrowe * @param pfnHandlerR3 The R3 handler.
37e7fdce0a4809a6c4cd3c102fc4668a6659ca95wrowe * @param pvUserR3 User argument to the R3 handler.
341fe490659bc00823087e34c84ae13567d9fb8fwrowe * @param pfnHandlerR0 The R0 handler.
37e7fdce0a4809a6c4cd3c102fc4668a6659ca95wrowe * @param pvUserR0 User argument to the R0 handler.
37e7fdce0a4809a6c4cd3c102fc4668a6659ca95wrowe * @param pfnHandlerRC The RC handler.
37e7fdce0a4809a6c4cd3c102fc4668a6659ca95wrowe * @param pvUserRC User argument to the RC handler. Values larger or
1462f24d09bed587fcdfb69abf1e858598a06382wrowe * equal to 0x10000 will be relocated automatically.
1462f24d09bed587fcdfb69abf1e858598a06382wrowe * @param pszDesc Pointer to description string. This must not be freed.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wroweVMMDECL(int) PGMHandlerPhysicalChangeCallbacks(PVM pVM, RTGCPHYS GCPhys,
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe R3PTRTYPE(PFNPGMR3PHYSHANDLER) pfnHandlerR3, RTR3PTR pvUserR3,
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe R0PTRTYPE(PFNPGMR0PHYSHANDLER) pfnHandlerR0, RTR0PTR pvUserR0,
fdc76d3c3f3fea82ba0f1d8af646f8ea5e4734a2wrowe RCPTRTYPE(PFNPGMRCPHYSHANDLER) pfnHandlerRC, RTRCPTR pvUserRC,
875f57a863e8f7522f78c370e25db2a552231ca8wrowe * Get the handler.
875f57a863e8f7522f78c370e25db2a552231ca8wrowe PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe * Change callbacks.
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
19725e678f8b916b0952a002356d2098301e9727wrowe * Splits a physical access handler in two.
823627d210d6c8bf02aec333587428584b29b6e2wrowe * @returns VBox status code.
823627d210d6c8bf02aec333587428584b29b6e2wrowe * @param pVM Pointer to the VM.
823627d210d6c8bf02aec333587428584b29b6e2wrowe * @param GCPhys Start physical address of the handler.
19725e678f8b916b0952a002356d2098301e9727wrowe * @param GCPhysSplit The split address.
19725e678f8b916b0952a002356d2098301e9727wroweVMMDECL(int) PGMHandlerPhysicalSplit(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysSplit)
f2f6daffb4236c6781e779e57561581c92a1f539wrowe AssertReturn(GCPhys < GCPhysSplit, VERR_INVALID_PARAMETER);
032eeda9f618fa26f635c9e8dfd854c17e76262fwrowe * Do the allocation without owning the lock.
032eeda9f618fa26f635c9e8dfd854c17e76262fwrowe int rc = MMHyperAlloc(pVM, sizeof(*pNew), 0, MM_TAG_PGM_HANDLERS, (void **)&pNew);
032eeda9f618fa26f635c9e8dfd854c17e76262fwrowe * Get the handler.
032eeda9f618fa26f635c9e8dfd854c17e76262fwrowe PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe * Create new handler node for the 2nd half.
823627d210d6c8bf02aec333587428584b29b6e2wrowe pNew->cPages = (pNew->Core.KeyLast - (pNew->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
f1b8465dec39c934d4bef4a2366139ffdd021851wrowe pCur->cPages = (pCur->Core.KeyLast - (pCur->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe if (RT_LIKELY(RTAvlroGCPhysInsert(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, &pNew->Core)))
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe LogFlow(("PGMHandlerPhysicalSplit: %RGp-%RGp and %RGp-%RGp\n",
19725e678f8b916b0952a002356d2098301e9727wrowe pCur->Core.Key, pCur->Core.KeyLast, pNew->Core.Key, pNew->Core.KeyLast));
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe AssertMsgFailed(("outside range: %RGp-%RGp split %RGp\n", pCur->Core.Key, pCur->Core.KeyLast, GCPhysSplit));
f99d4fa2605925f385a184ba3789be3423690533wrowe AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys));
72347cd608351452f99d5f4411d3e0c089d0293awrowe * Joins up two adjacent physical access handlers which has the same callbacks.
f99d4fa2605925f385a184ba3789be3423690533wrowe * @returns VBox status code.
60f8e9cbbfc2d757c71db17a35acb8566eebc0dawrowe * @param pVM Pointer to the VM.
d0b14e6c6aabb4ed84bc056df6caeae146973c21wrowe * @param GCPhys1 Start physical address of the first handler.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * @param GCPhys2 Start physical address of the second handler.
0bcc003d275c6b0a9060d43be89762b218cbc2c7wroweVMMDECL(int) PGMHandlerPhysicalJoin(PVM pVM, RTGCPHYS GCPhys1, RTGCPHYS GCPhys2)
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe * Get the handlers.
a901f6f8425b207639fe2d1e22b102d96f8e64ffwrowe PPGMPHYSHANDLER pCur1 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys1);
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe PPGMPHYSHANDLER pCur2 = (PPGMPHYSHANDLER)RTAvlroGCPhysGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
f99d4fa2605925f385a184ba3789be3423690533wrowe * Make sure that they are adjacent, and that they've got the same callbacks.
1e83c8de3aa48b316b28057d53995272baf1260cwrowe if (RT_LIKELY(pCur1->Core.KeyLast + 1 == pCur2->Core.Key))
72347cd608351452f99d5f4411d3e0c089d0293awrowe if (RT_LIKELY( pCur1->pfnHandlerRC == pCur2->pfnHandlerRC
72347cd608351452f99d5f4411d3e0c089d0293awrowe PPGMPHYSHANDLER pCur3 = (PPGMPHYSHANDLER)RTAvlroGCPhysRemove(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys2);
c2e5fcbd499ae7b5093d4877ff42e6c5ec74352bwrowe pCur1->cPages = (pCur1->Core.KeyLast - (pCur1->Core.Key & X86_PTE_PAE_PG_MASK) + PAGE_SIZE) >> PAGE_SHIFT;
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe LogFlow(("PGMHandlerPhysicalJoin: %RGp-%RGp %RGp-%RGp\n",
0bcc003d275c6b0a9060d43be89762b218cbc2c7wrowe pCur1->Core.Key, pCur1->Core.KeyLast, pCur2->Core.Key, pCur2->Core.KeyLast));
edf585d6f44e9019b3ab45be869d7d2ad23e5daewrowe AssertMsgFailed(("not adjacent: %RGp-%RGp %RGp-%RGp\n",
9fb3226780b297bcc320cb19cc3ec23194fac8e1wrowe pCur1->Core.Key, pCur1->Core.KeyLast, pCur2->Core.Key, pCur2->Core.KeyLast));
a19c94edefc000de60a6925b4ca15637e2f785f1wrowe AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys2));
6bc96ef510ce100bfdeefd80b8f05c010373ed13wrowe AssertMsgFailed(("Didn't find range starting at %RGp\n", GCPhys1));
f99d4fa2605925f385a184ba3789be3423690533wrowe * Resets any modifications to individual pages in a physical page access
1f0a9798d1c29e1e0cbdb339a0262ba287a29ed4wrowe * handler region.
525973b478c06cd0e8c457ade5c378dcae7485d2wrowe * This is used in pair with PGMHandlerPhysicalPageTempOff(),
0b54189e53778165cf497165f6b04af200fab8cawrowe * PGMHandlerPhysicalPageAlias() or PGMHandlerPhysicalPageAliasHC().
22390e3a41c29735e7c138ab3ea50b876b82b0e6wrowe * @returns VBox status code.
22390e3a41c29735e7c138ab3ea50b876b82b0e6wrowe * @param pVM Pointer to the VM
e3c59608a643aac0e86a0e8cf2d62f8ef655337fwrowe * @param GCPhys The start address of the handler regions, i.e. what you
e3c59608a643aac0e86a0e8cf2d62f8ef655337fwrowe * passed to PGMR3HandlerPhysicalRegister(),
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)
#ifndef VBOX_STRICT
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. (Unlikely 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 VBOX_WITH_REM
# 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);