PGMAllPool.cpp revision 0975ae0a0fb615c945150c48e4a73187c1f4f84d
adf2bcd2e5d07d5a11553b88e147c1f4b2249bffvboxsync * PGM Shadow Page Pool.
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * available from http://www.virtualbox.org. This file is free software;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * you can redistribute it and/or modify it under the terms of the GNU
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * General Public License (GPL) as published by the Free Software
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * additional information or have any questions.
70bb61ea2f96e80150e807529ce5df435607706bvboxsync/*******************************************************************************
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync* Header Files *
23179f1443b03947d85eccc81cbc6b5153a4abf3vboxsync*******************************************************************************/
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync/*******************************************************************************
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync* Internal Functions *
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync*******************************************************************************/
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsyncDECLINLINE(unsigned) pgmPoolTrackGetShadowEntrySize(PGMPOOLKIND enmKind);
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsyncDECLINLINE(unsigned) pgmPoolTrackGetGuestEntrySize(PGMPOOLKIND enmKind);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic void pgmPoolTrackDeref(PPGMPOOL pPool, PPGMPOOLPAGE pPage);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic void pgmPoolTracDerefGCPhysHint(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhysHint);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic int pgmPoolTrackAddUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic void pgmPoolMonitorModifiedRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncDECLEXPORT(int) pgmPoolAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync * Checks if the specified page pool kind is for a 4MB or 2MB guest page.
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync * @returns true if it's the shadow of a 4MB or 2MB guest page, otherwise false.
db0ecde8f28fdb4525bc6d94056166c70b02ebb8vboxsync * @param enmKind The page kind.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsyncDECLINLINE(bool) pgmPoolIsBigPage(PGMPOOLKIND enmKind)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return true;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return false;
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync#if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0)
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * Maps a pool page into the current context.
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * @returns Pointer to the mapping.
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * @param pPGM Pointer to the PGM instance data.
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * @param pPage The page to map.
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsyncvoid *pgmPoolMapPageFallback(PPGM pPGM, PPGMPOOLPAGE pPage)
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync /* general pages are take care of by the inlined part, it
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync only ends up here in case of failure. */
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync AssertReleaseReturn(pPage->idx < PGMPOOL_IDX_FIRST, NULL);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync/** @todo make sure HCPhys is valid for *all* indexes. */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /* special pages. */
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync AssertReleaseMsgFailed(("Invalid index %d\n", pPage->idx));
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync# else /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync AssertReleaseMsgFailed(("PGMPOOL_IDX_PAE_PD is not usable in VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 context\n"));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync AssertReleaseMsgFailed(("Invalid index %d\n", pPage->idx));
9ca017ceee656f9d33f2cb6652e401b5f17fcfb7vboxsync AssertMsg(HCPhys && HCPhys != NIL_RTHCPHYS && !(PAGE_OFFSET_MASK & HCPhys), ("%RHp\n", HCPhys));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync# endif /* VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync#endif /* IN_RC || VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0 */
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync * Determin the size of a write instruction.
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync * @returns number of bytes written.
dbabc9de5bf52ce5eb77cf82b038e9a6166c5a04vboxsync * @param pDis The disassembler state.
4090390866c02d5d0ad061151cdb298b9a173e86vboxsyncstatic unsigned pgmPoolDisasWriteSize(PDISCPUSTATE pDis)
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * This is very crude and possibly wrong for some opcodes,
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * but since it's not really supposed to be called we can
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * probably live with that.
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync * Flushes a chain of pages sharing the same access monitor.
7708252d252a55417a6a817041e4356797e34255vboxsync * @returns VBox status code suitable for scheduling.
5a41049c24bcf93e3dc63c76bee23db645867e0cvboxsync * @param pPool The pool.
62ab017295981c81484e5a5f93ff8b5f85f7defbvboxsync * @param pPage A page in the chain.
7708252d252a55417a6a817041e4356797e34255vboxsyncint pgmPoolMonitorChainFlush(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync LogFlow(("pgmPoolMonitorChainFlush: Flush page %RGp type=%d\n", pPage->GCPhys, pPage->enmKind));
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync * Find the list head.
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync * Iterate the list flushing each shadow page.
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync if (rc2 == VERR_PGM_POOL_CLEARED && rc == VINF_SUCCESS)
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync * Wrapper for getting the current context pointer to the entry being modified.
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync * @returns Pointer to the current context mapping of the entry.
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync * @param pPool The pool.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pvFault The fault virtual address.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param GCPhysFault The fault physical address.
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * @param cbEntry The entry size.
9353e321b583ed6f2b42414257a5212885575b5cvboxsyncDECLINLINE(const void *) pgmPoolMonitorGCPtr2CCPtr(PPGMPOOL pPool, RTHCPTR pvFault, RTGCPHYS GCPhysFault, const unsigned cbEntry)
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsyncDECLINLINE(const void *) pgmPoolMonitorGCPtr2CCPtr(PPGMPOOL pPool, RTGCPTR pvFault, RTGCPHYS GCPhysFault, const unsigned cbEntry)
1c6ec9a3a329da6f61978a372e509cd233f0d9f9vboxsync return (const void *)((RTGCUINTPTR)pvFault & ~(RTGCUINTPTR)(cbEntry - 1));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync int rc = PGMDynMapGCPageOff(pPool->pVMR0, GCPhysFault & ~(RTGCPHYS)(cbEntry - 1), &pvRet);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync int rc = pgmRamGCPhys2HCPtr(&pPool->pVMR0->pgm.s, GCPhysFault & ~(RTGCPHYS)(cbEntry - 1), &pvRet);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return (RTHCPTR)((uintptr_t)pvFault & ~(RTHCUINTPTR)(cbEntry - 1));
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * Process shadow entries before they are changed by the guest.
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * For PT entries we will clear them. For PD entries, we'll simply check
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * for mapping conflicts and set the SyncCR3 FF if found.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param pPool The pool.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param pPage The head page.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param GCPhysFault The guest physical fault address.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync * @param uAddress In R0 and GC this is the guest context fault address (flat).
95cb8e789c1eed6f2bb3195d0b996feee11d548evboxsync * In R3 this is the host context 'fault' address.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync * @param pCpu The disassembler state for figuring out the write size.
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync * This need not be specified if the caller knows we won't do cross entry accesses.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsyncvoid pgmPoolMonitorChainChanging(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhysFault, RTHCPTR pvAddress, PDISCPUSTATE pCpu)
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsyncvoid pgmPoolMonitorChainChanging(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhysFault, RTGCPTR pvAddress, PDISCPUSTATE pCpu)
19cb1f8699e352d590c4946caee33863a5157241vboxsync const unsigned off = GCPhysFault & PAGE_OFFSET_MASK;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync const unsigned cbWrite = (pCpu) ? pgmPoolDisasWriteSize(pCpu) : 0;
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync LogFlow(("pgmPoolMonitorChainChanging: %RGv phys=%RGp kind=%d cbWrite=%d\n", pvAddress, GCPhysFault, pPage->enmKind, cbWrite));
a72b5355eb89aafe6bfcc8912cf02645d7cccceavboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync PCX86PTE pGstPte = (PCX86PTE)pgmPoolMonitorGCPtr2CCPtr(pPool, pvAddress, GCPhysFault, sizeof(*pGstPte));
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync Log4(("pgmPoolMonitorChainChanging 32_32: deref %016RX64 GCPhys %08RX32\n", uShw.pPT->a[iShw].u & X86_PTE_PAE_PG_MASK, pGstPte->u & X86_PTE_PG_MASK));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* page/2 sized */
a9315925c69e4c3bb342bb317ca5b6d29e1ee467vboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
ad9e5a61fea617d40d07390ff1737277d6aef869vboxsync const unsigned iShw = (off / sizeof(X86PTE)) & (X86_PG_PAE_ENTRIES - 1);
40dce69ff1c2949a489337922f30f1021d62d864vboxsync PCX86PTE pGstPte = (PCX86PTE)pgmPoolMonitorGCPtr2CCPtr(pPool, pvAddress, GCPhysFault, sizeof(*pGstPte));
40dce69ff1c2949a489337922f30f1021d62d864vboxsync Log4(("pgmPoolMonitorChainChanging pae_32: deref %016RX64 GCPhys %08RX32\n", uShw.pPT->a[iShw].u & X86_PTE_PAE_PG_MASK, pGstPte->u & X86_PTE_PG_MASK));
cccc6ee5f7156cfcdf13acca545cf65124d9ed44vboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync PCX86PTEPAE pGstPte = (PCX86PTEPAE)pgmPoolMonitorGCPtr2CCPtr(pPool, pvAddress, GCPhysFault, sizeof(*pGstPte));
505ddd00252720bfb5569fcb17bfda53dc141e3bvboxsync Log4(("pgmPoolMonitorChainChanging pae: deref %016RX64 GCPhys %016RX64\n", uShw.pPTPae->a[iShw].u & X86_PTE_PAE_PG_MASK, pGstPte->u & X86_PTE_PAE_PG_MASK));
7708252d252a55417a6a817041e4356797e34255vboxsync /* paranoia / a bit assumptive. */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PTEPAE);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync AssertReturnVoid(iShw2 < RT_ELEMENTS(uShw.pPTPae->a));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync PCX86PTEPAE pGstPte = (PCX86PTEPAE)pgmPoolMonitorGCPtr2CCPtr(pPool, pvAddress, GCPhysFault, sizeof(*pGstPte));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync Log4(("pgmPoolMonitorChainChanging pae: deref %016RX64 GCPhys %016RX64\n", uShw.pPTPae->a[iShw2].u & X86_PTE_PAE_PG_MASK, pGstPte->u & X86_PTE_PAE_PG_MASK));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync const unsigned iShw = off / sizeof(X86PTE); // ASSUMING 32-bit guest paging!
3933885bc0c2c93436d858a14564c6179ec72872vboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync /* paranoia / a bit assumptive. */
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PTE);
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync#if 0 /* useful when running PGMAssertCR3(), a bit too troublesome for general use (TLBs). */
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync && !VM_FF_ISSET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3))
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync LogFlow(("pgmPoolMonitorChainChanging: iShw=%#x: %RX32 -> freeing it!\n", iShw, uShw.pPD->a[iShw].u));
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync# ifdef IN_RC /* TLB load - we're pushing things a bit... */
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync pgmPoolFree(pPool->CTX_SUFF(pVM), uShw.pPD->a[iShw].u & X86_PDE_PG_MASK, pPage->idx, iShw);
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync unsigned iGst = off / sizeof(X86PDE); // ASSUMING 32-bit guest paging!
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync Assert(pPage2->idx == PGMPOOL_IDX_PAE_PD_0 + iShwPdpt);
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage2);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if ((uShw.pPDPae->a[iShw].u & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == (PGM_PDFLAGS_MAPPING | X86_PDE_P))
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShwPdpt=%#x iShw=%#x!\n", iShwPdpt, iShw));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* paranoia / a bit assumptive. */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync if ( iShw2 < RT_ELEMENTS(uShw.pPDPae->a) /** @todo was completely wrong, it's better now after #1865 but still wrong from cross PD. */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync && (uShw.pPDPae->a[iShw2].u & (PGM_PDFLAGS_MAPPING | X86_PDE_P)) == (PGM_PDFLAGS_MAPPING | X86_PDE_P))
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShwPdpt=%#x iShw2=%#x!\n", iShwPdpt, iShw2));
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync#if 0 /* useful when running PGMAssertCR3(), a bit too troublesome for general use (TLBs). */
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsync && !VM_FF_ISSET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3))
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("pgmPoolMonitorChainChanging: iShwPdpt=%#x iShw=%#x: %RX64 -> freeing it!\n", iShwPdpt, iShw, uShw.pPDPae->a[iShw].u));
f4e792b5d6ee04e9d93499b747cce21510c3cdb3vboxsync# ifdef IN_RC /* TLB load - we're pushing things a bit... */
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pgmPoolFree(pPool->CTX_SUFF(pVM), uShw.pPDPae->a[iShw].u & X86_PDE_PAE_PG_MASK, pPage->idx, iShw + iShwPdpt * X86_PG_PAE_ENTRIES);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
1147e980f6ab0b7ff1d08c13ad1c03eea30d102dvboxsync#ifdef PGMPOOL_INVALIDATE_UPPER_SHADOW_TABLE_ENTRIES
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync * Causes trouble when the guest uses a PDE to refer to the whole page table level
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync * structure. (Invalidate here; faults later on when it tries to change the page
e59069cf1c98c1c2e90a18ec76fbc2e9907fb917vboxsync * table entries -> recheck; probably only applies to the RC case.)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPae->a[iShw].u));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* Note: hardcoded PAE implementation dependency */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync (pPage->enmKind == PGMPOOLKIND_PAE_PD_FOR_PAE_PD) ? PGMPOOL_IDX_PAE_PD : pPage->idx,
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync (pPage->enmKind == PGMPOOLKIND_PAE_PD_FOR_PAE_PD) ? iShw + (pPage->idx - PGMPOOL_IDX_PAE_PD_0) * X86_PG_PAE_ENTRIES : iShw);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* paranoia / a bit assumptive. */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDEPAE);
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync AssertReturnVoid(iShw2 < RT_ELEMENTS(uShw.pPDPae->a));
b304856b23107864c9c594a80cebca6006623f31vboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
b304856b23107864c9c594a80cebca6006623f31vboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
b304856b23107864c9c594a80cebca6006623f31vboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
b304856b23107864c9c594a80cebca6006623f31vboxsync#ifdef PGMPOOL_INVALIDATE_UPPER_SHADOW_TABLE_ENTRIES
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* Note: hardcoded PAE implementation dependency */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync (pPage->enmKind == PGMPOOLKIND_PAE_PD_FOR_PAE_PD) ? PGMPOOL_IDX_PAE_PD : pPage->idx,
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync (pPage->enmKind == PGMPOOLKIND_PAE_PD_FOR_PAE_PD) ? iShw2 + (pPage->idx - PGMPOOL_IDX_PAE_PD_0) * X86_PG_PAE_ENTRIES : iShw2);
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync * Hopefully this doesn't happen very often:
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync * - touching unused parts of the page
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * - messing with the bits of pd pointers without changing the physical address
21ddd8aa21b8d7ad25b18ab341ede34c1cb4a125vboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync if (iShw < X86_PG_PAE_PDPE_ENTRIES) /* don't use RT_ELEMENTS(uShw.pPDPT->a), because that's for long mode only */
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* paranoia / a bit assumptive. */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDPE);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync Assert(pPage->enmKind == PGMPOOLKIND_64BIT_PD_FOR_64BIT_PD);
8fdb854581fe3cb394d84835dc09b02e6e18d4edvboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
36929067a9d3cba77fd78f1e8fa042ed3a8ae2d6vboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
f31ac84c1c57e23801423b5bd184fadabe6456f3vboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw=%#x!\n", iShw));
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPae->a[iShw].u));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /* paranoia / a bit assumptive. */
121568d0a1e932e6f6acd49376827a0e593815favboxsync const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDEPAE);
121568d0a1e932e6f6acd49376827a0e593815favboxsync AssertReturnVoid(iShw2 < RT_ELEMENTS(uShw.pPDPae->a));
121568d0a1e932e6f6acd49376827a0e593815favboxsync Assert(pgmMapAreMappingsEnabled(&pPool->CTX_SUFF(pVM)->pgm.s));
121568d0a1e932e6f6acd49376827a0e593815favboxsync VM_FF_SET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3);
121568d0a1e932e6f6acd49376827a0e593815favboxsync LogFlow(("pgmPoolMonitorChainChanging: Detected conflict at iShw2=%#x!\n", iShw2));
121568d0a1e932e6f6acd49376827a0e593815favboxsync LogFlow(("pgmPoolMonitorChainChanging: pae pd iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPae->a[iShw2].u));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Hopefully this doesn't happen very often:
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * - messing with the bits of pd pointers without changing the physical address
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync if (!VM_FF_ISSET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3))
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync LogFlow(("pgmPoolMonitorChainChanging: pdpt iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPDPT->a[iShw].u));
c33fc49611f2444dade533488bf431e29eb88bcdvboxsync pgmPoolFree(pPool->CTX_SUFF(pVM), uShw.pPDPT->a[iShw].u & X86_PDPE_PG_MASK, pPage->idx, iShw);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /* paranoia / a bit assumptive. */
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PDPE);
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync LogFlow(("pgmPoolMonitorChainChanging: pdpt iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPDPT->a[iShw2].u));
1bf151411167b02ebdc6d6a18de8b97030341e1fvboxsync pgmPoolFree(pPool->CTX_SUFF(pVM), uShw.pPDPT->a[iShw2].u & X86_PDPE_PG_MASK, pPage->idx, iShw2);
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync * Hopefully this doesn't happen very often:
e2760cdc84c692bc46cfaf5018d313db2f122acavboxsync * - messing with the bits of pd pointers without changing the physical address
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!VM_FF_ISSET(pPool->CTX_SUFF(pVM), VM_FF_PGM_SYNC_CR3))
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync uShw.pv = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync LogFlow(("pgmPoolMonitorChainChanging: pml4 iShw=%#x: %RX64 -> freeing it!\n", iShw, uShw.pPML4->a[iShw].u));
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync pgmPoolFree(pPool->CTX_SUFF(pVM), uShw.pPML4->a[iShw].u & X86_PML4E_PG_MASK, pPage->idx, iShw);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync /* paranoia / a bit assumptive. */
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const unsigned iShw2 = (off + cbWrite - 1) / sizeof(X86PML4E);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync LogFlow(("pgmPoolMonitorChainChanging: pml4 iShw2=%#x: %RX64 -> freeing it!\n", iShw2, uShw.pPML4->a[iShw2].u));
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync pgmPoolFree(pPool->CTX_SUFF(pVM), uShw.pPML4->a[iShw2].u & X86_PML4E_PG_MASK, pPage->idx, iShw2);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync#endif /* IN_RING0 */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync AssertFatalMsgFailed(("enmKind=%d\n", pPage->enmKind));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Checks if a access could be a fork operation in progress.
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync * Meaning, that the guest is setuping up the parent process for Copy-On-Write.
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync * @returns true if it's likly that we're forking, otherwise false.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPool The pool.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param pCpu The disassembled instruction.
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync * @param offFault The access offset.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncDECLINLINE(bool) pgmPoolMonitorIsForking(PPGMPOOL pPool, PDISCPUSTATE pCpu, unsigned offFault)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * i386 linux is using btr to clear X86_PTE_RW.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * The functions involved are (2.6.16 source inspection):
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync * clear_bit
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * ptep_set_wrprotect
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync * copy_one_pte
49e54e2ffe0c10864d06e9d1ebe24a8eb1327a6bvboxsync * copy_pte_range
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * copy_pmd_range
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * copy_pud_range
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * copy_page_range
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync * copy_process
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /** @todo Validate that the bit index is X86_PTE_RW. */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,Fork));
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync return true;
91f8453d16b48876deddaba298c211071d0ca3a5vboxsync return false;
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Determine whether the page is likely to have been reused.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @returns true if we consider the page as being reused for a different purpose.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @returns false if we consider it to still be a paging page.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param pVM VM Handle.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pPage The page in question.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pRegFrame Trap register frame.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pCpu The disassembly info for the faulting instruction.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * @param pvFault The fault address.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @remark The REP prefix check is left to the caller because of STOSD/W.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsyncDECLINLINE(bool) pgmPoolMonitorIsReused(PVM pVM, PPGMPOOLPAGE pPage, PCPUMCTXCORE pRegFrame, PDISCPUSTATE pCpu, RTGCPTR pvFault)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync /** @todo could make this general, faulting close to rsp should be safe reuse heuristic. */
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync /* Fault caused by stack writes while trying to inject an interrupt event. */
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync Log(("pgmPoolMonitorIsReused: reused %RGv for interrupt stack (rsp=%RGv).\n", pvFault, pRegFrame->rsp));
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync return true;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync /* call implies the actual push of the return address faulted */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return true;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return true;
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync return true;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return true;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync return true;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return true;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync case OP_MOVNTDQ: /* solaris - hwblkclr & hwblkpagecopy */
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync return true;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return true;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync return false;
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync return true;
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync //if (pPage->fCR3Mix)
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync // return false;
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync return false;
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * Flushes the page being accessed.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @returns VBox status code suitable for scheduling.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @param pVM The VM handle.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @param pPool The pool.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @param pPage The pool page (head).
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @param pCpu The disassembly of the write instruction.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @param pRegFrame The trap register frame.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @param GCPhysFault The fault address as guest physical address.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync * @param pvFault The fault address.
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsyncstatic int pgmPoolAccessHandlerFlush(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pCpu,
4a0e2f51aaf27c0bca61ff0f1adb91106264f0dbvboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * First, do the flushing.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Emulate the instruction (xp/w2k problem, requires pc/cr2/sp detection).
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync int rc2 = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, pvFault, &cbWritten);
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync if (PATMIsPatchGCAddr(pVM, (RTRCPTR)pRegFrame->eip))
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("pgmPoolAccessHandlerPTWorker: Interpretation failed for patch code %04x:%RGv, ignoring.\n",
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync STAM_COUNTER_INC(&pPool->StatMonitorRZIntrFailPatch2);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,EmulateInstr));
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync /* See use in pgmPoolAccessHandlerSimple(). */
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync LogFlow(("pgmPoolAccessHandlerPT: returns %Rrc (flushed)\n", rc));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Handles the STOSD write accesses.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @returns VBox status code suitable for scheduling.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pVM The VM handle.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPool The pool.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPage The pool page (head).
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pCpu The disassembly of the write instruction.
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync * @param pRegFrame The trap register frame.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param GCPhysFault The fault address as guest physical address.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pvFault The fault address.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsyncDECLINLINE(int) pgmPoolAccessHandlerSTOSD(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pCpu,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Increment the modification counter and insert it into the list
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * of modified pages the first time.
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * Execute REP STOSD.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * This ASSUMES that we're not invoked by Trap0e on in a out-of-sync
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * write situation, meaning that it's safe to write here.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, (RTGCPTR)pu32, NULL);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync PGMPhysSimpleWriteGCPhys(pVM, GCPhysFault, &pRegFrame->eax, 4);
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync /* See use in pgmPoolAccessHandlerSimple(). */
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Handles the simple write accesses.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @returns VBox status code suitable for scheduling.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pVM The VM handle.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * @param pPool The pool.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pPage The pool page (head).
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pCpu The disassembly of the write instruction.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pRegFrame The trap register frame.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param GCPhysFault The fault address as guest physical address.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pvFault The fault address.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncDECLINLINE(int) pgmPoolAccessHandlerSimple(PVM pVM, PPGMPOOL pPool, PPGMPOOLPAGE pPage, PDISCPUSTATE pCpu,
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, RTGCPTR pvFault)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Increment the modification counter and insert it into the list
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * of modified pages the first time.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Clear all the pages. ASSUMES that pvFault is readable.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync uint32_t iPrevSubset = PGMDynMapPushAutoSubset(pVCpu);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, pvFault, pCpu);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pgmPoolMonitorChainChanging(pPool, pPage, GCPhysFault, pvFault, pCpu);
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync * Interpret the instruction.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync int rc = EMInterpretInstructionCPU(pVM, pCpu, pRegFrame, pvFault, &cb);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("pgmPoolAccessHandlerPTWorker: Interpretation failed for %04x:%RGv - opcode=%d\n",
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pRegFrame->cs, (RTGCPTR)pRegFrame->rip, pCpu->pCurInstr->opcode));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,EmulateInstr));
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync * Quick hack, with logging enabled we're getting stale
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * code TLBs but no data TLB for EIP and crash in EMInterpretDisasOne.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Flushing here is BAD and expensive, I think EMInterpretDisasOne will
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * have to be fixed to support this. But that'll have to wait till next week.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * An alternative is to keep track of the changed PTEs together with the
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * GCPhys from the guest PT. This may proove expensive though.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * At the moment, it's VITAL that it's done AFTER the instruction interpreting
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * because we need the stale TLBs in some cases (XP boot). This MUST be fixed properly!
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("pgmPoolAccessHandlerSimple: returns %Rrc cb=%d\n", rc, cb));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * \#PF Handler callback for PT write accesses.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @returns VBox status code (appropriate for GC return).
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pVM VM Handle.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param uErrorCode CPU Error code.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pRegFrame Trap register frame.
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync * NULL on DMA and other non CPU access.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pvFault The fault address (cr2).
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pvUser User argument.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncDECLEXPORT(int) pgmPoolAccessHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync STAM_PROFILE_START(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), a);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("pgmPoolAccessHandler: pvFault=%RGv pPage=%p:{.idx=%d} GCPhysFault=%RGp\n", pvFault, pPage, pPage->idx, GCPhysFault));
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * We should ALWAYS have the list head as user parameter. This
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * is because we use that page to record the changes.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Disassemble the faulting instruction.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync int rc = EMInterpretDisasOne(pVM, pRegFrame, &Cpu, NULL);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Check if it's worth dealing with.
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync bool fReused = false;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if ( ( pPage->cModifications < 48 /** @todo #define */ /** @todo need to check that it's not mapping EIP. */ /** @todo adjust this! */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync && !(fReused = pgmPoolMonitorIsReused(pVM, pPage, pRegFrame, &Cpu, pvFault))
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync && !pgmPoolMonitorIsForking(pPool, &Cpu, GCPhysFault & PAGE_OFFSET_MASK))
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Simple instructions, no REP prefix.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync rc = pgmPoolAccessHandlerSimple(pVM, pPool, pPage, &Cpu, pRegFrame, GCPhysFault, pvFault);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,Handled), a);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Windows is frequently doing small memset() operations (netio test 4k+).
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync * We have to deal with these or we'll kill the cache and performance.
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync && pRegFrame->ecx * 4 <= PAGE_SIZE - ((uintptr_t)pvFault & PAGE_OFFSET_MASK)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync && (pRegFrame->eax == 0 || pRegFrame->eax == 0x80) /* the two values observed. */
d107911787df36a78788a841b73d24da896d02f6vboxsync rc = pgmPoolAccessHandlerSTOSD(pVM, pPool, pPage, &Cpu, pRegFrame, GCPhysFault, pvFault);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,RepStosd), a);
2a5e5a032e6f23f8937718e4ee4d6979188bdd19vboxsync /* REP prefix, don't bother. */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync STAM_COUNTER_INC(&pPool->CTX_MID_Z(StatMonitor,RepPrefix));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Log4(("pgmPoolAccessHandler: eax=%#x ecx=%#x edi=%#x esi=%#x rip=%RGv opcode=%d prefix=%#x\n",
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pRegFrame->eax, pRegFrame->ecx, pRegFrame->edi, pRegFrame->esi, (RTGCPTR)pRegFrame->rip, Cpu.pCurInstr->opcode, Cpu.prefix));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Not worth it, so flush it.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * If we considered it to be reused, don't to back to ring-3
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * to emulate failed instructions since we usually cannot
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * interpret then. This may be a bit risky, in which case
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * the reuse detection must be fixed.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync rc = pgmPoolAccessHandlerFlush(pVM, pPool, pPage, &Cpu, pRegFrame, GCPhysFault, pvFault);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync STAM_PROFILE_STOP_EX(&pVM->pgm.s.CTX_SUFF(pPool)->CTX_SUFF_Z(StatMonitor), &pPool->CTX_MID_Z(StatMonitor,FlushPage), a);
1871985cb4854e5bfb2ead8174ee28dbfce74df5vboxsync# endif /* !IN_RING3 */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync#endif /* PGMPOOL_WITH_MONITORING */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Inserts a page into the GCPhys hash table.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPool The pool.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pPage The page.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncDECLINLINE(void) pgmPoolHashInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync Log3(("pgmPoolHashInsert: %RGp\n", pPage->GCPhys));
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync Assert(pPage->GCPhys != NIL_RTGCPHYS); Assert(pPage->iNext == NIL_PGMPOOL_IDX);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Removes a page from the GCPhys hash table.
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync * @param pPool The pool.
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsync * @param pPage The page.
a9f530691071e3496b072915b0c5ceabd4e05ea5vboxsyncDECLINLINE(void) pgmPoolHashRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
b7a8ce033b32a429def2feb142bc1bdd1b5dffa2vboxsync Log3(("pgmPoolHashRemove: %RGp\n", pPage->GCPhys));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync AssertReleaseMsgFailed(("GCPhys=%RGp idx=%#x\n", pPage->GCPhys, pPage->idx));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Frees up one cache page.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * @returns VBox status code.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @retval VINF_SUCCESS on success.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @retval VERR_PGM_POOL_CLEARED if the deregistration of a physical handler will cause a light weight pool flush.
261b44f7fa60a1d4bb4102142d3aa44188908484vboxsync * @param pPool The pool.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param iUser The user index.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncstatic int pgmPoolCacheFreeOne(PPGMPOOL pPool, uint16_t iUser)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync Assert(pPool->iAgeHead != pPool->iAgeTail); /* We shouldn't be here if there < 2 cached entries! */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Select one page from the tail of the age list.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync/* This is the alternative to the SyncCR3 pgmPoolCacheUsed calls.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (pPool->aPages[iToFree].iUserHead != NIL_PGMPOOL_USER_INDEX)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync uint16_t i = pPool->aPages[iToFree].iAgePrev;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync for (unsigned j = 0; j < 10 && i != NIL_PGMPOOL_USER_INDEX; j++, i = pPool->aPages[i].iAgePrev)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (pPool->aPages[iToFree].iUserHead == NIL_PGMPOOL_USER_INDEX)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync iToFree = i;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Reject any attempts at flushing the currently active shadow CR3 mapping
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (PGMGetHyperCR3(pPool->CTX_SUFF(pVM)) == pPage->Core.Key)
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync /* Refresh the cr3 mapping by putting it at the head of the age list. */
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Checks if a kind mismatch is really a page being reused
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * or if it's just normal remappings.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @returns true if reused and the cached page (enmKind1) should be flushed
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @returns false if not reused.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * @param enmKind1 The kind of the cached page.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param enmKind2 The kind of the requested page.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsyncstatic bool pgmPoolCacheReusedByKind(PGMPOOLKIND enmKind1, PGMPOOLKIND enmKind2)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Never reuse them. There is no remapping in non-paging mode.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync return true;
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync return true;
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync return false;
f62342e2cc901a67e27fa69c0e712ee35e9c4c68vboxsync * It's perfectly fine to reuse these, except for PAE and non-paging stuff.
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync return true;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync return false;
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync * These cannot be flushed, and it's common to reuse the PDs as PTs.
b604fbf16eda38d14b4999c245f032bfaa5aa85avboxsync return false;
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * Attempts to satisfy a pgmPoolAlloc request from the cache.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @returns VBox status code.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @retval VINF_PGM_CACHED_PAGE on success.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @retval VERR_FILE_NOT_FOUND if not found.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @param pPool The pool.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @param GCPhys The GC physical address of the page we're gonna shadow.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @param enmKind The kind of mapping.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @param iUser The shadow page pool index of the user table.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @param iUserTable The index into the user table (shadowed).
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * @param ppPage Where to store the pointer to the page.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsyncstatic int pgmPoolCacheAlloc(PPGMPOOL pPool, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, uint16_t iUser, uint32_t iUserTable, PPPGMPOOLPAGE ppPage)
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync * Look up the GCPhys in the hash.
13d1fd6f43e9a245a4f2b4fc6845bdaa5d0f4134vboxsync Log3(("pgmPoolCacheAlloc: %RGp kind %d iUser=%d iUserTable=%x SLOT=%d\n", GCPhys, enmKind, iUser, iUserTable, i));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync Log3(("pgmPoolCacheAlloc: slot %d found page %RGp\n", i, pPage->GCPhys));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync int rc = pgmPoolTrackAddUser(pPool, pPage, iUser, iUserTable);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * The kind is different. In some cases we should now flush the page
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * as it has been reused, but in most cases this is normal remapping
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * of PDs as PT or big pages using the GCPhys field in a slightly
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * different way than the other kinds.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync if (pgmPoolCacheReusedByKind((PGMPOOLKIND)pPage->enmKind, enmKind))
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pgmPoolFlushPage(pPool, pPage); /* ASSUMES that VERR_PGM_POOL_CLEARED will be returned by pgmPoolTracInsert. */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync } while (i != NIL_PGMPOOL_IDX);
8c58249d7f93d82395aa6c8b31526443892bc375vboxsync Log3(("pgmPoolCacheAlloc: Missed GCPhys=%RGp enmKind=%d\n", GCPhys, enmKind));
6c1f3eb64096421b9ba7272f297bac6ff3d29fe7vboxsync * Inserts a page into the cache.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pPool The pool.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPage The cached page.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param fCanBeCached Set if the page is fit for caching from the caller's point of view.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsyncstatic void pgmPoolCacheInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, bool fCanBeCached)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Insert into the GCPhys hash if the page is fit for that.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Log3(("pgmPoolCacheInsert: Caching %p:{.Core=%RHp, .idx=%d, .enmKind=%d, GCPhys=%RGp}\n",
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync pPage, pPage->Core.Key, pPage->idx, pPage->enmKind, pPage->GCPhys));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Log3(("pgmPoolCacheInsert: Not caching %p:{.Core=%RHp, .idx=%d, .enmKind=%d, GCPhys=%RGp}\n",
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pPage, pPage->Core.Key, pPage->idx, pPage->enmKind, pPage->GCPhys));
9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bffvboxsync * Insert at the head of the age list.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pPool->aPages[pPool->iAgeHead].iAgePrev = pPage->idx;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Flushes a cached page.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPool The pool.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pPage The cached page.
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsyncstatic void pgmPoolCacheFlushPage(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Log3(("pgmPoolCacheFlushPage: %RGp\n", pPage->GCPhys));
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Remove the page from the hash.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * Remove it from the age list.
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsync pPool->aPages[pPage->iAgeNext].iAgePrev = pPage->iAgePrev;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync pPool->aPages[pPage->iAgePrev].iAgeNext = pPage->iAgeNext;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync#endif /* PGMPOOL_WITH_CACHE */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Looks for pages sharing the monitor.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @returns Pointer to the head page.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @returns NULL if not found.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param pPool The Pool
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @param pNewPage The page which is going to be monitored.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsyncstatic PPGMPOOLPAGE pgmPoolMonitorGetPageByGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pNewPage)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Look up the GCPhys in the hash.
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync RTGCPHYS GCPhys = pNewPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1);
fa80a38f04b00afbb167e46c385cf24df0e223ddvboxsync /* find the head */
fa80a38f04b00afbb167e46c385cf24df0e223ddvboxsync /* ignore, no monitoring. */
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync AssertFatalMsgFailed(("enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync } while (i != NIL_PGMPOOL_IDX);
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync * Enabled write monitoring of a guest page.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync * @returns VBox status code.
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * @retval VINF_SUCCESS on success.
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * @retval VERR_PGM_POOL_CLEARED if the registration of the physical handler will cause a light weight pool flush.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync * @param pPool The pool.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync * @param pPage The cached page.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsyncstatic int pgmPoolMonitorInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync LogFlow(("pgmPoolMonitorInsert %RGp\n", pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1)));
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * Filter out the relevant kinds.
cb2880968807a37c9efe6d5d32d56f2def91d908vboxsync /* Nothing to monitor here. */
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * Install handler.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync PPGMPOOLPAGE pPageHead = pgmPoolMonitorGetPageByGCPhys(pPool, pPage);
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync Assert(pPageHead != pPage); Assert(pPageHead->iMonitoredNext != pPage->idx);
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync pPool->aPages[pPageHead->iMonitoredNext].iMonitoredPrev = pPage->idx;
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync Assert(pPage->iMonitoredNext == NIL_PGMPOOL_IDX); Assert(pPage->iMonitoredPrev == NIL_PGMPOOL_IDX);
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync const RTGCPHYS GCPhysPage = pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1);
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync rc = PGMHandlerPhysicalRegisterEx(pVM, PGMPHYSHANDLERTYPE_PHYSICAL_WRITE,
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pPage),
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pPage),
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync pPool->pfnAccessHandlerRC, MMHyperCCToRC(pVM, pPage),
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync /** @todo we should probably deal with out-of-memory conditions here, but for now increasing
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * the heap size should suffice. */
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync if (pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync * Disables write monitoring of a guest page.
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync * @returns VBox status code.
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync * @retval VINF_SUCCESS on success.
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync * @retval VERR_PGM_POOL_CLEARED if the deregistration of the physical handler will cause a light weight pool flush.
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync * @param pPool The pool.
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsync * @param pPage The cached page.
62a515eec8de1b7804ec6997c0f2013fef5c5a6bvboxsyncstatic int pgmPoolMonitorFlush(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * Filter out the relevant kinds.
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync /* Nothing to monitor here. */
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync AssertFatalMsgFailed(("This can't happen! enmKind=%d\n", pPage->enmKind));
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * Remove the page from the monitored list or uninstall it if last.
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync PPGMPOOLPAGE pNewHead = &pPool->aPages[pPage->iMonitoredNext];
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync rc = PGMHandlerPhysicalChangeCallbacks(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1),
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync pPool->pfnAccessHandlerR3, MMHyperCCToR3(pVM, pNewHead),
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync pPool->pfnAccessHandlerR0, MMHyperCCToR0(pVM, pNewHead),
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync pPool->pfnAccessHandlerRC, MMHyperCCToRC(pVM, pNewHead),
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync pPool->aPages[pPage->iMonitoredPrev].iMonitoredNext = pPage->iMonitoredNext;
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync pPool->aPages[pPage->iMonitoredNext].iMonitoredPrev = pPage->iMonitoredPrev;
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync rc = PGMHandlerPhysicalDeregister(pVM, pPage->GCPhys & ~(RTGCPHYS)(PAGE_SIZE - 1));
cebc93936b5bb4d867e1c086dd1b206db33c31dcvboxsync if (pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Remove it from the list of modified pages (if in it).
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Set or clear the fCR3Mix attribute in a chain of monitored pages.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param pPool The Pool.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pPage A page in the chain.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * @param fCR3Mix The new fCR3Mix value.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsyncstatic void pgmPoolMonitorChainChangeCR3Mix(PPGMPOOL pPool, PPGMPOOLPAGE pPage, bool fCR3Mix)
19cb1f8699e352d590c4946caee33863a5157241vboxsync /* current */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync /* before */
45e0b20bd50b7124efbbe1cdb1c65d67eb41498avboxsync /* after */
a85c47589af3385deccdbb1367b75108806d7cf5vboxsync * Installs or modifies monitoring of a CR3 page (special).
a85c47589af3385deccdbb1367b75108806d7cf5vboxsync * We're pretending the CR3 page is shadowed by the pool so we can use the
19cb1f8699e352d590c4946caee33863a5157241vboxsync * generic mechanisms in detecting chained monitoring. (This also gives us a
19cb1f8699e352d590c4946caee33863a5157241vboxsync * tast of what code changes are required to really pool CR3 shadow pages.)
19cb1f8699e352d590c4946caee33863a5157241vboxsync * @returns VBox status code.
19cb1f8699e352d590c4946caee33863a5157241vboxsync * @param pPool The pool.
45e0b20bd50b7124efbbe1cdb1c65d67eb41498avboxsync * @param idxRoot The CR3 (root) page index.
45e0b20bd50b7124efbbe1cdb1c65d67eb41498avboxsync * @param GCPhysCR3 The (new) CR3 value.
bdb01608062958ff140a733533f3d6574886c831vboxsyncint pgmPoolMonitorMonitorCR3(PPGMPOOL pPool, uint16_t idxRoot, RTGCPHYS GCPhysCR3)
bdb01608062958ff140a733533f3d6574886c831vboxsync Assert(idxRoot != NIL_PGMPOOL_IDX && idxRoot < PGMPOOL_IDX_FIRST);
45e0b20bd50b7124efbbe1cdb1c65d67eb41498avboxsync LogFlow(("pgmPoolMonitorMonitorCR3: idxRoot=%d pPage=%p:{.GCPhys=%RGp, .fMonitored=%d} GCPhysCR3=%RGp\n",
bdb01608062958ff140a733533f3d6574886c831vboxsync idxRoot, pPage, pPage->GCPhys, pPage->fMonitored, GCPhysCR3));
45e0b20bd50b7124efbbe1cdb1c65d67eb41498avboxsync * The unlikely case where it already matches.
19cb1f8699e352d590c4946caee33863a5157241vboxsync * Flush the current monitoring and remove it from the hash.
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync pgmPoolMonitorChainChangeCR3Mix(pPool, pPage, false);
45e0b20bd50b7124efbbe1cdb1c65d67eb41498avboxsync * Monitor the page at the new location and insert it into the hash.
45e0b20bd50b7124efbbe1cdb1c65d67eb41498avboxsync pgmPoolMonitorChainChangeCR3Mix(pPool, pPage, true);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Removes the monitoring of a CR3 page (special).
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @returns VBox status code.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * @param pPool The pool.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param idxRoot The CR3 (root) page index.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsyncint pgmPoolMonitorUnmonitorCR3(PPGMPOOL pPool, uint16_t idxRoot)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync Assert(idxRoot != NIL_PGMPOOL_IDX && idxRoot < PGMPOOL_IDX_FIRST);
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync LogFlow(("pgmPoolMonitorUnmonitorCR3: idxRoot=%d pPage=%p:{.GCPhys=%RGp, .fMonitored=%d}\n",
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync idxRoot, pPage, pPage->GCPhys, pPage->fMonitored));
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync pgmPoolMonitorChainChangeCR3Mix(pPool, pPage, false);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync# endif /* PGMPOOL_WITH_MIXED_PT_CR3 */
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Inserts the page into the list of modified pages.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPool The pool.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pPage The page.
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsyncvoid pgmPoolMonitorModifiedInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync Log3(("pgmPoolMonitorModifiedInsert: idx=%d\n", pPage->idx));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync ("Next=%d Prev=%d idx=%d cModifications=%d Head=%d cModifiedPages=%d\n",
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pPage->iModifiedNext, pPage->iModifiedPrev, pPage->idx, pPage->cModifications,
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync pPool->aPages[pPool->iModifiedHead].iModifiedPrev = pPage->idx;
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync if (pPool->cModifiedPages > pPool->cModifiedPagesHigh)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Removes the page from the list of modified pages and resets the
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * moficiation counter.
2823fbb1428e982169f04923472d7c94e7ed8385vboxsync * @param pPool The pool.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param pPage The page which is believed to be in the list of modified pages.
2823fbb1428e982169f04923472d7c94e7ed8385vboxsyncstatic void pgmPoolMonitorModifiedRemove(PPGMPOOL pPool, PPGMPOOLPAGE pPage)
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync Log3(("pgmPoolMonitorModifiedRemove: idx=%d cModifications=%d\n", pPage->idx, pPage->cModifications));
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync pPool->aPages[pPage->iModifiedNext].iModifiedPrev = NIL_PGMPOOL_IDX;
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync pPool->aPages[pPage->iModifiedPrev].iModifiedNext = pPage->iModifiedNext;
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync pPool->aPages[pPage->iModifiedNext].iModifiedPrev = pPage->iModifiedPrev;
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync * Zaps the list of modified pages, resetting their modification counters in the process.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * @param pVM The VM handle.
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync LogFlow(("pgmPoolMonitorModifiedClearAll: cModifiedPages=%d\n", pPool->cModifiedPages));
67ee25dd0b63a61dc35a35d0aade75ca6cd06350vboxsync AssertMsg(cPages == pPool->cModifiedPages, ("%d != %d\n", cPages, pPool->cModifiedPages));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Clear all shadow pages and clear all modification counters.
6efcf94383d6e48c764c6518cf1b4069ad34e210vboxsync * @param pVM The VM handle.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @remark Should only be used when monitoring is available, thus placed in
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * the PGMPOOL_WITH_MONITORING #ifdef.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync LogFlow(("pgmPoolClearAll: cUsedPages=%d\n", pPool->cUsedPages));
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * Iterate all the pages until we've encountered all that in use.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync * This is simple but not quite optimal solution.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync unsigned cModifiedPages = 0; NOREF(cModifiedPages);
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * We only care about shadow page tables.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync void *pvShw = PGMPOOL_PAGE_2_PTR(pPool->CTX_SUFF(pVM), pPage);
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync /* fall thru */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Assert(!pPage->cModifications || ++cModifiedPages);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Assert(pPage->iModifiedNext == NIL_PGMPOOL_IDX || pPage->cModifications);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX || pPage->cModifications);
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync /* swipe the special pages too. */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync for (iPage = PGMPOOL_IDX_FIRST_SPECIAL; iPage < PGMPOOL_IDX_FIRST; iPage++)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync Assert(!pPage->cModifications || ++cModifiedPages);
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync Assert(pPage->iModifiedNext == NIL_PGMPOOL_IDX || pPage->cModifications);
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync Assert(pPage->iModifiedPrev == NIL_PGMPOOL_IDX || pPage->cModifications);
a0644dbbd30adb9bd2937110d6f016e56c4cc52bvboxsync AssertMsg(cModifiedPages == pPool->cModifiedPages, ("%d != %d\n", cModifiedPages, pPool->cModifiedPages));
a0644dbbd30adb9bd2937110d6f016e56c4cc52bvboxsync * Clear all the GCPhys links and rebuild the phys ext free list.
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync for (PPGMRAMRANGE pRam = pPool->CTX_SUFF(pVM)->pgm.s.CTX_SUFF(pRamRanges);
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync while (iPage-- > 0)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync pRam->aPages[iPage].HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
ccf574508b96ea0f7dc62b4048f6156c1df160cdvboxsync PPGMPOOLPHYSEXT paPhysExts = pPool->CTX_SUFF(paPhysExts);
ccf574508b96ea0f7dc62b4048f6156c1df160cdvboxsync for (unsigned i = 0; i < cMaxPhysExts; i++)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync paPhysExts[cMaxPhysExts - 1].iNext = NIL_PGMPOOL_PHYSEXT_INDEX;
6fe1329154975472e055284198df7fa8e64dee3avboxsync#endif /* IN_RING3 */
6fe1329154975472e055284198df7fa8e64dee3avboxsync * Handle SyncCR3 pool tasks
6fe1329154975472e055284198df7fa8e64dee3avboxsync * @returns VBox status code.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * @retval VINF_SUCCESS if successfully added.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * @retval VINF_PGM_SYNC_CR3 is it needs to be deferred to ring 3 (GC only)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * @param pVM The VM handle.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * @remark Should only be used when monitoring is available, thus placed in
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * the PGMPOOL_WITH_MONITORING #ifdef.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * When monitoring shadowed pages, we reset the modification counters on CR3 sync.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Occasionally we will have to clear all the shadow page tables because we wanted
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * to monitor a page which was mapped by too many shadowed page tables. This operation
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * sometimes refered to as a 'lightweight flush'.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync if (!(pVM->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL))
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync# ifdef IN_RING3 /* Don't flush in ring-0 or raw mode, it's taking too long. */
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync# else /* !IN_RING3 */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync LogFlow(("SyncCR3: PGM_SYNC_CLEAR_PGM_POOL is set -> VINF_PGM_SYNC_CR3\n"));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync VM_FF_SET(pVM, VM_FF_PGM_SYNC_CR3); /** @todo no need to do global sync, right? */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync# endif /* !IN_RING3 */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* PGMPOOL_WITH_MONITORING */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Frees up at least one user entry.
fc60d7c6501c5e676e41b11c042d4358d9faa81dvboxsync * @returns VBox status code.
fc60d7c6501c5e676e41b11c042d4358d9faa81dvboxsync * @retval VINF_SUCCESS if successfully added.
fc60d7c6501c5e676e41b11c042d4358d9faa81dvboxsync * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
fc60d7c6501c5e676e41b11c042d4358d9faa81dvboxsync * @param pPool The pool.
fc60d7c6501c5e676e41b11c042d4358d9faa81dvboxsync * @param iUser The user index.
fc60d7c6501c5e676e41b11c042d4358d9faa81dvboxsyncstatic int pgmPoolTrackFreeOneUser(PPGMPOOL pPool, uint16_t iUser)
fc60d7c6501c5e676e41b11c042d4358d9faa81dvboxsync * Just free cached pages in a braindead fashion.
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsync /** @todo walk the age list backwards and free the first with usage. */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync } while (pPool->iUserFreeHead == NIL_PGMPOOL_USER_INDEX);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Lazy approach.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync /* @todo incompatible with long mode paging (cr3 root will be flushed) */
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Inserts a page into the cache.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * This will create user node for the page, insert it into the GCPhys
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * hash, and insert it into the age list.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @returns VBox status code.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @retval VINF_SUCCESS if successfully added.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
cc74f15083bf80fbc96723a89faa06c15d0dead8vboxsync * @retval VERR_PGM_POOL_CLEARED if the deregistration of the physical handler will cause a light weight pool flush.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pPool The pool.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pPage The cached page.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param GCPhys The GC physical address of the page we're gonna shadow.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param iUser The user index.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param iUserTable The user table index.
3933885bc0c2c93436d858a14564c6179ec72872vboxsyncDECLINLINE(int) pgmPoolTrackInsert(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTGCPHYS GCPhys, uint16_t iUser, uint32_t iUserTable)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync LogFlow(("pgmPoolTrackInsert iUser %d iUserTable %d\n", iUser, iUserTable));
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Find free a user node.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Unlink the user node from the free list,
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * initialize and insert it into the user list.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Insert into cache and enable monitoring of the guest page if enabled.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * Until we implement caching of all levels, including the CR3 one, we'll
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * have to make sure we don't try monitor & cache any recursive reuse of
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * a monitored CR3 page. Because all windows versions are doing this we'll
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * have to be able to do combined access monitoring, CR3 + PT and
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * PD + PT (guest PAE).
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * We're now cooperating with the CR3 monitor if an uncachable page is found.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync#if defined(PGMPOOL_WITH_MONITORING) || defined(PGMPOOL_WITH_CACHE)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync const bool fCanBeMonitored = true;
8b36957d815c23b479eb35d93ac76c66392e9402vboxsync bool fCanBeMonitored = pPool->CTX_SUFF(pVM)->pgm.s.GCPhysGstCR3Monitored == NIL_RTGCPHYS
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync || (GCPhys & X86_PTE_PAE_PG_MASK) != (pPool->CTX_SUFF(pVM)->pgm.s.GCPhysGstCR3Monitored & X86_PTE_PAE_PG_MASK)
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync pgmPoolCacheInsert(pPool, pPage, fCanBeMonitored); /* This can be expanded. */
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync /* 'Failed' - free the usage, and keep it in the cache (if enabled). */
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync#endif /* PGMPOOL_WITH_MONITORING */
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync# ifdef PGMPOOL_WITH_CACHE /* (only used when the cache is enabled.) */
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync * Adds a user reference to a page.
56349fc0a23f96f82208016f8f59f8377bb284b1vboxsync * This will
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync * This will move the page to the head of the
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync * @returns VBox status code.
6e25221ce8ef8e656d1e15eb7ec5cf8ae758ceb2vboxsync * @retval VINF_SUCCESS if successfully added.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @retval VERR_PGM_POOL_FLUSHED if the pool was flushed.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pPool The pool.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pPage The cached page.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * @param iUser The user index.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param iUserTable The user table.
3933885bc0c2c93436d858a14564c6179ec72872vboxsyncstatic int pgmPoolTrackAddUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("pgmPoolTrackAddUser iUser %d iUserTable %d\n", iUser, iUserTable));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Check that the entry doesn't already exists.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync AssertMsg(paUsers[i].iUser != iUser || paUsers[i].iUserTable != iUserTable, ("%x %x vs new %x %x\n", paUsers[i].iUser, paUsers[i].iUserTable, iUser, iUserTable));
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Allocate a user node.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Initialize the user node and insert it.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Tell the cache to update its replacement stats for this page.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync# endif /* PGMPOOL_WITH_CACHE */
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * Frees a user record associated with a page.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * This does not clear the entry in the user table, it simply replaces the
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * user record to the chain of free records.
7a7a4fb86f66f7ab919948a2ad6aae0483061e18vboxsync * @param pPool The pool.
d29ab0cfbeef254251f0a2458163034999abb8a0vboxsync * @param HCPhys The HC physical address of the shadow page.
bdb01608062958ff140a733533f3d6574886c831vboxsync * @param iUser The shadow page pool index of the user table.
bdb01608062958ff140a733533f3d6574886c831vboxsync * @param iUserTable The index into the user table (shadowed).
bdb01608062958ff140a733533f3d6574886c831vboxsyncstatic void pgmPoolTrackFreeUser(PPGMPOOL pPool, PPGMPOOLPAGE pPage, uint16_t iUser, uint32_t iUserTable)
bdb01608062958ff140a733533f3d6574886c831vboxsync * Unlink and free the specified user entry.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* Special: For PAE and 32-bit paging, there is usually no more than one user. */
bdb01608062958ff140a733533f3d6574886c831vboxsync /* General: Linear search. */
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync /* Fatal: didn't find it */
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync AssertFatalMsgFailed(("Didn't find the user entry! iUser=%#x iUserTable=%#x GCPhys=%RGp\n",
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * Gets the entry size of a shadow table.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param enmKind The kind of page.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @returns The size of the entry in bytes. That is, 4 or 8.
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * @returns If the kind is not for a table, an assertion is raised and 0 is
9e4ea89b1085fdaa5861e45a729d9c978db1a8f1vboxsync * returned.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsyncDECLINLINE(unsigned) pgmPoolTrackGetShadowEntrySize(PGMPOOLKIND enmKind)
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * Gets the entry size of a guest table.
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * @param enmKind The kind of page.
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * @returns The size of the entry in bytes. That is, 0, 4 or 8.
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * @returns If the kind is not for a table, an assertion is raised and 0 is
40dce69ff1c2949a489337922f30f1021d62d864vboxsync * returned.
40dce69ff1c2949a489337922f30f1021d62d864vboxsyncDECLINLINE(unsigned) pgmPoolTrackGetGuestEntrySize(PGMPOOLKIND enmKind)
40dce69ff1c2949a489337922f30f1021d62d864vboxsync /** @todo can we return 0? (nobody is calling this...) */
dbabc9de5bf52ce5eb77cf82b038e9a6166c5a04vboxsync * Scans one shadow page table for mappings of a physical page.
4090390866c02d5d0ad061151cdb298b9a173e86vboxsync * @param pVM The VM handle.
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync * @param pPhysPage The guest page in question.
4090390866c02d5d0ad061151cdb298b9a173e86vboxsync * @param iShw The shadow page table.
4090390866c02d5d0ad061151cdb298b9a173e86vboxsync * @param cRefs The number of references made in that PT.
4090390866c02d5d0ad061151cdb298b9a173e86vboxsyncstatic void pgmPoolTrackFlushGCPhysPTInt(PVM pVM, PCPGMPAGE pPhysPage, uint16_t iShw, uint16_t cRefs)
1cd59fdf671ca60c64d77e3f7046aaecf7003824vboxsync LogFlow(("pgmPoolTrackFlushGCPhysPT: HCPhys=%RHp iShw=%d cRefs=%d\n", pPhysPage->HCPhys, iShw, cRefs));
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync * Assert sanity.
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync AssertFatalMsg(iShw < pPool->cCurPages && iShw != NIL_PGMPOOL_IDX, ("iShw=%d\n", iShw));
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync * Then, clear the actual mappings to the page in the shadow PT.
e4efe3adcccfda0bcbd5a1f7f9644ce6c323c6f4vboxsync const uint32_t u32 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync PX86PT pPT = (PX86PT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX32 cRefs=%#x\n", i, pPT->a[i], cRefs));
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync pPT->a[i].u = 0;
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync if ((pPT->a[i].u & (X86_PTE_PG_MASK | X86_PTE_P)) == u32)
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync pPT->a[i].u = 0;
48890ac9b4b339e0341e826b5c26ce6408729987vboxsync AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent));
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
6f1ce0274d766b4a37d6bede42ed83d42edbbe92vboxsync PX86PTPAE pPT = (PX86PTPAE)PGMPOOL_PAGE_2_PTR(pVM, pPage);
6f1ce0274d766b4a37d6bede42ed83d42edbbe92vboxsync for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
6f1ce0274d766b4a37d6bede42ed83d42edbbe92vboxsync if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
6f1ce0274d766b4a37d6bede42ed83d42edbbe92vboxsync Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX64 cRefs=%#x\n", i, pPT->a[i], cRefs));
6f1ce0274d766b4a37d6bede42ed83d42edbbe92vboxsync pPT->a[i].u = 0;
6f1ce0274d766b4a37d6bede42ed83d42edbbe92vboxsync RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
6f1ce0274d766b4a37d6bede42ed83d42edbbe92vboxsync if ((pPT->a[i].u & (X86_PTE_PAE_PG_MASK | X86_PTE_P)) == u64)
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync pPT->a[i].u = 0;
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d u64=%RX64\n", cRefs, pPage->iFirstPresent, pPage->cPresent, u64));
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync PEPTPT pPT = (PEPTPT)PGMPOOL_PAGE_2_PTR(pVM, pPage);
5d57bcb78f1f3f918bd3daf709b551b8c2d30485vboxsync for (unsigned i = pPage->iFirstPresent; i < RT_ELEMENTS(pPT->a); i++)
5d57bcb78f1f3f918bd3daf709b551b8c2d30485vboxsync if ((pPT->a[i].u & (EPT_PTE_PG_MASK | X86_PTE_P)) == u64)
5d57bcb78f1f3f918bd3daf709b551b8c2d30485vboxsync Log4(("pgmPoolTrackFlushGCPhysPTs: i=%d pte=%RX64 cRefs=%#x\n", i, pPT->a[i], cRefs));
5d57bcb78f1f3f918bd3daf709b551b8c2d30485vboxsync pPT->a[i].u = 0;
3f00104a87d8a725dfa0348b69cbdac901062a4avboxsync RTLogPrintf("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent);
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync if ((pPT->a[i].u & (EPT_PTE_PG_MASK | X86_PTE_P)) == u64)
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync pPT->a[i].u = 0;
8c859f9b5248b011cfe07153154fe77ff69d67cevboxsync AssertFatalMsgFailed(("cRefs=%d iFirstPresent=%d cPresent=%d\n", cRefs, pPage->iFirstPresent, pPage->cPresent));
8c859f9b5248b011cfe07153154fe77ff69d67cevboxsync AssertFatalMsgFailed(("enmKind=%d iShw=%d\n", pPage->enmKind, iShw));
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync * Scans one shadow page table for mappings of a physical page.
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync * @param pVM The VM handle.
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync * @param pPhysPage The guest page in question.
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync * @param iShw The shadow page table.
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync * @param cRefs The number of references made in that PT.
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsyncvoid pgmPoolTrackFlushGCPhysPT(PVM pVM, PPGMPAGE pPhysPage, uint16_t iShw, uint16_t cRefs)
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync PPGMPOOL pPool = pVM->pgm.s.CTX_SUFF(pPool); NOREF(pPool);
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync LogFlow(("pgmPoolTrackFlushGCPhysPT: HCPhys=%RHp iShw=%d cRefs=%d\n", pPhysPage->HCPhys, iShw, cRefs));
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPT, f);
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, iShw, cRefs);
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync pPhysPage->HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
45a01ef53b009e9f56ce427bd8688da02ad32389vboxsync STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPT, f);
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync * Flushes a list of shadow page tables mapping the same physical page.
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync * @param pVM The VM handle.
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync * @param pPhysPage The guest page in question.
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync * @param iPhysExt The physical cross reference extent list to flush.
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsyncvoid pgmPoolTrackFlushGCPhysPTs(PVM pVM, PPGMPAGE pPhysPage, uint16_t iPhysExt)
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTs, f);
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync LogFlow(("pgmPoolTrackFlushGCPhysPTs: HCPhys=%RHp iPhysExt\n", pPhysPage->HCPhys, iPhysExt));
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync for (unsigned i = 0; i < RT_ELEMENTS(pPhysExt->aidx); i++)
7a29aa5ce149ccd344a2929d2815b8e212690b92vboxsync pgmPoolTrackFlushGCPhysPTInt(pVM, pPhysPage, pPhysExt->aidx[i], 1);
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync /* insert the list into the free list and clear the ram range entry. */
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync pPhysPage->HCPhys &= MM_RAM_FLAGS_NO_REFS_MASK; /** @todo PAGE FLAGS */
a1b4fb3917412d2632d358ff8989f1ec971f2d5bvboxsync STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTs, f);
5a41049c24bcf93e3dc63c76bee23db645867e0cvboxsync#endif /* PGMPOOL_WITH_GCPHYS_TRACKING */
62ab017295981c81484e5a5f93ff8b5f85f7defbvboxsync * Scans all shadow page tables for mappings of a physical page.
62ab017295981c81484e5a5f93ff8b5f85f7defbvboxsync * This may be slow, but it's most likely more efficient than cleaning
5a41049c24bcf93e3dc63c76bee23db645867e0cvboxsync * out the entire page pool / cache.
7708252d252a55417a6a817041e4356797e34255vboxsync * @returns VBox status code.
7708252d252a55417a6a817041e4356797e34255vboxsync * @retval VINF_SUCCESS if all references has been successfully cleared.
7708252d252a55417a6a817041e4356797e34255vboxsync * @retval VINF_PGM_GCPHYS_ALIASED if we're better off with a CR3 sync and
7708252d252a55417a6a817041e4356797e34255vboxsync * a page pool cleaning.
7708252d252a55417a6a817041e4356797e34255vboxsync * @param pVM The VM handle.
7708252d252a55417a6a817041e4356797e34255vboxsync * @param pPhysPage The guest page in question.
904810c4c6668233349b025cc58013cb7c11c701vboxsyncint pgmPoolTrackFlushGCPhysPTsSlow(PVM pVM, PPGMPAGE pPhysPage)
904810c4c6668233349b025cc58013cb7c11c701vboxsync STAM_PROFILE_START(&pPool->StatTrackFlushGCPhysPTsSlow, s);
904810c4c6668233349b025cc58013cb7c11c701vboxsync LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: cUsedPages=%d cPresent=%d HCPhys=%RHp\n",
904810c4c6668233349b025cc58013cb7c11c701vboxsync pPool->cUsedPages, pPool->cPresent, pPhysPage->HCPhys));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync * There is a limit to what makes sense.
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync LogFlow(("pgmPoolTrackFlushGCPhysPTsSlow: giving up... (cPresent=%d)\n", pPool->cPresent));
147e101bcd061b5e085e4a2c0cc9fc35546ff1aavboxsync STAM_PROFILE_STOP(&pPool->StatTrackFlushGCPhysPTsSlow, s);
1dc37bff2fb26897f5892d8330fe2bc0c9859aecvboxsync * Iterate all the pages until we've encountered all that in use.
71c8a528203c289a8585ce10ac6bafc4274058c6vboxsync * This is simple but not quite optimal solution.
825c2485cf84eec495985ffd605a1c9cddee8c32vboxsync const uint64_t u64 = PGM_PAGE_GET_HCPHYS(pPhysPage) | X86_PTE_P;
pPT->a[i].u = 0;
if (!--cPresent)
pPT->a[i].u = 0;
if (!--cPresent)
if (!--cLeft)
return VINF_SUCCESS;
#ifdef VBOX_STRICT
# ifndef VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0
case PGMPOOLKIND_ROOT_PAE_PD:
AssertMsg(!(u.pau64[iUserTable] & PGM_PDFLAGS_MAPPING), ("%llx %d\n", u.pau64[iUserTable], iUserTable));
case PGMPOOLKIND_ROOT_PDPT:
case PGMPOOLKIND_ROOT_NESTED:
case PGMPOOLKIND_ROOT_PAE_PD:
case PGMPOOLKIND_ROOT_PDPT:
case PGMPOOLKIND_ROOT_NESTED:
AssertFatalMsgFailed(("enmKind=%d iUser=%#x iUserTable=%#x\n", pUserPage->enmKind, pUser->iUser, pUser->iUserTable));
while (i != NIL_PGMPOOL_USER_INDEX)
i = iNext;
#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
return NULL;
return pPhysExt;
return iPhysExt | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
return iPhysExtStart | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
if (!--cMax)
return MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
if (!pNew)
return MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
LogFlow(("pgmPoolTrackPhysExtAddref: added new extent %d:{%d}->%d\n", iPhysExt, iShwPT, iPhysExtStart));
return iPhysExt | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
if (pPhysExt)
LogFlow(("pgmPoolTrackPhysExtAddref: new extent: %d:{%d, %d}\n", iPhysExt, u16 & MM_RAM_FLAGS_IDX_MASK, iShwPT));
u16 = iPhysExt | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
u16 = MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT));
else if (u16 != (MM_RAM_FLAGS_IDX_OVERFLOWED | (MM_RAM_FLAGS_CREFS_PHYSEXT << (MM_RAM_FLAGS_CREFS_SHIFT - MM_RAM_FLAGS_IDX_SHIFT))))
return u16;
AssertFatalMsg(cRefs == MM_RAM_FLAGS_CREFS_PHYSEXT, ("cRefs=%d HCPhys=%RHp pPage=%p:{.idx=%d}\n", cRefs, pPhysPage->HCPhys, pPage, pPage->idx));
LogFlow(("pgmPoolTrackPhysExtDerefGCPhys: HCPhys=%RX64 idx=%d lonely\n", pPhysPage->HCPhys, pPage->idx));
LogFlow(("pgmPoolTrackPhysExtDerefGCPhys: HCPhys=%RX64 idx=%d head\n", pPhysPage->HCPhys, pPage->idx));
AssertFatalMsgFailed(("not-found! cRefs=%d HCPhys=%RHp pPage=%p:{.idx=%d}\n", cRefs, pPhysPage->HCPhys, pPage, pPage->idx));
static void pgmPoolTracDerefGCPhys(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhys)
while (pRam)
#ifdef LOG_ENABLED
static void pgmPoolTracDerefGCPhysHint(PPGMPOOL pPool, PPGMPOOLPAGE pPage, RTHCPHYS HCPhys, RTGCPHYS GCPhysHint)
while (pRam)
while (pRam)
while (iPage-- > 0)
DECLINLINE(void) pgmPoolTrackDerefPT32Bit32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PT pShwPT, PCX86PT pGstPT)
pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK);
DECLINLINE(void) pgmPoolTrackDerefPTPae32Bit(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT, PCX86PT pGstPT)
pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PG_MASK);
DECLINLINE(void) pgmPoolTrackDerefPTPaePae(PPGMPOOL pPool, PPGMPOOLPAGE pPage, PX86PTPAE pShwPT, PCX86PTPAE pGstPT)
pgmPoolTracDerefGCPhysHint(pPool, pPage, pShwPT->a[i].u & X86_PTE_PAE_PG_MASK, pGstPT->a[i].u & X86_PTE_PAE_PG_MASK);
PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & X86_PDE_PAE_PG_MASK);
if (pSubPage)
PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & X86_PDPE_PG_MASK);
if (pSubPage)
PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPML4->a[i].u & X86_PDPE_PG_MASK);
if (pSubPage)
PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPD->a[i].u & EPT_PDE_PG_MASK);
if (pSubPage)
PPGMPOOLPAGE pSubPage = (PPGMPOOLPAGE)RTAvloHCPhysGet(&pPool->HCPhysTree, pShwPDPT->a[i].u & EPT_PDPTE_PG_MASK);
if (pSubPage)
#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
void *pvGst;
void *pvGst;
void *pvGst;
case PGMPOOLKIND_ROOT_PDPT:
case PGMPOOLKIND_ROOT_NESTED:
#ifdef IN_RING3
#ifdef PGMPOOL_WITH_MONITORING
#ifdef PGMPOOL_WITH_USER_TRACKING
#ifdef PGMPOOL_WITH_CACHE
#ifdef PGMPOOL_WITH_USER_TRACKING
for (unsigned i = 0; i < cMaxUsers; i++)
#ifdef PGMPOOL_WITH_GCPHYS_TRACKING
pRam;
while (iPage-- > 0)
for (unsigned i = 0; i < cMaxPhysExts; i++)
#ifdef PGMPOOL_WITH_MONITORING
#ifdef PGMPOOL_WITH_CACHE
#ifdef PGMPOOL_WITH_MONITORING
# ifdef PGMPOOL_WITH_CACHE
#ifdef PGMPOOL_WITH_USER_TRACKING
#ifdef PGMPOOL_WITH_CACHE
* @retval VERR_PGM_POOL_CLEARED if the deregistration of the physical handler will cause a light weight pool flush.
Log(("pgmPoolFlushPage: special root page, rejected. enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
return VINF_SUCCESS;
("Can't free the shadow CR3! (%RHp vs %RHp kind=%d\n", PGMGetHyperCR3(pPool->CTX_SUFF(pVM)), pPage->Core.Key, pPage->enmKind));
Log(("pgmPoolFlushPage: current active shadow CR3, rejected. enmKind=%d idx=%d\n", pPage->enmKind, pPage->idx));
return VINF_SUCCESS;
#ifdef PGMPOOL_WITH_USER_TRACKING
#ifdef PGMPOOL_WITH_CACHE
#ifdef PGMPOOL_WITH_MONITORING
return rc;
#ifdef PGMPOOL_WITH_USER_TRACKING
#ifdef PGMPOOL_WITH_CACHE
#ifdef IN_RING3
return rc;
return VINF_SUCCESS;
#ifdef PGMPOOL_WITH_CACHE
return VERR_PGM_POOL_FLUSHED;
int pgmPoolAlloc(PVM pVM, RTGCPHYS GCPhys, PGMPOOLKIND enmKind, uint16_t iUser, uint32_t iUserTable, PPPGMPOOLPAGE ppPage)
LogFlow(("pgmPoolAlloc: GCPhys=%RGp enmKind=%d iUser=%#x iUserTable=%#x\n", GCPhys, enmKind, iUser, iUserTable));
#ifdef PGMPOOL_WITH_CACHE
LogFlow(("pgmPoolAlloc: cached returns %Rrc *ppPage=%p:{.Key=%RHp, .idx=%d}\n", rc2, *ppPage, (*ppPage)->Core.Key, (*ppPage)->idx));
return rc2;
return rc;
pPool->cUsedPages++; /* physical handler registration / pgmPoolTrackFlushGCPhysPTsSlow requirement. */
#ifdef PGMPOOL_WITH_MONITORING
#ifdef PGMPOOL_WITH_USER_TRACKING
return rc3;
#ifdef VBOX_WITH_STATISTICS
LogFlow(("pgmPoolAlloc: returns %Rrc *ppPage=%p:{.Key=%RHp, .idx=%d, .fCached=%RTbool, .fMonitored=%RTbool}\n",
return rc;
return pPage;