PGMR0.cpp revision 19d274949f66f4797eb8850fe9c8de3e6ec931e8
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/* $Id$ */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/** @file
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * PGM - Page Manager and Monitor, Ring-0.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*
506df97a8c78dacfe69bc4d3ee5d3de832d0f19avboxsync * Copyright (C) 2007-2011 Oracle Corporation
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * available from http://www.virtualbox.org. This file is free software;
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * you can redistribute it and/or modify it under the terms of the GNU
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * General Public License (GPL) as published by the Free Software
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Header Files *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define LOG_GROUP LOG_GROUP_PGM
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <VBox/rawpci.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pgm.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/gmm.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <VBox/vmm/gvm.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "PGMInternal.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <VBox/vmm/vm.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "PGMInline.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <VBox/log.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <VBox/err.h>
506df97a8c78dacfe69bc4d3ee5d3de832d0f19avboxsync#include <iprt/assert.h>
506df97a8c78dacfe69bc4d3ee5d3de832d0f19avboxsync#include <iprt/mem.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Instantiate the ring-0 header/code templates.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_32BIT_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "PGMR0Bth.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#undef PGM_BTH_NAME
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_PAE_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "PGMR0Bth.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#undef PGM_BTH_NAME
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_AMD64_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "PGMR0Bth.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#undef PGM_BTH_NAME
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PGM_BTH_NAME(name) PGM_BTH_NAME_EPT_PROT(name)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "PGMR0Bth.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#undef PGM_BTH_NAME
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Worker function for PGMR3PhysAllocateHandyPages and pgmPhysEnsureHandyPage.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns The following VBox status codes.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_SUCCESS on success. FF cleared.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_EM_NO_MEMORY if we're out of memory. The FF is set in this case.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @remarks Must be called from within the PGM critical section. The caller
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * must clear the new pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(int) PGMR0PhysAllocateHandyPages(PVM pVM, PVMCPU pVCpu)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PGM_LOCK_ASSERT_OWNER_EX(pVM, pVCpu);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Check for error injection.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_UNLIKELY(pVM->pgm.s.fErrInjHandyPages))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VERR_NO_MEMORY;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Try allocate a full set of handy pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync uint32_t iFirst = pVM->pgm.s.cHandyPages;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(iFirst <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), VERR_PGM_HANDY_PAGE_IPE);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync uint32_t cPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages) - iFirst;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (!cPages)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, cPages, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_SUCCESS(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef VBOX_STRICT
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (uint32_t i = 0; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pVM->pgm.s.cHandyPages = RT_ELEMENTS(pVM->pgm.s.aHandyPages);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (rc != VERR_GMM_SEED_ME)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if ( ( rc == VERR_GMM_HIT_GLOBAL_LIMIT
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_GMM_HIT_VM_ACCOUNT_LIMIT)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && iFirst < PGM_HANDY_PAGES_MIN)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef VBOX_STRICT
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* We're ASSUMING that GMM has updated all the entires before failing us. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync uint32_t i;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (i = iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Reduce the number of pages until we hit the minimum limit.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync do
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync cPages >>= 1;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (cPages + iFirst < PGM_HANDY_PAGES_MIN)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync cPages = PGM_HANDY_PAGES_MIN - iFirst;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, 0, cPages, &pVM->pgm.s.aHandyPages[iFirst]);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync } while ( ( rc == VERR_GMM_HIT_GLOBAL_LIMIT
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_GMM_HIT_VM_ACCOUNT_LIMIT)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && cPages + iFirst > PGM_HANDY_PAGES_MIN);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_SUCCESS(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef VBOX_STRICT
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync i = iFirst + cPages;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync while (i-- > 0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage != NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage <= GMM_PAGEID_LAST);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys != NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (i = cPages + iFirst; i < RT_ELEMENTS(pVM->pgm.s.aHandyPages); i++)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].idSharedPage == NIL_GMM_PAGEID);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys == NIL_RTHCPHYS);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pVM->pgm.s.cHandyPages = iFirst + cPages;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_FAILURE(rc) && rc != VERR_GMM_SEED_ME)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogRel(("PGMR0PhysAllocateHandyPages: rc=%Rrc iFirst=%d cPages=%d\n", rc, iFirst, cPages));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VM_FF_SET(pVM, VM_FF_PGM_NO_MEMORY);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogFlow(("PGMR0PhysAllocateHandyPages: cPages=%d rc=%Rrc\n", cPages, rc));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Worker function for PGMR3PhysAllocateLargeHandyPage
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns The following VBox status codes.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_SUCCESS on success.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @retval VINF_EM_NO_MEMORY if we're out of memory.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @remarks Must be called from within the PGM critical section. The caller
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * must clear the new pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(int) PGMR0PhysAllocateLargeHandyPage(PVM pVM, PVMCPU pVCpu)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PGM_LOCK_ASSERT_OWNER_EX(pVM, pVCpu);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!pVM->pgm.s.cLargeHandyPages);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc = GMMR0AllocateLargePage(pVM, pVCpu->idCpu, _2M,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync &pVM->pgm.s.aLargeHandyPage[0].idPage,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync &pVM->pgm.s.aLargeHandyPage[0].HCPhysGCPhys);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_SUCCESS(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pVM->pgm.s.cLargeHandyPages = 1;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef VBOX_WITH_PCI_PASSTHROUGH
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/* Interface sketch. The interface belongs to a global PCI pass-through
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync manager. It shall use the global VM handle, not the user VM handle to
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync store the per-VM info (domain) since that is all ring-0 stuff, thus
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync passing pGVM here. I've tentitively prefixed the functions 'GPciRawR0',
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync we can discuss the PciRaw code re-organtization when I'm back from
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync vacation.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync I've implemented the initial IOMMU set up below. For things to work
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync reliably, we will probably need add a whole bunch of checks and
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync GPciRawR0GuestPageUpdate call to the PGM code. For the present,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync assuming nested paging (enforced) and prealloc (enforced), no
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync ballooning (check missing), page sharing (check missing) or live
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync migration (check missing), it might work fine. At least if some
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VM power-off hook is present and can tear down the IOMMU page tables. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Tells the global PCI pass-through manager that we are about to set up the
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * guest page to host page mappings for the specfied VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageBeginAssignments(PGVM pGVM)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync NOREF(pGVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Assigns a host page mapping for a guest page.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * This is only used when setting up the mappings, i.e. between
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * GPciRawR0GuestPageBeginAssignments and GPciRawR0GuestPageEndAssignments.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhys The address of the guest page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param HCPhys The address of the host page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageAssign(PGVM pGVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(HCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (pGVM->rawpci.s.pfnContigMemInfo)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** @todo: what do we do on failure? */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pGVM->rawpci.s.pfnContigMemInfo(&pGVM->rawpci.s, HCPhys, GCPhys, PAGE_SIZE, PCIRAW_MEMINFO_MAP);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Indicates that the specified guest page doesn't exists but doesn't have host
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * page mapping we trust PCI pass-through with.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * This is only used when setting up the mappings, i.e. between
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * GPciRawR0GuestPageBeginAssignments and GPciRawR0GuestPageEndAssignments.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhys The address of the guest page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param HCPhys The address of the host page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageUnassign(PGVM pGVM, RTGCPHYS GCPhys)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (pGVM->rawpci.s.pfnContigMemInfo)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** @todo: what do we do on failure? */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pGVM->rawpci.s.pfnContigMemInfo(&pGVM->rawpci.s, 0, GCPhys, PAGE_SIZE, PCIRAW_MEMINFO_UNMAP);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Tells the global PCI pass-through manager that we have completed setting up
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * the guest page to host page mappings for the specfied VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * This complements GPciRawR0GuestPageBeginAssignments and will be called even
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * if some page assignment failed.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageEndAssignments(PGVM pGVM)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync NOREF(pGVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Tells the global PCI pass-through manager that a guest page mapping has
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * changed after the initial setup.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pGVM The ring-0 VM structure.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhys The address of the guest page (page aligned).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param HCPhys The new host page address or NIL_RTHCPHYS if
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * now unassigned.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageUpdate(PGVM pGVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_4);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertReturn(!(HCPhys & PAGE_OFFSET_MASK) || HCPhys == NIL_RTHCPHYS, VERR_INTERNAL_ERROR_4);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync NOREF(pGVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif /* VBOX_WITH_PCI_PASSTHROUGH */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Sets up the IOMMU when raw PCI device is enabled.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @note This is a hack that will probably be remodelled and refined later!
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0_INT_DECL(int) PGMR0PhysSetupIommu(PVM pVM)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PGVM pGVM;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc = GVMMR0ByVM(pVM, &pGVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_FAILURE(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef VBOX_WITH_PCI_PASSTHROUGH
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (pVM->pgm.s.fPciPassthrough)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * The Simplistic Approach - Enumerate all the pages and call tell the
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * IOMMU about each of them.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmLock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = GPciRawR0GuestPageBeginAssignments(pGVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_SUCCESS(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR0; RT_SUCCESS(rc) && pRam; pRam = pRam->pNextR0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PPGMPAGE pPage = &pRam->aPages[0];
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync RTGCPHYS GCPhys = pRam->GCPhys;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync uint32_t cLeft = pRam->cb >> PAGE_SHIFT;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync while (cLeft-- > 0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Only expose pages that are 100% safe for now. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && !PGM_PAGE_HAS_ANY_HANDLERS(pPage))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = GPciRawR0GuestPageAssign(pGVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = GPciRawR0GuestPageUnassign(pGVM, GCPhys);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* next */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pPage++;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync GCPhys += PAGE_SIZE;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc2 = GPciRawR0GuestPageEndAssignments(pGVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = rc2;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmUnlock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = VERR_NOT_SUPPORTED;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * #PF Handler for nested paging.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code (appropriate for trap handling and GC return).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param enmShwPagingMode Paging mode for the nested page tables.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param uErr The trap error code.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pRegFrame Trap register frame.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhysFault The fault address.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync int rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync LogFlow(("PGMTrap0eHandler: uErr=%RGx GCPhysFault=%RGp eip=%RGv\n", uErr, GCPhysFault, (RTGCPTR)pRegFrame->rip));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_START(&pVCpu->pgm.s.StatRZTrap0e, a);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_STATS({ pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = NULL; } );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* AMD uses the host's paging mode; Intel has a single mode (EPT). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertMsg( enmShwPagingMode == PGMMODE_32_BIT || enmShwPagingMode == PGMMODE_PAE || enmShwPagingMode == PGMMODE_PAE_NX
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || enmShwPagingMode == PGMMODE_AMD64 || enmShwPagingMode == PGMMODE_AMD64_NX || enmShwPagingMode == PGMMODE_EPT,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync ("enmShwPagingMode=%d\n", enmShwPagingMode));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Reserved shouldn't end up here. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!(uErr & X86_TRAP_PF_RSVD));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef VBOX_WITH_STATISTICS
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Error code stats.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (uErr & X86_TRAP_PF_US)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (!(uErr & X86_TRAP_PF_P))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (uErr & X86_TRAP_PF_RW)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentRead);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (uErr & X86_TRAP_PF_RW)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (uErr & X86_TRAP_PF_RSVD)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSReserved);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (uErr & X86_TRAP_PF_ID)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNXE);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSRead);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync { /* Supervisor */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (!(uErr & X86_TRAP_PF_P))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (uErr & X86_TRAP_PF_RW)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentRead);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (uErr & X86_TRAP_PF_RW)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVWrite);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (uErr & X86_TRAP_PF_ID)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSNXE);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (uErr & X86_TRAP_PF_RSVD)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVReserved);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Call the worker.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Note! We pretend the guest is in protected mode without paging, so we
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * can use existing code to build the nested page tables.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync bool fLockTaken = false;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync switch (enmShwPagingMode)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case PGMMODE_32_BIT:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_32BIT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync break;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case PGMMODE_PAE:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case PGMMODE_PAE_NX:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_PAE_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync break;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case PGMMODE_AMD64:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case PGMMODE_AMD64_NX:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_AMD64_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync break;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case PGMMODE_EPT:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = PGM_BTH_NAME_EPT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync break;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync default:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertFailed();
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = VERR_INVALID_PARAMETER;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync break;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (fLockTaken)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PGM_LOCK_ASSERT_OWNER(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmUnlock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Note: hack alert for difficult to reproduce problem. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if ( rc == VERR_PAGE_NOT_PRESENT /* SMP only ; disassembly might fail. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_PAGE_TABLE_NOT_PRESENT /* seen with UNI & SMP */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT /* seen with SMP */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT) /* precaution */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("WARNING: Unexpected VERR_PAGE_TABLE_NOT_PRESENT (%d) for page fault at %RGp error code %x (rip=%RGv)\n", rc, GCPhysFault, uErr, pRegFrame->rip));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Some kind of inconsistency in the SMP case; it's safe to just execute the instruction again; not sure about
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync single VCPU VMs though. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = VINF_SUCCESS;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_STATS({ if (!pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Misc; });
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_STOP_EX(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0e, pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/**
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * #PF Handler for deliberate nested paging misconfiguration (/reserved bit)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * employed for MMIO pages.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns VBox status code (appropriate for trap handling and GC return).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVM Pointer to the VM.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pVCpu Pointer to the VMCPU.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param enmShwPagingMode Paging mode for the nested page tables.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pRegFrame Trap register frame.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param GCPhysFault The fault address.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param uErr The error code, UINT32_MAX if not available
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * (VT-x).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncVMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, uint32_t uErr)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync{
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef PGM_WITH_MMIO_OPTIMIZATIONS
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_START(&pVCpu->CTX_SUFF(pStats)->StatR0NpMiscfg, a);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync VBOXSTRICTRC rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Try lookup the all access physical handler for the address.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmLock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PPGMPHYSHANDLER pHandler = pgmHandlerPhysicalLookup(pVM, GCPhysFault);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (RT_LIKELY(pHandler && pHandler->enmType != PGMPHYSHANDLERTYPE_PHYSICAL_WRITE))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * If the handle has aliases page or pages that have been temporarily
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * disabled, we'll have to take a detour to make sure we resync them
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * to avoid lots of unnecessary exits.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PPGMPAGE pPage;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if ( ( pHandler->cAliasedPages
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || pHandler->cTmpOffPages)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && ( (pPage = pgmPhysGetPage(pVM, GCPhysFault)) == NULL
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync )
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: Resyncing aliases / tmp-off page at %RGp (uErr=%#x) %R[pgmpage]\n", GCPhysFault, uErr, pPage));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfgSyncPage);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = pgmShwSyncNestedPageLocked(pVCpu, GCPhysFault, 1 /*cPages*/, enmShwPagingMode);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmUnlock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (pHandler->CTX_SUFF(pfnHandler))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync CTX_MID(PFNPGM,PHYSHANDLER) pfnHandler = pHandler->CTX_SUFF(pfnHandler);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync void *pvUser = pHandler->CTX_SUFF(pvUser);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_START(&pHandler->Stat, h);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmUnlock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log6(("PGMR0Trap0eHandlerNPMisconfig: calling %p(,%#x,,%RGp,%p)\n", pfnHandler, uErr, GCPhysFault, pvUser));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = pfnHandler(pVM, uErr == UINT32_MAX ? RTGCPTR_MAX : uErr, pRegFrame, GCPhysFault, GCPhysFault, pvUser);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef VBOX_WITH_STATISTICS
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmLock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pHandler = pgmHandlerPhysicalLookup(pVM, GCPhysFault);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (pHandler)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_STOP(&pHandler->Stat, h);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmUnlock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmUnlock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: %RGp (uErr=%#x) -> R3\n", GCPhysFault, uErr));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = VINF_EM_RAW_EMULATE_INSTR;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /*
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Must be out of sync, so do a SyncPage and restart the instruction.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * ASSUMES that ALL handlers are page aligned and covers whole pages
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * (assumption asserted in PGMHandlerPhysicalRegisterEx).
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: Out of sync page at %RGp (uErr=%#x)\n", GCPhysFault, uErr));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfgSyncPage);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync rc = pgmShwSyncNestedPageLocked(pVCpu, GCPhysFault, 1 /*cPages*/, enmShwPagingMode);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pgmUnlock(pVM);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfg, a);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return rc;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#else
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertLogRelFailed();
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return VERR_PGM_NOT_USED_IN_MODE;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync