PGMR0.cpp revision 73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/* $Id$ */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/** @file
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * PGM - Page Manager and Monitor, Ring-0.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2007 Oracle Corporation
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync *
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * available from http://www.virtualbox.org. This file is free software;
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * 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.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/*******************************************************************************
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync* Header Files *
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync*******************************************************************************/
f84cd77241a1c4b9106a92280611c659243e10d1vboxsync#define LOG_GROUP LOG_GROUP_PGM
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <VBox/pgm.h>
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync#include <VBox/gmm.h>
d31ded334a29f575e23dc889b603b1a586759348vboxsync#include "../PGMInternal.h"
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <VBox/vm.h>
d31ded334a29f575e23dc889b603b1a586759348vboxsync#include "../PGMInline.h"
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <VBox/log.h>
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <VBox/err.h>
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <iprt/assert.h>
209c11e4b5dbb310116c99a42d773163928e002bvboxsync#include <iprt/mem.h>
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncRT_C_DECLS_BEGIN
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#include "PGMR0Bth.h"
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync#undef PGM_BTH_NAME
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#include "PGMR0Bth.h"
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync#undef PGM_BTH_NAME
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#include "PGMR0Bth.h"
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync#undef PGM_BTH_NAME
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PROT(name)
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync#include "PGMR0Bth.h"
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync#undef PGM_BTH_NAME
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncRT_C_DECLS_END
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
6420f75ffc86ab6494eb5e95418f0c95e71e8068vboxsync/**
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * Worker function for PGMR3PhysAllocateHandyPages and pgmPhysEnsureHandyPage.
6420f75ffc86ab6494eb5e95418f0c95e71e8068vboxsync *
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * @returns The following VBox status codes.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * @retval VINF_SUCCESS on success. FF cleared.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * @retval VINF_EM_NO_MEMORY if we're out of memory. The FF is set in this case.
6420f75ffc86ab6494eb5e95418f0c95e71e8068vboxsync *
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * @param pVM The VM handle.
faf968cea88f2ab4bcc3325b17bc8b095a8e3642vboxsync * @param pVCpu The VMCPU handle.
6420f75ffc86ab6494eb5e95418f0c95e71e8068vboxsync *
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync * @remarks Must be called from within the PGM critical section. The caller
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync * must clear the new pages.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync */
faf968cea88f2ab4bcc3325b17bc8b095a8e3642vboxsyncVMMR0DECL(int) PGMR0PhysAllocateHandyPages(PVM pVM, PVMCPU pVCpu)
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync{
faf968cea88f2ab4bcc3325b17bc8b095a8e3642vboxsync Assert(PDMCritSectIsOwnerEx(&pVM->pgm.s.CritSect, pVCpu->idCpu));
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync /*
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync * Check for error injection.
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync */
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync if (RT_UNLIKELY(pVM->pgm.s.fErrInjHandyPages))
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync return VERR_NO_MEMORY;
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync /*
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync * Try allocate a full set of handy pages.
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync */
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync uint32_t iFirst = pVM->pgm.s.cHandyPages;
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync AssertReturn(iFirst <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), VERR_INTERNAL_ERROR);
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync uint32_t cPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages) - iFirst;
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync if (!cPages)
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync return VINF_SUCCESS;
f94f82d66536c7332c347dd9a3a9f0f8c79247f4vboxsync int rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, cPages, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync if (RT_SUCCESS(rc))
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync {
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync {
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync }
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync pVM->pgm.s.cHandyPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages);
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync }
0d4bc23ca3867d6dbedd76d5b1e3725c766adb75vboxsync else if (rc != VERR_GMM_SEED_ME)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync if ( ( rc == VERR_GMM_HIT_GLOBAL_LIMIT
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync || rc == VERR_GMM_HIT_VM_ACCOUNT_LIMIT)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync && iFirst < PGM_HANDY_PAGES_MIN)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync#ifdef VBOX_STRICT
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync /* We're ASSUMING that GMM has updated all the entires before failing us. */
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync uint32_t i;
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync for (i = iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync }
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync#endif
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync /*
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync * Reduce the number of pages until we hit the minimum limit.
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync */
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync do
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync cPages >>= 2;
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync if (cPages + iFirst < PGM_HANDY_PAGES_MIN)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync cPages = PGM_HANDY_PAGES_MIN - iFirst;
f94f82d66536c7332c347dd9a3a9f0f8c79247f4vboxsync rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, cPages, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync } while ( ( rc == VERR_GMM_HIT_GLOBAL_LIMIT
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync || rc == VERR_GMM_HIT_VM_ACCOUNT_LIMIT)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync && cPages + iFirst > PGM_HANDY_PAGES_MIN);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync if (RT_SUCCESS(rc))
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync#ifdef VBOX_STRICT
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync i = iFirst + cPages;
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync while (i-- > 0)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync }
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync for (i = cPages + iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync }
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync#endif
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync pVM->pgm.s.cHandyPages = iFirst + cPages;
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync }
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync }
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync if (RT_FAILURE(rc) && rc != VERR_GMM_SEED_ME)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync {
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync LogRel(("PGMR0PhysAllocateHandyPages: rc=%Rrc iFirst=%d cPages=%d\n", rc, iFirst, cPages));
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync VM_FF_SET(pVM, VM_FF_PGM_NO_MEMORY);
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync }
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync }
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync LogFlow(("PGMR0PhysAllocateHandyPages: cPages=%d rc=%Rrc\n", cPages, rc));
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync return rc;
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync}
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync/**
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * Worker function for PGMR3PhysAllocateLargeHandyPage
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync *
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * @returns The following VBox status codes.
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * @retval VINF_SUCCESS on success.
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * @retval VINF_EM_NO_MEMORY if we're out of memory.
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync *
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * @param pVM The VM handle.
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * @param pVCpu The VMCPU handle.
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync *
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * @remarks Must be called from within the PGM critical section. The caller
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync * must clear the new pages.
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync */
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsyncVMMR0DECL(int) PGMR0PhysAllocateLargeHandyPage(PVM pVM, PVMCPU pVCpu)
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync{
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync Assert(PDMCritSectIsOwnerEx(&pVM->pgm.s.CritSect, pVCpu->idCpu));
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync Assert(!pVM->pgm.s.cLargeHandyPages);
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync int rc = GMMR0AllocateLargePage(pVM, pVCpu->idCpu, _2M, &pVM->pgm.s.aLargeHandyPage[0].idPage, &pVM->pgm.s.aLargeHandyPage[0].HCPhysGCPhys);
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync if (RT_SUCCESS(rc))
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync pVM->pgm.s.cLargeHandyPages = 1;
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync return rc;
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync}
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync/**
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * #PF Handler for nested paging.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync *
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @returns VBox status code (appropriate for trap handling and GC return).
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @param pVM VM Handle.
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * @param pVCpu VMCPU Handle.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @param enmShwPagingMode Paging mode for the nested page tables
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @param uErr The trap error code.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @param pRegFrame Trap register frame.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @param pvFault The fault address.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync */
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsyncVMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, PCPUMCTXCORE pRegFrame, RTGCPHYS pvFault)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync{
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync int rc;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
853e60357f021457980af0726d25a40ecd3c0107vboxsync LogFlow(("PGMTrap0eHandler: uErr=%RGx pvFault=%RGp eip=%RGv\n", uErr, pvFault, (RTGCPTR)pRegFrame->rip));
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0e, a);
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = NULL; } );
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync /* AMD uses the host's paging mode; Intel has a single mode (EPT). */
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync AssertMsg(enmShwPagingMode == PGMMODE_32_BIT || enmShwPagingMode == PGMMODE_PAE || enmShwPagingMode == PGMMODE_PAE_NX || enmShwPagingMode == PGMMODE_AMD64 || enmShwPagingMode == PGMMODE_AMD64_NX || enmShwPagingMode == PGMMODE_EPT, ("enmShwPagingMode=%d\n", enmShwPagingMode));
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#ifdef VBOX_WITH_STATISTICS
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /*
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * Error code stats.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (uErr & X86_TRAP_PF_US)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync {
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (!(uErr & X86_TRAP_PF_P))
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync {
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (uErr & X86_TRAP_PF_RW)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSNotPresentWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSNotPresentRead);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RW)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RSVD)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSReserved);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_ID)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSNXE);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eUSRead);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync { /* Supervisor */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (!(uErr & X86_TRAP_PF_P))
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync {
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (uErr & X86_TRAP_PF_RW)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVNotPresentWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVNotPresentRead);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RW)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_ID)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSNXE);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RSVD)
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.StatRZTrap0eSVReserved);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#endif
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /*
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * Call the worker.
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync *
9ad5e3912962c3dbccc1afc4e7d62890fe906814vboxsync * We pretend the guest is in protected mode without paging, so we can use existing code to build the
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync * nested page tables.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync */
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync bool fLockTaken = false;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync switch(enmShwPagingMode)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync {
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync case PGMMODE_32_BIT:
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync rc = PGM_BTH_NAME_32BIT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, pvFault, &fLockTaken);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync break;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync case PGMMODE_PAE:
50fdc90dae026b2086f85b0f028aa63dd6bbe14evboxsync case PGMMODE_PAE_NX:
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync rc = PGM_BTH_NAME_PAE_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, pvFault, &fLockTaken);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync break;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync case PGMMODE_AMD64:
50fdc90dae026b2086f85b0f028aa63dd6bbe14evboxsync case PGMMODE_AMD64_NX:
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync rc = PGM_BTH_NAME_AMD64_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, pvFault, &fLockTaken);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync break;
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync case PGMMODE_EPT:
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync rc = PGM_BTH_NAME_EPT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, pvFault, &fLockTaken);
289060a0c3cb1d509f2cb01fca060796212376f6vboxsync break;
50fdc90dae026b2086f85b0f028aa63dd6bbe14evboxsync default:
50fdc90dae026b2086f85b0f028aa63dd6bbe14evboxsync AssertFailed();
e8ac7dce6d625856c57792a6af738e2fe2667264vboxsync rc = VERR_INVALID_PARAMETER;
50fdc90dae026b2086f85b0f028aa63dd6bbe14evboxsync break;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync if (fLockTaken)
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync {
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync Assert(PGMIsLockOwner(pVM));
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync pgmUnlock(pVM);
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync rc = VINF_SUCCESS;
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync else
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync /* Note: hack alert for difficult to reproduce problem. */
ae7f4100e4fa100f3ac68a77afc7cbdf89a5eb93vboxsync if ( rc == VERR_PAGE_NOT_PRESENT /* SMP only ; disassembly might fail. */
ae7f4100e4fa100f3ac68a77afc7cbdf89a5eb93vboxsync || rc == VERR_PAGE_TABLE_NOT_PRESENT /* seen with UNI & SMP */
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync || rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT /* seen with SMP */
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT) /* precaution */
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync {
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync Log(("WARNING: Unexpected VERR_PAGE_TABLE_NOT_PRESENT (%d) for page fault at %RGp error code %x (rip=%RGv)\n", rc, pvFault, uErr, pRegFrame->rip));
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync /* Some kind of inconsistency in the SMP case; it's safe to just execute the instruction again; not sure about single VCPU VMs though. */
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync rc = VINF_SUCCESS;
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync }
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_STATS({ if (!pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution))
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.StatRZTrap0eTime2Misc; });
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_PROFILE_STOP_EX(&pVCpu->pgm.s.StatRZTrap0e, pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync return rc;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync}
6f516ad9911d9037a18778742caa955fe362f8ffvboxsync
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync#ifdef VBOX_WITH_PAGE_SHARING
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync/**
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync * Check a registered module for shared page changes
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync *
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync * @returns The following VBox status codes.
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync *
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync * @param pVM The VM handle.
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync * @param idCpu VCPU id
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync * @param pModule Module description
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync * @param pGVM Pointer to the GVM instance data.
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsyncVMMR0DECL(int) PGMR0SharedModuleCheckRegion(PVM pVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, PGVM pGVM)
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync{
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync int rc = VINF_SUCCESS;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync PGMMSHAREDPAGEDESC paPageDesc = NULL;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync uint32_t cbPreviousRegion = 0;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync bool fFlushTLBs = false;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync PVMCPU pVCpu = &pVM->aCpus[idCpu];
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync Log(("PGMR0SharedModuleCheck: check %s %s base=%RGv size=%x\n", pModule->szName, pModule->szVersion, pModule->Core.Key, pModule->cbModule));
e7af1aba019c26bfd3e69e146884ad4b3daafa50vboxsync
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync pgmLock(pVM);
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync /* Check every region of the shared module. */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync for (unsigned i = 0; i < pModule->cRegions; i++)
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync Assert((pModule->aRegions[i].cbRegion & 0xfff) == 0);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync Assert((pModule->aRegions[i].GCRegionAddr & 0xfff) == 0);
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync RTGCPTR GCRegion = pModule->aRegions[i].GCRegionAddr;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync unsigned cbRegion = pModule->aRegions[i].cbRegion & ~0xfff;
209c11e4b5dbb310116c99a42d773163928e002bvboxsync unsigned idxPage = 0;
209c11e4b5dbb310116c99a42d773163928e002bvboxsync bool fValidChanges = false;
209c11e4b5dbb310116c99a42d773163928e002bvboxsync
209c11e4b5dbb310116c99a42d773163928e002bvboxsync if (cbPreviousRegion < cbRegion)
209c11e4b5dbb310116c99a42d773163928e002bvboxsync {
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync if (paPageDesc)
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync RTMemFree(paPageDesc);
209c11e4b5dbb310116c99a42d773163928e002bvboxsync
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync paPageDesc = (PGMMSHAREDPAGEDESC)RTMemAlloc((cbRegion >> PAGE_SHIFT) * sizeof(*paPageDesc));
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync if (!paPageDesc)
209c11e4b5dbb310116c99a42d773163928e002bvboxsync {
209c11e4b5dbb310116c99a42d773163928e002bvboxsync AssertFailed();
209c11e4b5dbb310116c99a42d773163928e002bvboxsync rc = VERR_NO_MEMORY;
209c11e4b5dbb310116c99a42d773163928e002bvboxsync goto end;
209c11e4b5dbb310116c99a42d773163928e002bvboxsync }
209c11e4b5dbb310116c99a42d773163928e002bvboxsync cbPreviousRegion = cbRegion;
209c11e4b5dbb310116c99a42d773163928e002bvboxsync }
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync while (cbRegion)
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync {
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync RTGCPHYS GCPhys;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync uint64_t fFlags;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync
ca74d6e1d76a5b1caf9a0b148306386821dadce8vboxsync rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys);
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync if ( rc == VINF_SUCCESS
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync && !(fFlags & X86_PTE_RW)) /* important as we make assumptions about this below! */
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync {
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync if ( pPage
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync && !PGM_PAGE_IS_SHARED(pPage))
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync {
209c11e4b5dbb310116c99a42d773163928e002bvboxsync fValidChanges = true;
2560ed0c999a3144e98992d4b2ee4e8803ae012avboxsync paPageDesc[idxPage].uHCPhysPageId = PGM_PAGE_GET_PAGEID(pPage);
2560ed0c999a3144e98992d4b2ee4e8803ae012avboxsync paPageDesc[idxPage].HCPhys = PGM_PAGE_GET_HCPHYS(pPage);
2560ed0c999a3144e98992d4b2ee4e8803ae012avboxsync paPageDesc[idxPage].GCPhys = GCPhys;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync }
209c11e4b5dbb310116c99a42d773163928e002bvboxsync else
2560ed0c999a3144e98992d4b2ee4e8803ae012avboxsync paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync }
209c11e4b5dbb310116c99a42d773163928e002bvboxsync else
2560ed0c999a3144e98992d4b2ee4e8803ae012avboxsync paPageDesc[idxPage].uHCPhysPageId = NIL_GMM_PAGEID;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync
209c11e4b5dbb310116c99a42d773163928e002bvboxsync idxPage++;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync GCRegion += PAGE_SIZE;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync cbRegion -= PAGE_SIZE;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync }
209c11e4b5dbb310116c99a42d773163928e002bvboxsync
209c11e4b5dbb310116c99a42d773163928e002bvboxsync if (fValidChanges)
209c11e4b5dbb310116c99a42d773163928e002bvboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync rc = GMMR0SharedModuleCheckRange(pGVM, pModule, i, idxPage, paPageDesc);
209c11e4b5dbb310116c99a42d773163928e002bvboxsync AssertRC(rc);
209c11e4b5dbb310116c99a42d773163928e002bvboxsync if (RT_FAILURE(rc))
209c11e4b5dbb310116c99a42d773163928e002bvboxsync break;
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync for (unsigned i = 0; i < idxPage; i++)
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync {
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync /* Any change for this page? */
2560ed0c999a3144e98992d4b2ee4e8803ae012avboxsync if (paPageDesc[i].uHCPhysPageId != NIL_GMM_PAGEID)
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync {
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync /** todo: maybe cache these to prevent the nth lookup. */
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, paPageDesc[i].GCPhys);
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync if (!pPage)
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync {
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync /* Should never happen. */
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync AssertFailed();
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync rc = VERR_PGM_PHYS_INVALID_PAGE_ID;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync goto end;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync }
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync Assert(!PGM_PAGE_IS_SHARED(pPage));
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync
e7af1aba019c26bfd3e69e146884ad4b3daafa50vboxsync Log(("PGMR0SharedModuleCheck: shared page gc phys %RGp host %RHp->%RHp\n", paPageDesc[i].GCPhys, PGM_PAGE_GET_HCPHYS(pPage), paPageDesc[i].HCPhys));
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync if (paPageDesc[i].HCPhys != PGM_PAGE_GET_HCPHYS(pPage))
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync {
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync bool fFlush = false;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync /* Page was replaced by an existing shared version of it; clear all references first. */
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync rc = pgmPoolTrackUpdateGCPhys(pVM, paPageDesc[i].GCPhys, pPage, true /* clear the entries */, &fFlush);
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync if (RT_FAILURE(rc))
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync {
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync AssertRC(rc);
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync goto end;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync }
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync Assert(rc == VINF_SUCCESS || (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_PGM_SYNC_CR3) && (pVCpu->pgm.s.fSyncFlags & PGM_SYNC_CLEAR_PGM_POOL)));
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync if (rc = VINF_SUCCESS)
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync fFlushTLBs |= fFlush;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync /* Update the physical address and page id now. */
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync PGM_PAGE_SET_HCPHYS(pPage, paPageDesc[i].HCPhys);
5879cb244b131c1e4b63ca7f27c4e026d7b96915vboxsync PGM_PAGE_SET_PAGEID(pPage, paPageDesc[i].uHCPhysPageId);
bc0229fce4e9f3a2938f0e8c680c3d92f78351dcvboxsync
bc0229fce4e9f3a2938f0e8c680c3d92f78351dcvboxsync /* Invalidate page map TLB entry for this page too. */
bc0229fce4e9f3a2938f0e8c680c3d92f78351dcvboxsync PGMPhysInvalidatePageMapTLBEntry(pVM, paPageDesc[i].GCPhys);
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync }
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync /* else nothing changed (== this page is now a shared page), so no need to flush anything. */
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync
ca5a32299eb0e3ca177357a3d220e091903aeb0evboxsync pVM->pgm.s.cSharedPages++;
54106f1abf765bf6d28cd59060aa8d3b82ca1308vboxsync pVM->pgm.s.cPrivatePages--;
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync PGM_PAGE_SET_STATE(pPage, PGM_PAGE_STATE_SHARED);
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync }
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync }
209c11e4b5dbb310116c99a42d773163928e002bvboxsync }
36f983274b743cb7749651f95a587130f8c81a4avboxsync else
36f983274b743cb7749651f95a587130f8c81a4avboxsync rc = VINF_SUCCESS; /* nothing to do. */
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync }
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync
209c11e4b5dbb310116c99a42d773163928e002bvboxsyncend:
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync pgmUnlock(pVM);
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync if (fFlushTLBs)
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync PGM_INVL_ALL_VCPU_TLBS(pVM);
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync if (paPageDesc)
e4d7b580d72e968d3753363ab36e196a968c1947vboxsync RTMemFree(paPageDesc);
209c11e4b5dbb310116c99a42d773163928e002bvboxsync
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync return rc;
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync}
9d7fdfd90ef8d681a2d2c339339e8dc0b1fc5bd3vboxsync#endif
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync#if 0
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync/**
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync * Shared module registration helper (called on the way out).
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync *
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync * @param pVM The VM handle.
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync * @param pReq Registration request info
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsyncstatic DECLCALLBACK(void) pgmR3SharedModuleRegisterHelper(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq)
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync{
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync int rc;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync rc = GMMR3RegisterSharedModule(pVM, pReq);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync Assert(rc == VINF_SUCCESS || rc == VINF_PGM_SHARED_MODULE_COLLISION || rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync if (rc == VINF_PGM_SHARED_MODULE_ALREADY_REGISTERED)
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync PVMCPU pVCpu = VMMGetCpu(pVM);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync unsigned cFlushedPages = 0;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync /** todo count copy-on-write actions in the trap handler so we don't have to check everything all the time! */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync /* Count the number of shared pages that were changed (copy-on-write). */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync for (unsigned i = 0; i < pReq->cRegions; i++)
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync Assert((pReq->aRegions[i].cbRegion & 0xfff) == 0);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync Assert((pReq->aRegions[i].GCRegionAddr & 0xfff) == 0);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync RTGCPTR GCRegion = pReq->aRegions[i].GCRegionAddr;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync uint32_t cbRegion = pReq->aRegions[i].cbRegion & ~0xfff;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync while (cbRegion)
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync RTGCPHYS GCPhys;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync uint64_t fFlags;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync rc = PGMGstGetPage(pVCpu, GCRegion, &fFlags, &GCPhys);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync if ( rc == VINF_SUCCESS
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync && !(fFlags & X86_PTE_RW))
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync PPGMPAGE pPage = pgmPhysGetPage(&pVM->pgm.s, GCPhys);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync if ( pPage
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync && !PGM_PAGE_IS_SHARED(pPage))
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync cFlushedPages++;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync }
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync }
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync GCRegion += PAGE_SIZE;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync cbRegion -= PAGE_SIZE;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync }
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync }
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync if (cFlushedPages > 32)
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync rc = VINF_SUCCESS; /* force recheck below */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync }
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync /* Full (re)check needed? */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync if (rc == VINF_SUCCESS)
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync {
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync pReq->Hdr.u32Magic = SUPVMMR0REQHDR_MAGIC;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync pReq->Hdr.cbReq = RT_OFFSETOF(GMMREGISTERSHAREDMODULEREQ, aRegions[pReq->cRegions]);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync /* We must stall other VCPUs as we'd otherwise have to send IPI flush commands for every single change we make. */
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync rc = VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE, pgmR3SharedModuleRegRendezvous, pReq);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync AssertRC(rc);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync }
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync RTMemFree(pReq);
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync return;
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync}
73c74bb1e8e8a8c2f26c69cb20f7666fcb72b1f0vboxsync#endif