summaryrefslogtreecommitdiff
path: root/src/VBox/VMM/VMMRZ/VMMRZ.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/VMMRZ/VMMRZ.cpp')
-rw-r--r--src/VBox/VMM/VMMRZ/VMMRZ.cpp80
1 files changed, 76 insertions, 4 deletions
diff --git a/src/VBox/VMM/VMMRZ/VMMRZ.cpp b/src/VBox/VMM/VMMRZ/VMMRZ.cpp
index 9a86cfb6..e78f41fb 100644
--- a/src/VBox/VMM/VMMRZ/VMMRZ.cpp
+++ b/src/VBox/VMM/VMMRZ/VMMRZ.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -25,6 +25,7 @@
#include <VBox/err.h>
#include <iprt/assert.h>
+#include <iprt/asm-amd64-x86.h>
#include <iprt/string.h>
@@ -52,6 +53,7 @@ VMMRZDECL(int) VMMRZCallRing3(PVM pVM, PVMCPU pVCpu, VMMCALLRING3 enmOperation,
if (RT_UNLIKELY( pVCpu->vmm.s.cCallRing3Disabled != 0
&& enmOperation != VMMCALLRING3_VM_R0_ASSERTION))
{
+#ifndef IN_RING0
/*
* In most cases, it's sufficient to return a status code which
* will then be propagated up the code usually encountering several
@@ -64,6 +66,7 @@ VMMRZDECL(int) VMMRZCallRing3(PVM pVM, PVMCPU pVCpu, VMMCALLRING3 enmOperation,
*/
if (enmOperation != VMMCALLRING3_REM_REPLAY_HANDLER_NOTIFICATIONS)
return VERR_VMM_RING3_CALL_DISABLED;
+#endif
#ifdef IN_RC
RTStrPrintf(g_szRTAssertMsg1, sizeof(pVM->vmm.s.szRing0AssertMsg1),
"VMMRZCallRing3: enmOperation=%d uArg=%#llx idCpu=%#x\n", enmOperation, uArg, pVCpu->idCpu);
@@ -83,7 +86,14 @@ VMMRZDECL(int) VMMRZCallRing3(PVM pVM, PVMCPU pVCpu, VMMCALLRING3 enmOperation,
#ifdef IN_RC
pVM->vmm.s.pfnRCToHost(VINF_VMM_CALL_HOST);
#else
- int rc = vmmR0CallRing3LongJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, VINF_VMM_CALL_HOST);
+ int rc;
+ if (pVCpu->vmm.s.pfnCallRing3CallbackR0)
+ {
+ rc = pVCpu->vmm.s.pfnCallRing3CallbackR0(pVCpu, enmOperation, pVCpu->vmm.s.pvCallRing3CallbackUserR0);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+ rc = vmmR0CallRing3LongJmp(&pVCpu->vmm.s.CallRing3JmpBufR0, VINF_VMM_CALL_HOST);
if (RT_FAILURE(rc))
return rc;
#endif
@@ -118,8 +128,12 @@ VMMRZDECL(int) VMMRZCallRing3NoCpu(PVM pVM, VMMCALLRING3 enmOperation, uint64_t
VMMRZDECL(void) VMMRZCallRing3Disable(PVMCPU pVCpu)
{
VMCPU_ASSERT_EMT(pVCpu);
+#if defined(LOG_ENABLED) && defined(IN_RING0)
+ RTCCUINTREG fFlags = ASMIntDisableFlags(); /* preemption consistency. */
+#endif
+
Assert(pVCpu->vmm.s.cCallRing3Disabled < 16);
- if (++pVCpu->vmm.s.cCallRing3Disabled == 1)
+ if (ASMAtomicIncU32(&pVCpu->vmm.s.cCallRing3Disabled) == 1) /** @todo replace with unordered variant (ASMAtomicUoIncU32). */
{
/** @todo it might make more sense to just disable logging here, then we
* won't flush away important bits... but that goes both ways really. */
@@ -132,6 +146,10 @@ VMMRZDECL(void) VMMRZCallRing3Disable(PVMCPU pVCpu)
# endif
#endif
}
+
+#if defined(LOG_ENABLED) && defined(IN_RING0)
+ ASMSetFlags(fFlags);
+#endif
}
@@ -144,8 +162,12 @@ VMMRZDECL(void) VMMRZCallRing3Disable(PVMCPU pVCpu)
VMMRZDECL(void) VMMRZCallRing3Enable(PVMCPU pVCpu)
{
VMCPU_ASSERT_EMT(pVCpu);
+#if defined(LOG_ENABLED) && defined(IN_RING0)
+ RTCCUINTREG fFlags = ASMIntDisableFlags(); /* preemption consistency. */
+#endif
+
Assert(pVCpu->vmm.s.cCallRing3Disabled > 0);
- if (--pVCpu->vmm.s.cCallRing3Disabled == 0)
+ if (ASMAtomicDecU32(&pVCpu->vmm.s.cCallRing3Disabled) == 0) /** @todo replace with unordered variant (ASMAtomicUoDecU32). */
{
#ifdef IN_RC
pVCpu->pVMRC->vmm.s.fRCLoggerFlushingDisabled = false;
@@ -156,6 +178,10 @@ VMMRZDECL(void) VMMRZCallRing3Enable(PVMCPU pVCpu)
# endif
#endif
}
+
+#if defined(LOG_ENABLED) && defined(IN_RING0)
+ ASMSetFlags(fFlags);
+#endif
}
@@ -172,3 +198,49 @@ VMMRZDECL(bool) VMMRZCallRing3IsEnabled(PVMCPU pVCpu)
return pVCpu->vmm.s.cCallRing3Disabled == 0;
}
+
+/**
+ * Sets the ring-0 callback before doing the ring-3 call.
+ *
+ * @param pVCpu Pointer to the VMCPU.
+ * @param pfnCallback Pointer to the callback.
+ * @param pvUser The user argument.
+ *
+ * @return VBox status code.
+ */
+VMMRZDECL(int) VMMRZCallRing3SetNotification(PVMCPU pVCpu, R0PTRTYPE(PFNVMMR0CALLRING3NOTIFICATION) pfnCallback, RTR0PTR pvUser)
+{
+ AssertPtrReturn(pVCpu, VERR_INVALID_POINTER);
+ AssertPtrReturn(pfnCallback, VERR_INVALID_POINTER);
+
+ if (pVCpu->vmm.s.pfnCallRing3CallbackR0)
+ return VERR_ALREADY_EXISTS;
+
+ pVCpu->vmm.s.pfnCallRing3CallbackR0 = pfnCallback;
+ pVCpu->vmm.s.pvCallRing3CallbackUserR0 = pvUser;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Removes the ring-0 callback.
+ *
+ * @param pVCpu Pointer to the VMCPU.
+ */
+VMMRZDECL(void) VMMRZCallRing3RemoveNotification(PVMCPU pVCpu)
+{
+ pVCpu->vmm.s.pfnCallRing3CallbackR0 = NULL;
+}
+
+
+/**
+ * Checks whether there is a ring-0 callback notification active.
+ *
+ * @param pVCpu Pointer to the VMCPU.
+ * @returns true if there the notification is active, false otherwise.
+ */
+VMMRZDECL(bool) VMMRZCallRing3IsNotificationSet(PVMCPU pVCpu)
+{
+ return pVCpu->vmm.s.pfnCallRing3CallbackR0 != NULL;
+}
+