PGMAllGst.h revision 9f9a20823b87e89c1b5cb45eb9b5699b29bfefeb
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync * VBox - Page Manager, Guest Paging Template - All context code.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2010 Oracle Corporation
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * available from http://www.virtualbox.org. This file is free software;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync/*******************************************************************************
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync* Internal Functions *
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync*******************************************************************************/
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncstatic int PGM_GST_NAME(Walk)(PVMCPU pVCpu, RTGCPTR GCPtr, PGSTPTWALK pWalk);
da957c069c2a3c582fe265ff88170ce4c42b499dvboxsyncPGM_GST_DECL(int, GetPage)(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncPGM_GST_DECL(int, ModifyPage)(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncPGM_GST_DECL(int, GetPDE)(PVMCPU pVCpu, RTGCPTR GCPtr, PX86PDEPAE pPDE);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncPGM_GST_DECL(bool, HandlerVirtualUpdate)(PVM pVM, uint32_t cr4);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncDECLINLINE(int) PGM_GST_NAME(WalkReturnNotPresent)(PVMCPU pVCpu, PGSTPTWALK pWalk, int iLevel)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncDECLINLINE(int) PGM_GST_NAME(WalkReturnBadPhysAddr)(PVMCPU pVCpu, PGSTPTWALK pWalk, int rc, int iLevel)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync AssertMsg(rc == VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS, ("%Rrc\n", rc));
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncDECLINLINE(int) PGM_GST_NAME(WalkReturnRsvdError)(PVMCPU pVCpu, PGSTPTWALK pWalk, int iLevel)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Performs a guest page table walk.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns VBox status code.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @retval VINF_SUCCESS on success.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @retval VERR_PAGE_TABLE_NOT_PRESENT on failure. Check pWalk for details.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @param pVCpu The current CPU.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @param GCPtr The guest virtual address to walk by.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * @param pWalk Where to return the walk result. This is always set.
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsyncstatic int PGM_GST_NAME(Walk)(PVMCPU pVCpu, RTGCPTR GCPtr, PGSTPTWALK pWalk)
fe96bc0e43d9c137304462ef8c2d79cbff22446fvboxsync * Init the walking structure.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Boundary check for PAE and 32-bit (prevents trouble further down).
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 8);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * The PMLE4.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync rc = pgmGstGetLongModePML4PtrEx(pVCpu, &pWalk->pPml4);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 4, rc);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pWalk->pPml4e = pPml4e = &pPml4->a[(GCPtr >> X86_PML4_SHIFT) & X86_PML4_MASK];
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 4);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync if (RT_UNLIKELY(!GST_IS_PML4E_VALID(pVCpu, Pml4e)))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 4);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync * The PDPE.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, Pml4e.u & X86_PML4E_PG_MASK, &pWalk->pPdpt);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 3, rc);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 8, rc);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
aa32d4906f2f685992091893d5abdf27a2352a85vboxsync pWalk->pPdpe = pPdpe = &pPdpt->a[(GCPtr >> GST_PDPT_SHIFT) & GST_PDPT_MASK];
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 3);
e3f5c51715cbf77ae2d2e9d05bafd00d69b1bec9vboxsync return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 3);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, Pdpe.u & X86_PDPE_PG_MASK, &pWalk->pPd);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 2, rc);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 8, rc);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pWalk->pPde = pPde = &pPd->a[(GCPtr >> GST_PD_SHIFT) & GST_PD_MASK];
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 2);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync if (RT_UNLIKELY(!GST_IS_BIG_PDE_VALID(pVCpu, Pde)))
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 2);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pWalk->Core.GCPhys = GST_GET_BIG_PDE_GCPHYS(pVCpu->CTX_SUFF(pVM), Pde)
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pWalk->Core.fEffectiveRW = !!(fEffectiveXX & X86_PTE_RW);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync pWalk->Core.fEffectiveUS = !!(fEffectiveXX & X86_PTE_US);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync pWalk->Core.fEffectiveNX = ( pWalk->Pde.n.u1NoExecute
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 2);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync rc = PGM_GCPHYS_2_PTR_BY_VMCPU(pVCpu, GST_GET_PDE_GCPHYS(Pde), &pWalk->pPt);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PGM_GST_NAME(WalkReturnBadPhysAddr)(pVCpu, pWalk, 1, rc);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pWalk->pPte = pPte = &pPt->a[(GCPtr >> GST_PT_SHIFT) & GST_PT_MASK];
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PGM_GST_NAME(WalkReturnNotPresent)(pVCpu, pWalk, 1);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync return PGM_GST_NAME(WalkReturnRsvdError)(pVCpu, pWalk, 1);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * We're done.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pWalk->Core.fEffectiveRW = !!(fEffectiveXX & X86_PTE_RW);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync pWalk->Core.fEffectiveUS = !!(fEffectiveXX & X86_PTE_US);
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync# if PGM_GST_TYPE == PGM_TYPE_AMD64 || PGM_GST_TYPE == PGM_TYPE_PAE
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync pWalk->Core.fEffectiveNX = ( pWalk->Pte.n.u1NoExecute
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync#endif /* 32BIT, PAE, AMD64 */
b7a5b3f9f9ecce32ddacf8404c625ce0451bbdc1vboxsync * Gets effective Guest OS page information.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * When GCPtr is in a big page, the function will return as if it was a normal
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * 4KB page. If the need for distinguishing between big and normal page becomes
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * necessary at a later point, a PGMGstGetPage Ex() will be created for that
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @returns VBox status.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pVCpu The VMCPU handle.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param GCPtr Guest Context virtual address of the page.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pfFlags Where to store the flags. These are X86_PTE_*, even for big pages.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pGCPhys Where to store the GC physical address of the page.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * This is page aligned!
b1cc88518a7578ee20491f3d97b9792c24c6428dvboxsyncPGM_GST_DECL(int, GetPage)(PVMCPU pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTGCPHYS pGCPhys)
362838d79d234a41380be42aae9118850cc3c929vboxsync *pGCPhys = Walk.Core.GCPhys & ~(RTGCPHYS)PAGE_OFFSET_MASK;
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync *pfFlags = (Walk.Pte.u & ~(GST_PTE_PG_MASK | X86_PTE_RW | X86_PTE_US)) /* NX not needed */
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync *pfFlags = (Walk.Pde.u & ~(GST_PTE_PG_MASK | X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PS)) /* NX not needed */
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync | ((Walk.Pde.u & X86_PDE4M_PAT) >> X86_PDE4M_PAT_SHIFT)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* something else... */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Modify page flags for a range of pages in the guest's tables
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * The existing flags are ANDed with the fMask and ORed with the fFlags.
22bdb1ce26b2d5a41d1b071c16f1078e5348bb0dvboxsync * @returns VBox status code.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pVCpu The VMCPU handle.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param GCPtr Virtual address of the first page in the range. Page aligned!
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param cb Size (in bytes) of the page range to apply the modification to. Page aligned!
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param fFlags The OR mask - page flags X86_PTE_*, excluding the page mask of course.
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * @param fMask The AND mask - page flags X86_PTE_*.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncPGM_GST_DECL(int, ModifyPage)(PVMCPU pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask)
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * 4KB Page table, process
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync * Walk pages till we're done.
801238b286a80a5dd67ba56a1f26c0bc98a2a1eavboxsync unsigned iPTE = (GCPtr >> GST_PT_SHIFT) & GST_PT_MASK;
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync Pte.u = (Pte.u & (fMask | X86_PTE_PAE_PG_MASK_FULL))
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /* next page */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * 2/4MB Page table
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PdeNew.u = (Walk.Pde.u & (fMask | ((fMask & X86_PTE_PAT) << X86_PDE4M_PAT_SHIFT) | GST_PDE_BIG_PG_MASK | X86_PDE4M_PG_HIGH_MASK | X86_PDE4M_PS))
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PdeNew.u = (Walk.Pde.u & (fMask | ((fMask & X86_PTE_PAT) << X86_PDE4M_PAT_SHIFT) | GST_PDE_BIG_PG_MASK | X86_PDE4M_PS))
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync /* advance */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync const unsigned cbDone = GST_BIG_PAGE_SIZE - (GCPtr & GST_BIG_PAGE_OFFSET_MASK);
914d33aebb63d8c288dfd1b7e74f8e2acf3eaa66vboxsync /* real / protected mode: ignore. */
548ca31b6b47c36bacce49bed3339cb8075b9681vboxsync * Retrieve guest PDE information.
97dc0e92bcc0cddf896cbf620b689b095c7346davboxsync * @returns VBox status code.
97dc0e92bcc0cddf896cbf620b689b095c7346davboxsync * @param pVCpu The VMCPU handle.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param GCPtr Guest context pointer.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pPDE Pointer to guest PDE structure.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsyncPGM_GST_DECL(int, GetPDE)(PVMCPU pVCpu, RTGCPTR GCPtr, PX86PDEPAE pPDE)
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* Boundary check. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync unsigned iPd = (GCPtr >> GST_PD_SHIFT) & GST_PD_MASK;
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PCX86PDPAE pPd = pgmGstGetPaePDPtr(pVCpu, GCPtr, &iPd, NULL);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync PCX86PDPAE pPd = pgmGstGetLongModePDPtr(pVCpu, GCPtr, &pPml4eIgn, &PdpeIgn, &iPd);
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync /* Note! We do not return an effective PDE here like we do for the PTE in GetPage method. */
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * Updates one virtual handler range.
cba6719bd64ec749967bbe931230452664109857vboxsync * @returns 0
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pNode Pointer to a PGMVIRTHANDLER.
5b1d6bab9f4cf5dacf1883e7c4a40c84349f597fvboxsync * @param pvUser Pointer to a PGMVHUARGS structure (see PGM.cpp).
static DECLCALLBACK(int) PGM_GST_NAME(VirtHandlerUpdateOne)(PAVLROGCPTRNODECORE pNode, void *pvUser)
unsigned iPage = 0;
&& ( !fBigPage
if (!fBigPage)
("{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} GCPhysNew=%RGp\n",
offPage = 0;
("{.Core.Key=%RGp, .Core.KeyLast=%RGp, .offVirtHandler=%#RX32, .offNextAlias=%#RX32} GCPhysNew=%RGp\n",
offPage = 0;
RTAvlroGCPtrDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, true, PGM_GST_NAME(VirtHandlerUpdateOne), &State);
RTAvlroGCPtrDoWithAll(&pVM->pgm.s.CTX_SUFF(pTrees)->VirtHandlers, true, pgmHandlerVirtualResetOne, pVM);