PGMR0.cpp revision df25990f935e7fd32acd9be9a156aff8d10facf2
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/* $Id$ */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/** @file
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * PGM - Page Manager and Monitor, Ring-0.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/*
5654aa8329bbe2838fa5733f28c1a0461c9e6453vboxsync * Copyright (C) 2007-2011 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
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync#include <VBox/rawpci.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/pgm.h>
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/gmm.h>
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync#include <VBox/vmm/gvm.h>
0c437bb10c61b229407a7517efde04dfe3b1e4a1vboxsync#include "PGMInternal.h"
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync#include <VBox/vmm/vm.h>
0c437bb10c61b229407a7517efde04dfe3b1e4a1vboxsync#include "PGMInline.h"
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <VBox/log.h>
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <VBox/err.h>
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync#include <iprt/assert.h>
209c11e4b5dbb310116c99a42d773163928e002bvboxsync#include <iprt/mem.h>
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync/*
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync * Instantiate the ring-0 header/code templates.
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync */
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
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 *
4bfa7b58e362a1bca0628643c352c137900bf01avboxsync * @param pVM Pointer to the VM.
df25990f935e7fd32acd9be9a156aff8d10facf2vboxsync * @param pVCpu Pointer to the VMCPU.
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{
c7a00ac75c7941df2afb62e6fd7ffdf1795e6c76vboxsync PGM_LOCK_ASSERT_OWNER_EX(pVM, pVCpu);
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;
683371bbf37760161d1b8454ce978acf89bbb04fvboxsync AssertReturn(iFirst <= RT_ELEMENTS(pVM->pgm.s.aHandyPages), VERR_PGM_HANDY_PAGE_IPE);
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 {
43dff6077acb4176145b18bdb862eb73620182d2vboxsync#ifdef VBOX_STRICT
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);
b40179b44fea65b72b2f226f62af1ed7bd3c48fcvboxsync Assert(!(pVM->pgm.s.aHandyPages[i].HCPhysGCPhys & ~X86_PTE_PAE_PG_MASK));
436b5c616e019c5e62053657c52d3ab5562ecbbfvboxsync }
43dff6077acb4176145b18bdb862eb73620182d2vboxsync#endif
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 {
5654aa8329bbe2838fa5733f28c1a0461c9e6453vboxsync cPages >>= 1;
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync if (cPages + iFirst < PGM_HANDY_PAGES_MIN)
ff78b877ed7acd25e2d384570a938441455d6a95vboxsync cPages = PGM_HANDY_PAGES_MIN - iFirst;
5654aa8329bbe2838fa5733f28c1a0461c9e6453vboxsync rc = GMMR0AllocateHandyPages(pVM, pVCpu->idCpu, 0, 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);
b40179b44fea65b72b2f226f62af1ed7bd3c48fcvboxsync 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
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync
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 *
4bfa7b58e362a1bca0628643c352c137900bf01avboxsync * @param pVM Pointer to the VM.
df25990f935e7fd32acd9be9a156aff8d10facf2vboxsync * @param pVCpu Pointer to the VMCPU.
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{
c7a00ac75c7941df2afb62e6fd7ffdf1795e6c76vboxsync PGM_LOCK_ASSERT_OWNER_EX(pVM, pVCpu);
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync Assert(!pVM->pgm.s.cLargeHandyPages);
c7a00ac75c7941df2afb62e6fd7ffdf1795e6c76vboxsync
c7a00ac75c7941df2afb62e6fd7ffdf1795e6c76vboxsync int rc = GMMR0AllocateLargePage(pVM, pVCpu->idCpu, _2M,
c7a00ac75c7941df2afb62e6fd7ffdf1795e6c76vboxsync &pVM->pgm.s.aLargeHandyPage[0].idPage,
c7a00ac75c7941df2afb62e6fd7ffdf1795e6c76vboxsync &pVM->pgm.s.aLargeHandyPage[0].HCPhysGCPhys);
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync if (RT_SUCCESS(rc))
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync pVM->pgm.s.cLargeHandyPages = 1;
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync return rc;
30868e719f5a45ec4689ecb2616767cb1fd02c28vboxsync}
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync#ifdef VBOX_WITH_PCI_PASSTHROUGH
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync/* Interface sketch. The interface belongs to a global PCI pass-through
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync manager. It shall use the global VM handle, not the user VM handle to
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync store the per-VM info (domain) since that is all ring-0 stuff, thus
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync passing pGVM here. I've tentitively prefixed the functions 'GPciRawR0',
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync we can discuss the PciRaw code re-organtization when I'm back from
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync vacation.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync I've implemented the initial IOMMU set up below. For things to work
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync reliably, we will probably need add a whole bunch of checks and
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync GPciRawR0GuestPageUpdate call to the PGM code. For the present,
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync assuming nested paging (enforced) and prealloc (enforced), no
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync ballooning (check missing), page sharing (check missing) or live
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync migration (check missing), it might work fine. At least if some
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync VM power-off hook is present and can tear down the IOMMU page tables. */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync/**
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * Tells the global PCI pass-through manager that we are about to set up the
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * guest page to host page mappings for the specfied VM.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @returns VBox status code.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param pGVM The ring-0 VM structure.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageBeginAssignments(PGVM pGVM)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync{
2afbe132eb7931e0125141eabe3a48e08f1ffab5vboxsync NOREF(pGVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync return VINF_SUCCESS;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync}
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync/**
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * Assigns a host page mapping for a guest page.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * This is only used when setting up the mappings, i.e. between
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * GPciRawR0GuestPageBeginAssignments and GPciRawR0GuestPageEndAssignments.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @returns VBox status code.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param pGVM The ring-0 VM structure.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param GCPhys The address of the guest page (page aligned).
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param HCPhys The address of the host page (page aligned).
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageAssign(PGVM pGVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync{
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync AssertReturn(!(HCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync if (pGVM->rawpci.s.pfnContigMemInfo)
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync /** @todo: what do we do on failure? */
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync pGVM->rawpci.s.pfnContigMemInfo(&pGVM->rawpci.s, HCPhys, GCPhys, PAGE_SIZE, PCIRAW_MEMINFO_MAP);
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync return VINF_SUCCESS;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync}
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync/**
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * Indicates that the specified guest page doesn't exists but doesn't have host
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * page mapping we trust PCI pass-through with.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * This is only used when setting up the mappings, i.e. between
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * GPciRawR0GuestPageBeginAssignments and GPciRawR0GuestPageEndAssignments.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @returns VBox status code.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param pGVM The ring-0 VM structure.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param GCPhys The address of the guest page (page aligned).
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param HCPhys The address of the host page (page aligned).
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageUnassign(PGVM pGVM, RTGCPHYS GCPhys)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync{
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_3);
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync if (pGVM->rawpci.s.pfnContigMemInfo)
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync /** @todo: what do we do on failure? */
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync pGVM->rawpci.s.pfnContigMemInfo(&pGVM->rawpci.s, 0, GCPhys, PAGE_SIZE, PCIRAW_MEMINFO_UNMAP);
2508d15edddcae0b79002fae3fe103d6c4836810vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync return VINF_SUCCESS;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync}
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync/**
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * Tells the global PCI pass-through manager that we have completed setting up
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * the guest page to host page mappings for the specfied VM.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * This complements GPciRawR0GuestPageBeginAssignments and will be called even
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * if some page assignment failed.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @returns VBox status code.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param pGVM The ring-0 VM structure.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageEndAssignments(PGVM pGVM)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync{
2afbe132eb7931e0125141eabe3a48e08f1ffab5vboxsync NOREF(pGVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync return VINF_SUCCESS;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync}
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync/**
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * Tells the global PCI pass-through manager that a guest page mapping has
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * changed after the initial setup.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @returns VBox status code.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param pGVM The ring-0 VM structure.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param GCPhys The address of the guest page (page aligned).
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @param HCPhys The new host page address or NIL_RTHCPHYS if
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * now unassigned.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsyncVMMR0_INT_DECL(int) GPciRawR0GuestPageUpdate(PGVM pGVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync{
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync AssertReturn(!(GCPhys & PAGE_OFFSET_MASK), VERR_INTERNAL_ERROR_4);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync AssertReturn(!(HCPhys & PAGE_OFFSET_MASK) || HCPhys == NIL_RTHCPHYS, VERR_INTERNAL_ERROR_4);
2afbe132eb7931e0125141eabe3a48e08f1ffab5vboxsync NOREF(pGVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync return VINF_SUCCESS;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync}
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync#endif /* VBOX_WITH_PCI_PASSTHROUGH */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync/**
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * Sets up the IOMMU when raw PCI device is enabled.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @note This is a hack that will probably be remodelled and refined later!
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * @returns VBox status code.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync *
4bfa7b58e362a1bca0628643c352c137900bf01avboxsync * @param pVM Pointer to the VM.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsyncVMMR0_INT_DECL(int) PGMR0PhysSetupIommu(PVM pVM)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync{
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync PGVM pGVM;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync int rc = GVMMR0ByVM(pVM, &pGVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync if (RT_FAILURE(rc))
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync return rc;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync#ifdef VBOX_WITH_PCI_PASSTHROUGH
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync if (pVM->pgm.s.fPciPassthrough)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync {
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync /*
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * The Simplistic Approach - Enumerate all the pages and call tell the
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync * IOMMU about each of them.
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync pgmLock(pVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync rc = GPciRawR0GuestPageBeginAssignments(pGVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync if (RT_SUCCESS(rc))
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync {
1999ae03c34840fa4d712fd2e020120b2cb7182avboxsync for (PPGMRAMRANGE pRam = pVM->pgm.s.pRamRangesXR0; RT_SUCCESS(rc) && pRam; pRam = pRam->pNextR0)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync {
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync PPGMPAGE pPage = &pRam->aPages[0];
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync RTGCPHYS GCPhys = pRam->GCPhys;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync uint32_t cLeft = pRam->cb >> PAGE_SHIFT;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync while (cLeft-- > 0)
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync {
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync /* Only expose pages that are 100% safe for now. */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync if ( PGM_PAGE_GET_TYPE(pPage) == PGMPAGETYPE_RAM
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync && PGM_PAGE_GET_STATE(pPage) == PGM_PAGE_STATE_ALLOCATED
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync && !PGM_PAGE_HAS_ANY_HANDLERS(pPage))
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync rc = GPciRawR0GuestPageAssign(pGVM, GCPhys, PGM_PAGE_GET_HCPHYS(pPage));
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync else
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync rc = GPciRawR0GuestPageUnassign(pGVM, GCPhys);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync /* next */
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync pPage++;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync GCPhys += PAGE_SIZE;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync }
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync }
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync int rc2 = GPciRawR0GuestPageEndAssignments(pGVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync rc = rc2;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync }
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync pgmUnlock(pVM);
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync }
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync else
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync#endif
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync rc = VERR_NOT_SUPPORTED;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync return rc;
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync}
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
e2bd93b4f9c38c9b01eb960ba7bc1fc9c4d38ce8vboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync/**
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * #PF Handler for nested paging.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync *
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @returns VBox status code (appropriate for trap handling and GC return).
fa8716d08ff627a8e1c14bcac56e8e3867b3f795vboxsync * @param pVM Pointer to the VM.
df25990f935e7fd32acd9be9a156aff8d10facf2vboxsync * @param pVCpu Pointer to the VMCPU.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * @param enmShwPagingMode Paging mode for the nested page tables.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @param uErr The trap error code.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @param pRegFrame Trap register frame.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * @param GCPhysFault The fault address.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync */
c7ff622115966b69b482bd2896662e40d823b22fvboxsyncVMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr,
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync{
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync int rc;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync LogFlow(("PGMTrap0eHandler: uErr=%RGx GCPhysFault=%RGp eip=%RGv\n", uErr, GCPhysFault, (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). */
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync AssertMsg( enmShwPagingMode == PGMMODE_32_BIT || enmShwPagingMode == PGMMODE_PAE || enmShwPagingMode == PGMMODE_PAE_NX
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync || enmShwPagingMode == PGMMODE_AMD64 || enmShwPagingMode == PGMMODE_AMD64_NX || enmShwPagingMode == PGMMODE_EPT,
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync ("enmShwPagingMode=%d\n", enmShwPagingMode));
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
3f1e0eea71cabeb90529e546f16eb7aee513fde9vboxsync /* Reserved shouldn't end up here. */
3f1e0eea71cabeb90529e546f16eb7aee513fde9vboxsync Assert(!(uErr & X86_TRAP_PF_RSVD));
3f1e0eea71cabeb90529e546f16eb7aee513fde9vboxsync
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)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNotPresentRead);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RW)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RSVD)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSReserved);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_ID)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSNXE);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eUSRead);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync { /* Supervisor */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (!(uErr & X86_TRAP_PF_P))
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync {
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (uErr & X86_TRAP_PF_RW)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVNotPresentRead);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RW)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVWrite);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_ID)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSNXE);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync else if (uErr & X86_TRAP_PF_RSVD)
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eSVReserved);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync#endif
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /*
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * Call the worker.
134a71c1528b56afe4db843ab63ec5a5b849535bvboxsync *
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync * Note! We pretend the guest is in protected mode without paging, so we
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync * can use existing code to build the nested page tables.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync */
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync bool fLockTaken = false;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync switch(enmShwPagingMode)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync {
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync case PGMMODE_32_BIT:
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync rc = PGM_BTH_NAME_32BIT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync break;
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync case PGMMODE_PAE:
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync case PGMMODE_PAE_NX:
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync rc = PGM_BTH_NAME_PAE_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync break;
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync case PGMMODE_AMD64:
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync case PGMMODE_AMD64_NX:
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync rc = PGM_BTH_NAME_AMD64_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync break;
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync case PGMMODE_EPT:
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync rc = PGM_BTH_NAME_EPT_PROT(Trap0eHandler)(pVCpu, uErr, pRegFrame, GCPhysFault, &fLockTaken);
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync break;
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync default:
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync AssertFailed();
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync rc = VERR_INVALID_PARAMETER;
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync break;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync }
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync if (fLockTaken)
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync {
addc480d0d7650db6323467bbdab6c21836a2928vboxsync PGM_LOCK_ASSERT_OWNER(pVM);
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync pgmUnlock(pVM);
0bc7c910e57c78c68e89122e2244cc073d1ef06evboxsync }
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync if (rc == VINF_PGM_SYNCPAGE_MODIFIED_PDE)
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync rc = VINF_SUCCESS;
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync /* Note: hack alert for difficult to reproduce problem. */
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync else if ( rc == VERR_PAGE_NOT_PRESENT /* SMP only ; disassembly might fail. */
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync || rc == VERR_PAGE_TABLE_NOT_PRESENT /* seen with UNI & SMP */
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync || rc == VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT /* seen with SMP */
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync || rc == VERR_PAGE_MAP_LEVEL4_NOT_PRESENT) /* precaution */
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync {
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync 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));
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync /* Some kind of inconsistency in the SMP case; it's safe to just execute the instruction again; not sure about
7c9a5eca233baf6ede345ace077a00bd0b7af1efvboxsync single VCPU VMs though. */
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync rc = VINF_SUCCESS;
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync }
3c941112ffb137d71a8e457fcc3915f2d464ed2avboxsync
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync STAM_STATS({ if (!pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution))
1986f56777969a25707ab214f8dd070804be666cvboxsync pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution) = &pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0eTime2Misc; });
1986f56777969a25707ab214f8dd070804be666cvboxsync STAM_PROFILE_STOP_EX(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatRZTrap0e, pVCpu->pgm.s.CTX_SUFF(pStatTrap0eAttribution), a);
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync return rc;
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync}
6f516ad9911d9037a18778742caa955fe362f8ffvboxsync
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync/**
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * #PF Handler for deliberate nested paging misconfiguration (/reserved bit)
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * employed for MMIO pages.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync *
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * @returns VBox status code (appropriate for trap handling and GC return).
4bfa7b58e362a1bca0628643c352c137900bf01avboxsync * @param pVM Pointer to the VM.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * @param pVCpu The current CPU.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * @param enmShwPagingMode Paging mode for the nested page tables.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * @param pRegFrame Trap register frame.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * @param GCPhysFault The fault address.
150283991b1a312acbe86c67d3420f6463b38878vboxsync * @param uErr The error code, UINT32_MAX if not available
150283991b1a312acbe86c67d3420f6463b38878vboxsync * (VT-x).
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync */
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsyncVMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PVM pVM, PVMCPU pVCpu, PGMMODE enmShwPagingMode,
150283991b1a312acbe86c67d3420f6463b38878vboxsync PCPUMCTXCORE pRegFrame, RTGCPHYS GCPhysFault, uint32_t uErr)
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync{
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync#ifdef PGM_WITH_MMIO_OPTIMIZATIONS
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync STAM_PROFILE_START(&pVCpu->CTX_SUFF(pStats)->StatR0NpMiscfg, a);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync VBOXSTRICTRC rc;
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync /*
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * Try lookup the all access physical handler for the address.
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync */
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync pgmLock(pVM);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync PPGMPHYSHANDLER pHandler = pgmHandlerPhysicalLookup(pVM, GCPhysFault);
150283991b1a312acbe86c67d3420f6463b38878vboxsync if (RT_LIKELY(pHandler && pHandler->enmType != PGMPHYSHANDLERTYPE_PHYSICAL_WRITE))
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync {
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync /*
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync * If the handle has aliases page or pages that have been temporarily
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync * disabled, we'll have to take a detour to make sure we resync them
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync * to avoid lots of unnecessary exits.
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync */
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync PPGMPAGE pPage;
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync if ( ( pHandler->cAliasedPages
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync || pHandler->cTmpOffPages)
1999ae03c34840fa4d712fd2e020120b2cb7182avboxsync && ( (pPage = pgmPhysGetPage(pVM, GCPhysFault)) == NULL
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync || PGM_PAGE_GET_HNDL_PHYS_STATE(pPage) == PGM_PAGE_HNDL_PHYS_STATE_DISABLED)
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync )
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync {
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: Resyncing aliases / tmp-off page at %RGp (uErr=%#x) %R[pgmpage]\n", GCPhysFault, uErr, pPage));
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfgSyncPage);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync rc = pgmShwSyncNestedPageLocked(pVCpu, GCPhysFault, 1 /*cPages*/, enmShwPagingMode);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync pgmUnlock(pVM);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync }
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync else
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync {
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync if (pHandler->CTX_SUFF(pfnHandler))
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync {
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync CTX_MID(PFNPGM,PHYSHANDLER) pfnHandler = pHandler->CTX_SUFF(pfnHandler);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync void *pvUser = pHandler->CTX_SUFF(pvUser);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync STAM_PROFILE_START(&pHandler->Stat, h);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync pgmUnlock(pVM);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync Log6(("PGMR0Trap0eHandlerNPMisconfig: calling %p(,%#x,,%RGp,%p)\n", pfnHandler, uErr, GCPhysFault, pvUser));
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync rc = pfnHandler(pVM, uErr == UINT32_MAX ? RTGCPTR_MAX : uErr, pRegFrame, GCPhysFault, GCPhysFault, pvUser);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync#ifdef VBOX_WITH_STATISTICS
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync pgmLock(pVM);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync pHandler = pgmHandlerPhysicalLookup(pVM, GCPhysFault);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync if (pHandler)
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync STAM_PROFILE_STOP(&pHandler->Stat, h);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync pgmUnlock(pVM);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync#endif
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync }
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync else
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync {
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync pgmUnlock(pVM);
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: %RGp (uErr=%#x) -> R3\n", GCPhysFault, uErr));
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync rc = VINF_EM_RAW_EMULATE_INSTR;
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync }
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync }
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync }
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync else
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync {
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync /*
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync * Must be out of sync, so do a SyncPage and restart the instruction.
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync *
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync * ASSUMES that ALL handlers are page aligned and covers whole pages
6e4b0f4821f335d37975004f6a7badab8bc48b6fvboxsync * (assumption asserted in PGMHandlerPhysicalRegisterEx).
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync */
150283991b1a312acbe86c67d3420f6463b38878vboxsync Log(("PGMR0Trap0eHandlerNPMisconfig: Out of sync page at %RGp (uErr=%#x)\n", GCPhysFault, uErr));
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync STAM_COUNTER_INC(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfgSyncPage);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync rc = pgmShwSyncNestedPageLocked(pVCpu, GCPhysFault, 1 /*cPages*/, enmShwPagingMode);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync pgmUnlock(pVM);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync }
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync STAM_PROFILE_STOP(&pVCpu->pgm.s.CTX_SUFF(pStats)->StatR0NpMiscfg, a);
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync return rc;
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync#else
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync AssertLogRelFailed();
683371bbf37760161d1b8454ce978acf89bbb04fvboxsync return VERR_PGM_NOT_USED_IN_MODE;
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync#endif
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync}
cc723cf07e365cd40b517b9c5da4f113e9469745vboxsync