diff options
Diffstat (limited to 'src/VBox/VMM/VMMAll/PGMAllPhys.cpp')
| -rw-r--r-- | src/VBox/VMM/VMMAll/PGMAllPhys.cpp | 161 |
1 files changed, 116 insertions, 45 deletions
diff --git a/src/VBox/VMM/VMMAll/PGMAllPhys.cpp b/src/VBox/VMM/VMMAll/PGMAllPhys.cpp index 0bb156e6..9d6c7f98 100644 --- a/src/VBox/VMM/VMMAll/PGMAllPhys.cpp +++ b/src/VBox/VMM/VMMAll/PGMAllPhys.cpp @@ -4,7 +4,7 @@ */ /* - * Copyright (C) 2006-2011 Oracle Corporation + * Copyright (C) 2006-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -119,8 +119,6 @@ VMMDECL(int) pgmPhysRomWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE p return VINF_SUCCESS; } } - else if (RT_UNLIKELY(rc == VERR_EM_INTERNAL_DISAS_ERROR)) - return rc; break; } @@ -489,7 +487,7 @@ static int pgmPhysEnsureHandyPage(PVM pVM) #endif { Log(("PGM: cHandyPages=%u out of %u -> allocate more; VM_FF_PGM_NO_MEMORY=%RTbool\n", - pVM->pgm.s.cHandyPages, RT_ELEMENTS(pVM->pgm.s.aHandyPages), VM_FF_ISSET(pVM, VM_FF_PGM_NO_MEMORY) )); + pVM->pgm.s.cHandyPages, RT_ELEMENTS(pVM->pgm.s.aHandyPages), VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY) )); #ifdef IN_RING3 int rc = PGMR3PhysAllocateHandyPages(pVM); #else @@ -505,8 +503,8 @@ static int pgmPhysEnsureHandyPage(PVM pVM) LogRel(("PGM: no more handy pages!\n")); return VERR_EM_NO_MEMORY; } - Assert(VM_FF_ISSET(pVM, VM_FF_PGM_NEED_HANDY_PAGES)); - Assert(VM_FF_ISSET(pVM, VM_FF_PGM_NO_MEMORY)); + Assert(VM_FF_IS_SET(pVM, VM_FF_PGM_NEED_HANDY_PAGES)); + Assert(VM_FF_IS_SET(pVM, VM_FF_PGM_NO_MEMORY)); #ifdef IN_RING3 # ifdef VBOX_WITH_REM REMR3NotifyFF(pVM); @@ -572,7 +570,7 @@ int pgmPhysAllocPage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys) */ PGM_LOCK_ASSERT_OWNER(pVM); AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys)); - Assert(!PGM_PAGE_IS_MMIO(pPage)); + Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)); # ifdef PGM_WITH_LARGE_PAGES /* @@ -621,7 +619,7 @@ int pgmPhysAllocPage(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys) /* re-assert preconditions since pgmPhysEnsureHandyPage may do a context switch. */ PGM_LOCK_ASSERT_OWNER(pVM); AssertMsg(PGM_PAGE_IS_ZERO(pPage) || PGM_PAGE_IS_SHARED(pPage), ("%R[pgmpage] %RGp\n", pPage, GCPhys)); - Assert(!PGM_PAGE_IS_MMIO(pPage)); + Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)); uint32_t iHandyPage = --pVM->pgm.s.cHandyPages; AssertMsg(iHandyPage < RT_ELEMENTS(pVM->pgm.s.aHandyPages), ("%d\n", iHandyPage)); @@ -1029,35 +1027,42 @@ static int pgmPhysPageMapCommon(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, PPPGMP /* - * Special case: ZERO and MMIO2 pages. + * Special cases: MMIO2, ZERO and specially aliased MMIO pages. */ + if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2 + || PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO) + { + /* Decode the page id to a page in a MMIO2 ram range. */ + uint8_t idMmio2 = PGM_MMIO2_PAGEID_GET_MMIO2_ID(PGM_PAGE_GET_PAGEID(pPage)); + uint32_t iPage = PGM_MMIO2_PAGEID_GET_IDX(PGM_PAGE_GET_PAGEID(pPage)); + AssertLogRelReturn((uint8_t)(idMmio2 - 1U)< RT_ELEMENTS(pVM->pgm.s.CTX_SUFF(apMmio2Ranges)), + VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE); + PPGMMMIO2RANGE pMmio2Range = pVM->pgm.s.CTX_SUFF(apMmio2Ranges)[idMmio2 - 1]; + AssertLogRelReturn(pMmio2Range, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE); + AssertLogRelReturn(pMmio2Range->idMmio2 == idMmio2, VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE); + AssertLogRelReturn(iPage < (pMmio2Range->RamRange.cb >> PAGE_SHIFT), VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE); + *ppv = (uint8_t *)pMmio2Range->RamRange.pvR3 + ((uintptr_t)iPage << PAGE_SHIFT); + *ppMap = NULL; + return VINF_SUCCESS; + } + const uint32_t idChunk = PGM_PAGE_GET_CHUNKID(pPage); if (idChunk == NIL_GMM_CHUNKID) { - AssertMsgReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, ("pPage=%R[pgmpage]\n", pPage), VERR_PGM_PHYS_PAGE_MAP_IPE_1); - if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2) - { - /* Lookup the MMIO2 range and use pvR3 to calc the address. */ - PPGMRAMRANGE pRam = pgmPhysGetRange(pVM, GCPhys); - AssertMsgReturn(pRam || !pRam->pvR3, ("pRam=%p pPage=%R[pgmpage]\n", pRam, pPage), VERR_PGM_PHYS_PAGE_MAP_IPE_2); - *ppv = (void *)((uintptr_t)pRam->pvR3 + (uintptr_t)((GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK) - pRam->GCPhys)); - } - else if (PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_MMIO2_ALIAS_MMIO) + AssertMsgReturn(PGM_PAGE_GET_PAGEID(pPage) == NIL_GMM_PAGEID, ("pPage=%R[pgmpage]\n", pPage), + VERR_PGM_PHYS_PAGE_MAP_IPE_1); + if (!PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage)) { - /** @todo deal with aliased MMIO2 pages somehow... - * One solution would be to seed MMIO2 pages to GMM and get unique Page IDs for - * them, that would also avoid this mess. It would actually be kind of - * elegant... */ - AssertLogRelMsgFailedReturn(("%RGp\n", GCPhys), VERR_PGM_MAP_MMIO2_ALIAS_MMIO); + AssertMsgReturn(PGM_PAGE_IS_ZERO(pPage), ("pPage=%R[pgmpage]\n", pPage), + VERR_PGM_PHYS_PAGE_MAP_IPE_3); + AssertMsgReturn(PGM_PAGE_GET_HCPHYS(pPage)== pVM->pgm.s.HCPhysZeroPg, ("pPage=%R[pgmpage]\n", pPage), + VERR_PGM_PHYS_PAGE_MAP_IPE_4); + *ppv = pVM->pgm.s.CTXALLSUFF(pvZeroPg); } else { - /** @todo handle MMIO2 */ - AssertMsgReturn(PGM_PAGE_IS_ZERO(pPage), ("pPage=%R[pgmpage]\n", pPage), VERR_PGM_PHYS_PAGE_MAP_IPE_3); - AssertMsgReturn(PGM_PAGE_GET_HCPHYS(pPage) == pVM->pgm.s.HCPhysZeroPg, - ("pPage=%R[pgmpage]\n", pPage), - VERR_PGM_PHYS_PAGE_MAP_IPE_4); - *ppv = pVM->pgm.s.CTXALLSUFF(pvZeroPg); + static uint8_t s_abPlayItSafe[0x1000*2]; /* I don't dare return the zero page at the moment. */ + *ppv = (uint8_t *)((uintptr_t)&s_abPlayItSafe[0x1000] & ~(uintptr_t)0xfff); } *ppMap = NULL; return VINF_SUCCESS; @@ -1685,7 +1690,7 @@ VMMDECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVM pVM, RTGCPHYS GCPhys, void const ** rc = pgmPhysGetPageEx(pVM, GCPhys, &pPage); if (RT_SUCCESS(rc)) { - if (RT_UNLIKELY(PGM_PAGE_IS_MMIO(pPage))) + if (RT_UNLIKELY(PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))) rc = VERR_PGM_PHYS_PAGE_RESERVED; else { @@ -1717,7 +1722,7 @@ VMMDECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVM pVM, RTGCPHYS GCPhys, void const ** { /* MMIO pages doesn't have any readable backing. */ PPGMPAGE pPage = pTlbe->pPage; - if (RT_UNLIKELY(PGM_PAGE_IS_MMIO(pPage))) + if (RT_UNLIKELY(PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage))) rc = VERR_PGM_PHYS_PAGE_RESERVED; else { @@ -2100,7 +2105,8 @@ static int pgmPhysReadHandler(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void *pv #ifdef IN_RING3 PPGMPHYSHANDLER pPhys = NULL; #endif - if (PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_ALL) + if ( PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_ALL + || PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)) { #ifdef IN_RING3 pPhys = pgmHandlerPhysicalLookup(pVM, GCPhys); @@ -2237,7 +2243,8 @@ VMMDECL(int) PGMPhysRead(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) /* * Any ALL access handlers? */ - if (RT_UNLIKELY(PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage))) + if (RT_UNLIKELY( PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage) + || PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage))) { int rc = pgmPhysReadHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb); if (RT_FAILURE(rc)) @@ -2336,8 +2343,8 @@ static int pgmPhysWriteHandler(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void co * write area. This should be a pretty frequent case with MMIO and * the heavy usage of full page handlers in the page pool. */ - if ( !PGM_PAGE_HAS_ACTIVE_VIRTUAL_HANDLERS(pPage) - || PGM_PAGE_IS_MMIO(pPage) /* screw virtual handlers on MMIO pages */) + if ( !PGM_PAGE_HAS_ACTIVE_VIRTUAL_HANDLERS(pPage) + || PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage) /* screw virtual handlers on MMIO pages */) { PPGMPHYSHANDLER pCur = pgmHandlerPhysicalLookup(pVM, GCPhys); if (pCur) @@ -2357,7 +2364,7 @@ static int pgmPhysWriteHandler(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void co #else /* IN_RING3 */ Log5(("pgmPhysWriteHandler: GCPhys=%RGp cbRange=%#x pPage=%R[pgmpage] phys %s\n", GCPhys, cbRange, pPage, R3STRING(pCur->pszDesc) )); - if (!PGM_PAGE_IS_MMIO(pPage)) + if (!PGM_PAGE_IS_MMIO_OR_SPECIAL_ALIAS(pPage)) rc = pgmPhysGCPhys2CCPtrInternal(pVM, pPage, GCPhys, &pvDst, &PgMpLck); else rc = VINF_SUCCESS; @@ -2405,7 +2412,7 @@ static int pgmPhysWriteHandler(PVM pVM, PPGMPAGE pPage, RTGCPHYS GCPhys, void co #endif /* IN_RING3 */ } /* else: the handler is somewhere else in the page, deal with it below. */ - Assert(!PGM_PAGE_IS_MMIO(pPage)); /* MMIO handlers are all PAGE_SIZEed! */ + Assert(!PGM_PAGE_IS_MMIO_OR_ALIAS(pPage)); /* MMIO handlers are all PAGE_SIZEed! */ } /* * A virtual handler without any interfering physical handlers. @@ -2772,7 +2779,8 @@ VMMDECL(int) PGMPhysWrite(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cb /* * Any active WRITE or ALL access handlers? */ - if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage)) + if ( PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) + || PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage)) { int rc = pgmPhysWriteHandler(pVM, pPage, pRam->GCPhys + off, pvBuf, cb); if (RT_FAILURE(rc)) @@ -4016,22 +4024,25 @@ VMMDECL(PGMPAGETYPE) PGMPhysGetPageType(PVM pVM, RTGCPHYS GCPhys) * accesses or is odd in any way. * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist. * - * @param pVM Pointer to the VM. - * @param GCPhys The GC physical address to convert. Since this is only - * used for filling the REM TLB, the A20 mask must be - * applied before calling this API. + * @param pVM Pointer to the cross context VM structure. + * @param pVCpu Pointer to the cross context virtual CPU structure of + * the calling EMT. + * @param GCPhys The GC physical address to convert. This API mask the + * A20 line when necessary. * @param fWritable Whether write access is required. * @param ppv Where to store the pointer corresponding to GCPhys on * success. * @param pLock * * @remarks This is more or a less a copy of PGMR3PhysTlbGCPhys2Ptr. + * @thread EMT(pVCpu). */ -VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers, +VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers, void **ppv, PPGMPAGEMAPLOCK pLock) { + PGM_A20_APPLY_TO_VAR(pVCpu, GCPhys); + pgmLock(pVM); - PGM_A20_ASSERT_MASKED(VMMGetCpu(pVM), GCPhys); PPGMRAMRANGE pRam; PPGMPAGE pPage; @@ -4040,6 +4051,8 @@ VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, { if (PGM_PAGE_IS_BALLOONED(pPage)) rc = VERR_PGM_PHYS_TLB_CATCH_WRITE; + else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage)) + rc = VERR_PGM_PHYS_TLB_CATCH_ALL; else if ( !PGM_PAGE_HAS_ANY_HANDLERS(pPage) || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) ) rc = VINF_SUCCESS; @@ -4077,7 +4090,6 @@ VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, } #if defined(IN_RC) || defined(VBOX_WITH_2X_4GB_ADDR_SPACE_IN_R0) - PVMCPU pVCpu = VMMGetCpu(pVM); void *pv; rc = pgmRZDynMapHCPageInlined(pVCpu, PGM_PAGE_GET_HCPHYS(pPage), @@ -4117,3 +4129,62 @@ VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, return rc; } + +/** + * Checks if the give GCPhys page requires special handling for the given access + * because it's MMIO or otherwise monitored. + * + * @returns VBox status code (no informational statuses). + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_TLB_CATCH_WRITE and *ppv set if the page has a write + * access handler of some kind. + * @retval VERR_PGM_PHYS_TLB_CATCH_ALL if the page has a handler catching all + * accesses or is odd in any way. + * @retval VERR_PGM_PHYS_TLB_UNASSIGNED if the page doesn't exist. + * + * @param pVM Pointer to the VM. + * @param GCPhys The GC physical address to convert. Since this is only + * used for filling the REM TLB, the A20 mask must be + * applied before calling this API. + * @param fWritable Whether write access is required. + * + * @remarks This is a watered down version PGMPhysIemGCPhys2Ptr and really just + * a stop gap thing that should be removed once there is a better TLB + * for virtual address accesses. + */ +VMM_INT_DECL(int) PGMPhysIemQueryAccess(PVM pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers) +{ + pgmLock(pVM); + PGM_A20_ASSERT_MASKED(VMMGetCpu(pVM), GCPhys); + + PPGMRAMRANGE pRam; + PPGMPAGE pPage; + int rc = pgmPhysGetPageAndRangeEx(pVM, GCPhys, &pPage, &pRam); + if (RT_SUCCESS(rc)) + { + if (PGM_PAGE_IS_BALLOONED(pPage)) + rc = VERR_PGM_PHYS_TLB_CATCH_WRITE; + else if (PGM_PAGE_IS_SPECIAL_ALIAS_MMIO(pPage)) + rc = VERR_PGM_PHYS_TLB_CATCH_ALL; + else if ( !PGM_PAGE_HAS_ANY_HANDLERS(pPage) + || (fByPassHandlers && !PGM_PAGE_IS_MMIO(pPage)) ) + rc = VINF_SUCCESS; + else + { + if (PGM_PAGE_HAS_ACTIVE_ALL_HANDLERS(pPage)) /* catches MMIO */ + { + Assert(!fByPassHandlers || PGM_PAGE_IS_MMIO(pPage)); + rc = VERR_PGM_PHYS_TLB_CATCH_ALL; + } + else if (PGM_PAGE_HAS_ACTIVE_HANDLERS(pPage) && fWritable) + { + Assert(!fByPassHandlers); + rc = VERR_PGM_PHYS_TLB_CATCH_WRITE; + } + } + } + + pgmUnlock(pVM); + return rc; +} + |
