summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/VMMAll/REMAll.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/VMMAll/REMAll.cpp')
-rw-r--r--src/VBox/VMM/VMMAll/REMAll.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/VBox/VMM/VMMAll/REMAll.cpp b/src/VBox/VMM/VMMAll/REMAll.cpp
new file mode 100644
index 00000000..51506697
--- /dev/null
+++ b/src/VBox/VMM/VMMAll/REMAll.cpp
@@ -0,0 +1,249 @@
+/* $Id: REMAll.cpp $ */
+/** @file
+ * REM - Recompiled Execution Monitor, all Contexts part.
+ */
+
+/*
+ * Copyright (C) 2006-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_REM
+#ifdef VBOX_WITH_REM
+# include <VBox/vmm/rem.h>
+#endif
+#include <VBox/vmm/em.h>
+#include <VBox/vmm/vmm.h>
+#include "REMInternal.h"
+#include <VBox/vmm/vm.h>
+#include <iprt/errcore.h>
+#include <VBox/log.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+
+
+#ifndef IN_RING3
+
+/**
+ * Records a invlpg instruction for replaying upon REM entry.
+ *
+ * @param pVM The cross context VM structure.
+ * @param GCPtrPage The
+ */
+VMMDECL(void) REMNotifyInvalidatePage(PVM pVM, RTGCPTR GCPtrPage)
+{
+ /*
+ * Try take the REM lock and push the address onto the array.
+ */
+ if ( pVM->rem.s.cInvalidatedPages < RT_ELEMENTS(pVM->rem.s.aGCPtrInvalidatedPages)
+ && EMRemTryLock(pVM) == VINF_SUCCESS)
+ {
+ uint32_t iPage = pVM->rem.s.cInvalidatedPages;
+ if (iPage < RT_ELEMENTS(pVM->rem.s.aGCPtrInvalidatedPages))
+ {
+ ASMAtomicWriteU32(&pVM->rem.s.cInvalidatedPages, iPage + 1);
+ pVM->rem.s.aGCPtrInvalidatedPages[iPage] = GCPtrPage;
+
+ EMRemUnlock(pVM);
+ return;
+ }
+
+ CPUMSetChangedFlags(VMMGetCpu(pVM), CPUM_CHANGED_GLOBAL_TLB_FLUSH); /** @todo this array should be per-cpu technically speaking. */
+ ASMAtomicWriteU32(&pVM->rem.s.cInvalidatedPages, 0); /** @todo leave this alone? Optimize this code? */
+
+ EMRemUnlock(pVM);
+ }
+ else
+ {
+ /* Fallback: Simply tell the recompiler to flush its TLB. */
+ CPUMSetChangedFlags(VMMGetCpu(pVM), CPUM_CHANGED_GLOBAL_TLB_FLUSH);
+ ASMAtomicWriteU32(&pVM->rem.s.cInvalidatedPages, 0); /** @todo leave this alone?! Optimize this code? */
+ }
+
+ return;
+}
+
+
+/**
+ * Insert pending notification
+ *
+ * @param pVM The cross context VM structure.
+ * @param pRec Notification record to insert
+ */
+static void remNotifyHandlerInsert(PVM pVM, PREMHANDLERNOTIFICATION pRec)
+{
+ /*
+ * Fetch a free record.
+ */
+ uint32_t cFlushes = 0;
+ uint32_t idxFree;
+ PREMHANDLERNOTIFICATION pFree;
+ do
+ {
+ idxFree = ASMAtomicUoReadU32(&pVM->rem.s.idxFreeList);
+ if (idxFree == UINT32_MAX)
+ {
+ do
+ {
+ cFlushes++;
+ Assert(cFlushes != 128);
+ AssertFatal(cFlushes < _1M);
+ VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS, 0);
+ idxFree = ASMAtomicUoReadU32(&pVM->rem.s.idxFreeList);
+ } while (idxFree == UINT32_MAX);
+ }
+ pFree = &pVM->rem.s.aHandlerNotifications[idxFree];
+ } while (!ASMAtomicCmpXchgU32(&pVM->rem.s.idxFreeList, pFree->idxNext, idxFree));
+
+ /*
+ * Copy the record.
+ */
+ pFree->enmKind = pRec->enmKind;
+ pFree->u = pRec->u;
+
+ /*
+ * Insert it into the pending list.
+ */
+ uint32_t idxNext;
+ do
+ {
+ idxNext = ASMAtomicUoReadU32(&pVM->rem.s.idxPendingList);
+ ASMAtomicWriteU32(&pFree->idxNext, idxNext);
+ ASMCompilerBarrier();
+ } while (!ASMAtomicCmpXchgU32(&pVM->rem.s.idxPendingList, idxFree, idxNext));
+
+ VM_FF_SET(pVM, VM_FF_REM_HANDLER_NOTIFY);
+}
+
+
+/**
+ * Notification about a successful PGMR3HandlerPhysicalRegister() call.
+ *
+ * @param pVM The cross context VM structure.
+ * @param enmKind Kind of access handler.
+ * @param GCPhys Handler range address.
+ * @param cb Size of the handler range.
+ * @param fHasHCHandler Set if the handler have a HC callback function.
+ */
+VMMDECL(void) REMNotifyHandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler)
+{
+ REMHANDLERNOTIFICATION Rec;
+ Rec.enmKind = REMHANDLERNOTIFICATIONKIND_PHYSICAL_REGISTER;
+ Rec.u.PhysicalRegister.enmKind = enmKind;
+ Rec.u.PhysicalRegister.GCPhys = GCPhys;
+ Rec.u.PhysicalRegister.cb = cb;
+ Rec.u.PhysicalRegister.fHasHCHandler = fHasHCHandler;
+ remNotifyHandlerInsert(pVM, &Rec);
+}
+
+
+/**
+ * Notification about a successful PGMR3HandlerPhysicalDeregister() operation.
+ *
+ * @param pVM The cross context VM structure.
+ * @param enmKind Kind of access handler.
+ * @param GCPhys Handler range address.
+ * @param cb Size of the handler range.
+ * @param fHasHCHandler Set if the handler have a HC callback function.
+ * @param fRestoreAsRAM Whether the to restore it as normal RAM or as unassigned memory.
+ */
+VMMDECL(void) REMNotifyHandlerPhysicalDeregister(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM)
+{
+ REMHANDLERNOTIFICATION Rec;
+ Rec.enmKind = REMHANDLERNOTIFICATIONKIND_PHYSICAL_DEREGISTER;
+ Rec.u.PhysicalDeregister.enmKind = enmKind;
+ Rec.u.PhysicalDeregister.GCPhys = GCPhys;
+ Rec.u.PhysicalDeregister.cb = cb;
+ Rec.u.PhysicalDeregister.fHasHCHandler = fHasHCHandler;
+ Rec.u.PhysicalDeregister.fRestoreAsRAM = fRestoreAsRAM;
+ remNotifyHandlerInsert(pVM, &Rec);
+}
+
+
+/**
+ * Notification about a successful PGMR3HandlerPhysicalModify() call.
+ *
+ * @param pVM The cross context VM structure.
+ * @param enmKind Kind of access handler.
+ * @param GCPhysOld Old handler range address.
+ * @param GCPhysNew New handler range address.
+ * @param cb Size of the handler range.
+ * @param fHasHCHandler Set if the handler have a HC callback function.
+ * @param fRestoreAsRAM Whether the to restore it as normal RAM or as unassigned memory.
+ */
+VMMDECL(void) REMNotifyHandlerPhysicalModify(PVM pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld, RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fHasHCHandler, bool fRestoreAsRAM)
+{
+ REMHANDLERNOTIFICATION Rec;
+ Rec.enmKind = REMHANDLERNOTIFICATIONKIND_PHYSICAL_MODIFY;
+ Rec.u.PhysicalModify.enmKind = enmKind;
+ Rec.u.PhysicalModify.GCPhysOld = GCPhysOld;
+ Rec.u.PhysicalModify.GCPhysNew = GCPhysNew;
+ Rec.u.PhysicalModify.cb = cb;
+ Rec.u.PhysicalModify.fHasHCHandler = fHasHCHandler;
+ Rec.u.PhysicalModify.fRestoreAsRAM = fRestoreAsRAM;
+ remNotifyHandlerInsert(pVM, &Rec);
+}
+
+#endif /* !IN_RING3 */
+
+#ifdef IN_RC
+/**
+ * Flushes the physical handler notifications if the queue is almost full.
+ *
+ * This is for avoiding trouble in RC when changing CR3.
+ *
+ * @param pVM The cross context VM structure.
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ */
+VMMDECL(void) REMNotifyHandlerPhysicalFlushIfAlmostFull(PVM pVM, PVMCPU pVCpu)
+{
+ Assert(pVM->cCpus == 1); NOREF(pVCpu);
+
+ /*
+ * Less than 48 items means we should flush.
+ */
+ uint32_t cFree = 0;
+ for (uint32_t idx = pVM->rem.s.idxFreeList;
+ idx != UINT32_MAX;
+ idx = pVM->rem.s.aHandlerNotifications[idx].idxNext)
+ {
+ Assert(idx < RT_ELEMENTS(pVM->rem.s.aHandlerNotifications));
+ if (++cFree >= 48)
+ return;
+ }
+ AssertRelease(VM_FF_IS_SET(pVM, VM_FF_REM_HANDLER_NOTIFY));
+ AssertRelease(pVM->rem.s.idxPendingList != UINT32_MAX);
+
+ /* Ok, we gotta flush them. */
+ VMMRZCallRing3NoCpu(pVM, VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS, 0);
+
+ AssertRelease(pVM->rem.s.idxPendingList == UINT32_MAX);
+ AssertRelease(pVM->rem.s.idxFreeList != UINT32_MAX);
+}
+#endif /* IN_RC */
+
+
+/**
+ * Make REM flush all translation block upon the next call to REMR3State().
+ *
+ * @param pVM The cross context VM structure.
+ */
+VMMDECL(void) REMFlushTBs(PVM pVM)
+{
+ LogFlow(("REMFlushTBs: fFlushTBs=%RTbool fInREM=%RTbool fInStateSync=%RTbool\n",
+ pVM->rem.s.fFlushTBs, pVM->rem.s.fInREM, pVM->rem.s.fInStateSync));
+ pVM->rem.s.fFlushTBs = true;
+}
+