PGMAllPhys.cpp revision 73ad24047e6df1acb94f7166288ada2533b6d7e7
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * PGM - Page Manager and Monitor, Physical Memory Addressing.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * available from http://www.virtualbox.org. This file is free software;
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * you can redistribute it and/or modify it under the terms of the GNU
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * General Public License (GPL) as published by the Free Software
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * additional information or have any questions.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync/*******************************************************************************
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync* Header Files *
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync*******************************************************************************/
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * \#PF Handler callback for Guest ROM range write access.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * We simply ignore the writes or fall back to the recompiler if we don't support the instruction.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * @returns VBox status code (appropritate for trap handling and GC return).
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * @param pVM VM Handle.
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync * @param uErrorCode CPU Error code.
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync * @param pRegFrame Trap register frame.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * @param pvFault The fault address (cr2).
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * @param GCPhysFault The GC physical address corresponding to pvFault.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsync * @param pvUser User argument. Pointer to the ROM range structure.
5c1381fc884d30a749517579368ff6cb4b43e809vboxsyncVMMDECL(int) pgmPhysRomWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPHYS GCPhysFault, void *pvUser)
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync uint32_t iPage = (GCPhysFault - pRom->GCPhys) >> PAGE_SHIFT;
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync * If it's a simple instruction which doesn't change the cpu state
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * we will simply skip it. Otherwise we'll have to defer it to REM.
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync rc = EMInterpretDisasOne(pVM, pVCpu, pRegFrame, pDis, &cbOp);
3fd65c821ad93f378baf8c75b30dcb6a17a5dd77vboxsync && pDis->mode == CPUMODE_32BIT /** @todo why does this matter? */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync && !(pDis->prefix & (PREFIX_REPNE | PREFIX_REP | PREFIX_SEG)))
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** @todo Find other instructions we can safely skip, possibly
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * adding this kind of detection to DIS or EM. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZGuestROMWriteHandled);
5e5603ae40c7a0a884fe91e269b7d6d6c0ba56f5vboxsync rc = PGMHandlerPhysicalPageTempOff(pVM, pRom->GCPhys, GCPhysFault & X86_PTE_PG_MASK);
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync break; /** @todo Must edit the shadow PT and restart the instruction, not use the interpreter! */
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync /* Handle it in ring-3 because it's *way* easier there. */
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync AssertMsgFailedReturn(("enmProt=%d iPage=%d GCPhysFault=%RGp\n",
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZGuestROMWriteUnhandled);
2235e7604f29ce0edc7a1d9aa829668563f86867vboxsync#endif /* IN_RING3 */
2235e7604f29ce0edc7a1d9aa829668563f86867vboxsync * Checks if Address Gate 20 is enabled or not.
6a5bc4dc98789eb202e249b189f036e5ff9129ccvboxsync * @returns true if enabled.
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * @returns false if disabled.
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * @param pVCpu VMCPU handle.
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync LogFlow(("PGMPhysIsA20Enabled %d\n", pVCpu->pgm.s.fA20Enabled));
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * Validates a GC physical address.
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * @returns true if valid.
ab7139411cba3600213877c953b69fc11a7ef0cfvboxsync * @returns false if invalid.
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * @param pVM The VM handle.
04bce18d27791abed8346aba0de41c53a2acd81avboxsync * @param GCPhys The physical address to validate.
04bce18d27791abed8346aba0de41c53a2acd81avboxsyncVMMDECL(bool) PGMPhysIsGCPhysValid(PVM pVM, RTGCPHYS GCPhys)
04bce18d27791abed8346aba0de41c53a2acd81avboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync * Checks if a GC physical address is a normal page,
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync * i.e. not ROM, MMIO or reserved.
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync * @returns true if normal.
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync * @returns false if invalid, ROM, MMIO or reserved page.
2a560b28131ee7efa5b73a9e9cbfdb08eae28624vboxsync * @param pVM The VM handle.
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * @param GCPhys The physical address to check.
e3e8bde164b5715114ebf596187b5512fa9b75advboxsyncVMMDECL(bool) PGMPhysIsGCPhysNormal(PVM pVM, RTGCPHYS GCPhys)
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * Converts a GC physical address to a HC physical address.
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * @returns VINF_SUCCESS on success.
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * @returns VERR_PGM_PHYS_PAGE_RESERVED it it's a valid GC physical
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync * page but has no physical backing.
04bce18d27791abed8346aba0de41c53a2acd81avboxsync * @returns VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid
04bce18d27791abed8346aba0de41c53a2acd81avboxsync * GC physical address.
04bce18d27791abed8346aba0de41c53a2acd81avboxsync * @param pVM The VM handle.
04bce18d27791abed8346aba0de41c53a2acd81avboxsync * @param GCPhys The GC physical address to convert.
04bce18d27791abed8346aba0de41c53a2acd81avboxsync * @param pHCPhys Where to store the HC physical address on success.
e3e8bde164b5715114ebf596187b5512fa9b75advboxsyncVMMDECL(int) PGMPhysGCPhys2HCPhys(PVM pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys)
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync int rc = pgmPhysGetPageEx(&pVM->pgm.s, GCPhys, &pPage);
e3e8bde164b5715114ebf596187b5512fa9b75advboxsync *pHCPhys = PGM_PAGE_GET_HCPHYS(pPage) | (GCPhys & PAGE_OFFSET_MASK);
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync * Invalidates all page mapping TLBs.
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync * @param pVM The VM handle.
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatPageMapTlbFlushes);
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync /* Clear the shared R0/R3 TLB completely. */
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync for (unsigned i = 0; i < RT_ELEMENTS(pVM->pgm.s.PhysTlbHC.aEntries); i++)
5a7d67754026bd3654a2464799f0db1790ecf183vboxsync pVM->pgm.s.PhysTlbHC.aEntries[i].GCPhys = NIL_RTGCPHYS;
1df297ea8319f3f3afddb73e6ea2fd9c7f0e5eb4vboxsync /* @todo clear the RC TLB whenever we add it. */
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync * Invalidates a page mapping TLB entry
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync * @param pVM The VM handle.
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsync * @param GCPhys GCPhys entry to flush
c00fd08041e14ed8ad7733165f855bfbbc818a0evboxsyncVMMDECL(void) PGMPhysInvalidatePageMapTLBEntry(PVM pVM, RTGCPHYS GCPhys)
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync STAM_COUNTER_INC(&pVM->pgm.s.StatPageMapTlbFlushEntry);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync /* Clear the shared R0/R3 TLB entry. */
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync pVM->pgm.s.PhysTlbHC.aEntries[idx].GCPhys = NIL_RTGCPHYS;
d9658602103599d13b5449fc1ea49d765a23e6f1vboxsync PPGMPAGEMAPTLBE pTlbe = &pVM->pgm.s.CTXSUFF(PhysTlb).aEntries[PGM_PAGEMAPTLB_IDX(GCPhys)];
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync /* @todo clear the RC TLB whenever we add it. */
e0dec59adb362e8486c0622785420ad10e720972vboxsync * Makes sure that there is at least one handy page ready for use.
e0dec59adb362e8486c0622785420ad10e720972vboxsync * This will also take the appropriate actions when reaching water-marks.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @returns VBox status code.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @retval VINF_SUCCESS on success.
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * @retval VERR_EM_NO_MEMORY if we're really out of memory.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * @param pVM The VM handle.
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync * @remarks Must be called from within the PGM critical section. It may
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * nip back to ring-3/0 in some cases.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync AssertMsg(pVM->pgm.s.cHandyPages <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d\n", pVM->pgm.s.cHandyPages));
e0dec59adb362e8486c0622785420ad10e720972vboxsync * Do we need to do anything special?
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync if (pVM->pgm.s.cHandyPages <= RT_MAX(PGM_HANDY_PAGES_SET_FF, PGM_HANDY_PAGES_R3_ALLOC))
fa86ccda70bc5dd1ae28597340f252b212dcf36dvboxsync if (pVM->pgm.s.cHandyPages <= RT_MAX(PGM_HANDY_PAGES_SET_FF, PGM_HANDY_PAGES_RZ_TO_R3))
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync * Allocate pages only if we're out of them, or in ring-3, almost out.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_R3_ALLOC)
2c19fa7a35e93931f995c196426585b16f8bf2c0vboxsync if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_RZ_ALLOC)
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync Log(("PGM: cHandyPages=%u out of %u -> allocate more; VM_FF_PGM_NO_MEMORY=%RTbool\n",
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync pVM->pgm.s.cHandyPages, RT_ELEMENTS(pVM->pgm.s.aHandyPages), VM_FF_ISSET(pVM, VM_FF_PGM_NO_MEMORY) ));
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync int rc = VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_PGM_ALLOCATE_HANDY_PAGES, 0);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync AssertMsgReturn(rc == VINF_EM_NO_MEMORY, ("%Rrc\n", rc), VERR_IPE_UNEXPECTED_INFO_STATUS);
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync Assert(VM_FF_ISSET(pVM, VM_FF_PGM_NEED_HANDY_PAGES));
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync VMCPU_FF_SET(VMMGetCpu(pVM), VMCPU_FF_TO_R3); /* paranoia */
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync && pVM->pgm.s.cHandyPages <= RT_ELEMENTS(pVM->pgm.s.aHandyPages),
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_SET_FF)
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync if (pVM->pgm.s.cHandyPages <= PGM_HANDY_PAGES_RZ_TO_R3)
1d8f69ceb39fecbf9a7c95dbac083f3ce5c4efd9vboxsync Log(("PGM: VM_FF_TO_R3 - cHandyPages=%u out of %u\n", pVM->pgm.s.cHandyPages, RT_ELEMENTS(pVM->pgm.s.aHandyPages)));
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * Replace a zero or shared page with new page that we can write to.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @returns The following VBox status codes.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @retval VINF_SUCCESS on success, pPage is modified.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @retval VINF_PGM_SYNC_CR3 on success and a page pool flush is pending.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @retval VERR_EM_NO_MEMORY if we're totally out of memory.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @todo Propagate VERR_EM_NO_MEMORY up the call tree.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @param pVM The VM address.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @param pPage The physical page tracking structure. This will
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * be modified on success.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @param GCPhys The address of the page.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @remarks Must be called from within the PGM critical section. It may
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * nip back to ring-3/0 in some cases.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * @remarks This function shouldn't really fail, however if it does
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * it probably means we've screwed up the size of handy pages and/or
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * the low-water mark. Or, that some device I/O is causing a lot of
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * pages to be allocated while while the host is in a low-memory
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * condition. This latter should be handled elsewhere and in a more
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * controlled manner, it's on the @bugref{3170} todo list...
34bfec0bd844700e3b769dcfad1a869ca6b8a0d8vboxsyncint pgmPhysAllocPage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys)
34bfec0bd844700e3b769dcfad1a869ca6b8a0d8vboxsync LogFlow(("pgmPhysAllocPage: %R[pgmpage] %RGp\n", pPage, GCPhys));
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys));
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * Flush any shadow page table mappings of the page.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * When VBOX_WITH_NEW_LAZY_PAGE_ALLOC isn't defined, there shouldn't be any.
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync bool fFlushTLBs = false;
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync int rc = pgmPoolTrackFlushGCPhys(pVM, pPage, &fFlushTLBs);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync AssertMsgReturn(rc == VINF_SUCCESS || rc == VINF_PGM_SYNC_CR3, ("%Rrc\n", rc), RT_FAILURE(rc) ? rc : VERR_IPE_UNEXPECTED_STATUS);
0aaf889969ebdaba8a310db13adcec8c10174796vboxsync * Ensure that we've got a page handy, take it and use it.
165b506f4c024dabd5a4caaeda31c66712d154eavboxsync /* re-assert preconditions since pgmPhysEnsureHandyPage may do a context switch. */
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys));
AssertMsgFailed(("TODO: copy shared page content")); /** @todo err.. what about copying the page content? */
Log2(("PGM: Replaced zero page %RGp with %#x / %RHp\n", GCPhys, pVM->pgm.s.aHandyPages[iHandyPage].idPage, HCPhys));
if ( fFlushTLBs
return rc;
case PGM_PAGE_STATE_ALLOCATED:
return VINF_SUCCESS;
case PGM_PAGE_STATE_ZERO:
return VERR_PGM_PHYS_PAGE_RESERVED;
case PGM_PAGE_STATE_SHARED:
return rc;
#ifdef IN_RC
if (!pMap)
# ifdef IN_RING0
return rc;
return VINF_SUCCESS;
static int pgmPhysPageMapCommon(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMPAGEMAP ppMap, void **ppv)
return VINF_SUCCESS;
AssertMsgReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, ("pPage=%R[pgmpage]\n", pPage), VERR_INTERNAL_ERROR_2);
AssertMsgReturn(pRam || !pRam->pvR3, ("pRam=%p pPage=%R[pgmpage]\n", pRam, pPage), VERR_INTERNAL_ERROR_2);
return VINF_SUCCESS;
if (!pMap)
#ifdef IN_RING0
return rc;
return VINF_SUCCESS;
return rc;
if (!pRam)
void *pv;
return rc;
return VINF_SUCCESS;
void *pv;
return rc;
return VINF_SUCCESS;
int rc;
return rc;
return rc;
return VINF_SUCCESS;
*ppv = pgmDynMapHCPageOff(&pVM->pgm.s, PGM_PAGE_GET_HCPHYS(pPage) | (GCPhys & PAGE_OFFSET_MASK)); /** @todo add a read only flag? */
return rc;
return VINF_SUCCESS;
*ppv = pgmDynMapHCPageOff(&pVM->pgm.s, PGM_PAGE_GET_HCPHYS(pPage) | (GCPhys & PAGE_OFFSET_MASK)); /** @todo add a read only flag? */
if (pMap)
if (cLocks == 0)
if (pMap)
return rc;
VMMDECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock)
*ppv = pgmDynMapHCPageOff(&pVM->pgm.s, PGM_PAGE_GET_HCPHYS(pPage) | (GCPhys & PAGE_OFFSET_MASK)); /** @todo add a read only flag? */
if (pMap)
if (cLocks == 0)
AssertMsgFailed(("%RGp / %R[pgmpage] is entering permanent readonly locked state!\n", GCPhys, pPage));
if (pMap)
return rc;
return rc;
VMMDECL(int) PGMPhysGCPtr2CCPtrReadOnly(PVMCPU pVCpu, RTGCPTR GCPtr, void const **ppv, PPGMPAGEMAPLOCK pLock)
return rc;
if (fWriteLock)
if (pMap)
#ifndef DEBUG_sandervl
Log(("PGMPhysGCPhys2R3Ptr(,%RGp,%#x,): dont use this API!\n", GCPhys, cbRange)); /** @todo eliminate this API! */
return rc;
#ifdef VBOX_STRICT
return R3Ptr;
return NIL_RTR3PTR;
return rc;
return rc;
rc = PGMPhysGCPhys2R3Ptr(pVM, GCPhys | ((RTGCUINTPTR)GCPtr & PAGE_OFFSET_MASK), 1 /* we always stay within one page */, pR3Ptr);
return rc;
#ifdef IN_RING3
AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
return VINF_SUCCESS;
#ifdef IN_RING3
Log5(("pgmPhysReadHandler: GCPhys=%RGp cb=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cb, pPage, R3STRING(pPhys->pszDesc) ));
# ifdef VBOX_WITH_STATISTICS
if (pPhys)
AssertLogRelMsg(rc == VINF_SUCCESS || rc == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp\n", rc, GCPhys));
return VERR_PGM_PHYS_WR_HIT_HANDLER;
unsigned iPage;
Assert(GCPhys >= pVirt->aPhysToVirt[iPage].Core.Key && GCPhys <= pVirt->aPhysToVirt[iPage].Core.KeyLast);
#ifdef IN_RING3
if (!pPhys)
Log5(("pgmPhysReadHandler: GCPhys=%RGp cb=%#x pPage=%R[pgmpage] virt %s\n", GCPhys, cb, pPage, R3STRING(pVirt->pszDesc) ));
Log(("pgmPhysReadHandler: GCPhys=%RGp cb=%#x pPage=%R[pgmpage] phys/virt %s/%s\n", GCPhys, cb, pPage, R3STRING(pVirt->pszDesc), R3STRING(pPhys->pszDesc) ));
rc2 = pVirt->CTX_SUFF(pfnHandler)(pVM, GCPtr, (void *)pvSrc, pvBuf, cb, PGMACCESSTYPE_READ, /*pVirt->CTX_SUFF(pvUser)*/ NULL);
AssertLogRelMsg(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc2, GCPhys, pPage, pVirt->pszDesc));
Log5(("pgmPhysReadHandler: GCPhys=%RGp cb=%#x pPage=%R[pgmpage] virt %s [no handler]\n", GCPhys, cb, pPage, R3STRING(pVirt->pszDesc) ));
return VERR_PGM_PHYS_WR_HIT_HANDLER;
return rc;
return rc;
const void *pvSrc;
AssertLogRelMsgFailed(("pgmPhysGCPhys2CCPtrInternalReadOnly failed on %RGp / %R[pgmpage] -> %Rrc\n",
return VINF_SUCCESS;
if (!pRam)
return VINF_SUCCESS;
static int pgmPhysWriteHandler(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void const *pvBuf, size_t cbWrite)
int rc;
PPGMPHYSHANDLER pCur = (PPGMPHYSHANDLER)RTAvlroGCPhysRangeGet(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysHandlers, GCPhys);
if (pCur)
#ifndef IN_RING3
return VERR_PGM_PHYS_WR_HIT_HANDLER;
Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pCur->pszDesc) ));
# ifdef VBOX_WITH_STATISTICS
if (pCur)
AssertLogRelMsg(rc == VINF_SUCCESS || rc == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, (pCur) ? pCur->pszDesc : ""));
return VINF_SUCCESS;
unsigned iPage;
#ifndef IN_RING3
return VERR_PGM_PHYS_WR_HIT_HANDLER;
Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] virt %s\n", GCPhys, cbRange, pPage, R3STRING(pCur->pszDesc) ));
rc = pCur->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, /*pCur->CTX_SUFF(pvUser)*/ NULL);
AssertLogRelMsg(rc == VINF_SUCCESS, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, pCur->pszDesc));
return VINF_SUCCESS;
if (!pvDst)
unsigned iVirtPage = 0;
offVirt = 0;
offVirtLast = (pVirt->aPhysToVirt[iVirtPage].Core.KeyLast & PAGE_OFFSET_MASK) - (GCPhys & PAGE_OFFSET_MASK);
pVirtPhys = (PPGMPHYS2VIRTHANDLER)RTAvlroGCPhysGetBestFit(&pVM->pgm.s.CTX_SUFF(pTrees)->PhysToVirtHandlers,
if ( pVirtPhys
fMoreVirt = false;
if (pPhys)
offPhys = 0;
if ( pPhys
fMorePhys = false;
Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] miss\n", GCPhys, cbRange, pPage));
#ifdef IN_RING3
Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pPhys->pszDesc) ));
# ifdef VBOX_WITH_STATISTICS
if (pPhys)
AssertLogRelMsg(rc == VINF_SUCCESS || rc == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, (pPhys) ? pPhys->pszDesc : ""));
return VERR_PGM_PHYS_WR_HIT_HANDLER;
#ifdef IN_RING3
Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pVirt->pszDesc) ));
rc = pVirt->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, /*pCur->CTX_SUFF(pvUser)*/ NULL);
AssertLogRelMsg(rc == VINF_SUCCESS || rc == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, pVirt->pszDesc));
return VERR_PGM_PHYS_WR_HIT_HANDLER;
#ifdef IN_RING3
Log(("pgmPhysWriteHandler: overlapping phys and virt handlers at %RGp %R[pgmpage]; cbRange=%#x\n", GCPhys, pPage, cbRange));
Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys/virt %s/%s\n", GCPhys, cbRange, pPage, R3STRING(pPhys->pszDesc), R3STRING(pVirt->pszDesc) ));
# ifdef VBOX_WITH_STATISTICS
if (pPhys)
AssertLogRelMsg(rc == VINF_SUCCESS || rc == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, (pPhys) ? pPhys->pszDesc : ""));
int rc2 = pVirt->CTX_SUFF(pfnHandler)(pVM, GCPtr, pvDst, (void *)pvBuf, cbRange, PGMACCESSTYPE_WRITE, /*pCur->CTX_SUFF(pvUser)*/ NULL);
AssertLogRelMsg(rc2 == VINF_SUCCESS || rc2 == VINF_PGM_HANDLER_DO_DEFAULT, ("rc=%Rrc GCPhys=%RGp pPage=%R[pgmpage] %s\n", rc, GCPhys, pPage, pVirt->pszDesc));
return VERR_PGM_PHYS_WR_HIT_HANDLER;
return VINF_SUCCESS;
return rc;
void *pvDst;
return VINF_SUCCESS;
if (!pRam)
return VINF_SUCCESS;
if (!cb)
return VINF_SUCCESS;
void const *pvSrc;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
if (!cb)
return VINF_SUCCESS;
void *pvDst;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
if (!cb)
return VINF_SUCCESS;
/* Take the PGM lock here, because many called functions take the lock for a very short period. That's counter-productive
void const *pvSrc;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
if (!cb)
return VINF_SUCCESS;
void *pvDst;
return rc;
return VINF_SUCCESS;
return rc;
return VINF_SUCCESS;
VMMDECL(int) PGMPhysSimpleDirtyWriteGCPtr(PVMCPU pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb)
if (!cb)
return VINF_SUCCESS;
void *pvDst;
return rc;
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
return VINF_SUCCESS;
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
return rc;
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
return VINF_SUCCESS;
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D)); AssertRC(rc);
int rc;
if (!cb)
return VINF_SUCCESS;
return rc;
int rc;
if (!cb)
return VINF_SUCCESS;
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
return rc;
VMMDECL(int) PGMPhysInterpretedRead(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCUINTPTR GCPtrSrc, size_t cb)
int rc;
void *pvSrc;
switch (rc)
case VINF_SUCCESS:
Log(("PGMPhysInterpretedRead: pvDst=%p pvSrc=%p cb=%d\n", pvDst, (uint8_t *)pvSrc + (GCPtrSrc & PAGE_OFFSET_MASK), cb));
return rc;
return VINF_SUCCESS;
void *pvSrc1;
switch (rc)
case VINF_SUCCESS:
return rc;
void *pvSrc2;
switch (rc)
case VINF_SUCCESS:
return rc;
return VINF_SUCCESS;
switch (rc)
case VINF_SUCCESS:
case VERR_PAGE_NOT_PRESENT:
return rc;
VMMDECL(int) PGMPhysInterpretedReadNoHandlers(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, void *pvDst, RTGCUINTPTR GCPtrSrc, size_t cb, bool fRaiseTrap)
int rc;
const void *pvSrc;
switch (rc)
case VINF_SUCCESS:
return rc;
return VINF_SUCCESS;
const void *pvSrc;
switch (rc)
case VINF_SUCCESS:
return rc;
switch (rc)
case VINF_SUCCESS:
return rc;
return VINF_SUCCESS;
switch (rc)
case VINF_SUCCESS:
case VERR_PAGE_NOT_PRESENT:
return rc;
if (fRaiseTrap)
Log(("PGMPhysInterpretedReadNoHandlers: GCPtrSrc=%RGv cb=%#x -> Raised #PF(%#x)\n", GCPtrSrc, cb, uErr));
Log(("PGMPhysInterpretedReadNoHandlers: GCPtrSrc=%RGv cb=%#x -> #PF(%#x) [!raised]\n", GCPtrSrc, cb, uErr));
return rc;
VMMDECL(int) PGMPhysInterpretedWriteNoHandlers(PVMCPU pVCpu, PCPUMCTXCORE pCtxCore, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb, bool fRaiseTrap)
int rc;
&& CPUMGetGuestCPL(pVCpu, pCtxCore) <= 2) ) /** @todo it's 2, right? Check cpl check below as well. */
void *pvDst;
switch (rc)
case VINF_SUCCESS:
return rc;
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, X86_PTE_A | X86_PTE_D, ~(uint64_t)(X86_PTE_A | X86_PTE_D));
return VINF_SUCCESS;
void *pvDst;
switch (rc)
case VINF_SUCCESS:
return rc;
switch (rc)
case VINF_SUCCESS:
return rc;
rc = PGMGstModifyPage(pVCpu, GCPtrDst, 1, (X86_PTE_A | X86_PTE_RW), ~(uint64_t)(X86_PTE_A | X86_PTE_RW));
rc = PGMGstModifyPage(pVCpu, GCPtrDst + cb1, 1, (X86_PTE_A | X86_PTE_RW), ~(uint64_t)(X86_PTE_A | X86_PTE_RW));
return VINF_SUCCESS;
switch (rc)
case VINF_SUCCESS:
case VERR_ACCESS_DENIED:
case VERR_PAGE_NOT_PRESENT:
return rc;
if (fRaiseTrap)
Log(("PGMPhysInterpretedWriteNoHandlers: GCPtrDst=%RGv cb=%#x -> Raised #PF(%#x)\n", GCPtrDst, cb, uErr));
Log(("PGMPhysInterpretedWriteNoHandlers: GCPtrDst=%RGv cb=%#x -> #PF(%#x) [!raised]\n", GCPtrDst, cb, uErr));
return rc;