summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/IOMInline.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/include/IOMInline.h')
-rw-r--r--src/VBox/VMM/include/IOMInline.h216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/VBox/VMM/include/IOMInline.h b/src/VBox/VMM/include/IOMInline.h
new file mode 100644
index 00000000..6705a8b8
--- /dev/null
+++ b/src/VBox/VMM/include/IOMInline.h
@@ -0,0 +1,216 @@
+/* $Id: IOMInline.h $ */
+/** @file
+ * IOM - Inlined functions.
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef VMM_INCLUDED_SRC_include_IOMInline_h
+#define VMM_INCLUDED_SRC_include_IOMInline_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <iprt/errcore.h>
+
+/** @addtogroup grp_iom_int Internals
+ * @internal
+ * @{
+ */
+
+/**
+ * Gets the I/O port range for the specified I/O port in the current context.
+ *
+ * @returns Pointer to I/O port range.
+ * @returns NULL if no port registered.
+ *
+ * @param pVM The cross context VM structure.
+ * @param Port The I/O port lookup.
+ */
+DECLINLINE(CTX_SUFF(PIOMIOPORTRANGE)) iomIOPortGetRange(PVM pVM, RTIOPORT Port)
+{
+ Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
+ return (CTX_SUFF(PIOMIOPORTRANGE))RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->CTX_SUFF(IOPortTree), Port);
+}
+
+
+/**
+ * Gets the I/O port range for the specified I/O port in the HC.
+ *
+ * @returns Pointer to I/O port range.
+ * @returns NULL if no port registered.
+ *
+ * @param pVM The cross context VM structure.
+ * @param Port The I/O port to lookup.
+ */
+DECLINLINE(PIOMIOPORTRANGER3) iomIOPortGetRangeR3(PVM pVM, RTIOPORT Port)
+{
+ Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
+ return (PIOMIOPORTRANGER3)RTAvlroIOPortRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->IOPortTreeR3, Port);
+}
+
+
+/**
+ * Gets the MMIO range for the specified physical address in the current context.
+ *
+ * @returns Pointer to MMIO range.
+ * @returns NULL if address not in a MMIO range.
+ *
+ * @param pVM The cross context VM structure.
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param GCPhys Physical address to lookup.
+ */
+DECLINLINE(PIOMMMIORANGE) iomMmioGetRange(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
+{
+ Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
+ PIOMMMIORANGE pRange = pVCpu->iom.s.CTX_SUFF(pMMIORangeLast);
+ if ( !pRange
+ || GCPhys - pRange->GCPhys >= pRange->cb)
+ pVCpu->iom.s.CTX_SUFF(pMMIORangeLast) = pRange
+ = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->MMIOTree, GCPhys);
+ return pRange;
+}
+
+/**
+ * Retain a MMIO range.
+ *
+ * @param pRange The range to release.
+ */
+DECLINLINE(void) iomMmioRetainRange(PIOMMMIORANGE pRange)
+{
+ uint32_t cRefs = ASMAtomicIncU32(&pRange->cRefs);
+ Assert(cRefs > 1);
+ Assert(cRefs < _1M);
+ NOREF(cRefs);
+}
+
+
+/**
+ * Gets the referenced MMIO range for the specified physical address in the
+ * current context.
+ *
+ * @returns Pointer to MMIO range.
+ * @returns NULL if address not in a MMIO range.
+ *
+ * @param pVM The cross context VM structure.
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param GCPhys Physical address to lookup.
+ */
+DECLINLINE(PIOMMMIORANGE) iomMmioGetRangeWithRef(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
+{
+ int rc = IOM_LOCK_SHARED_EX(pVM, VINF_SUCCESS);
+ AssertRCReturn(rc, NULL);
+
+ PIOMMMIORANGE pRange = pVCpu->iom.s.CTX_SUFF(pMMIORangeLast);
+ if ( !pRange
+ || GCPhys - pRange->GCPhys >= pRange->cb)
+ pVCpu->iom.s.CTX_SUFF(pMMIORangeLast) = pRange
+ = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->MMIOTree, GCPhys);
+ if (pRange)
+ iomMmioRetainRange(pRange);
+
+ IOM_UNLOCK_SHARED(pVM);
+ return pRange;
+}
+
+
+/**
+ * Releases a MMIO range.
+ *
+ * @param pVM The cross context VM structure.
+ * @param pRange The range to release.
+ */
+DECLINLINE(void) iomMmioReleaseRange(PVM pVM, PIOMMMIORANGE pRange)
+{
+ uint32_t cRefs = ASMAtomicDecU32(&pRange->cRefs);
+ if (!cRefs)
+ iomMmioFreeRange(pVM, pRange);
+}
+
+
+#ifdef VBOX_STRICT
+/**
+ * Gets the MMIO range for the specified physical address in the current context.
+ *
+ * @returns Pointer to MMIO range.
+ * @returns NULL if address not in a MMIO range.
+ *
+ * @param pVM The cross context VM structure.
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param GCPhys Physical address to lookup.
+ */
+DECLINLINE(PIOMMMIORANGE) iomMMIOGetRangeUnsafe(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys)
+{
+ PIOMMMIORANGE pRange = pVCpu->iom.s.CTX_SUFF(pMMIORangeLast);
+ if ( !pRange
+ || GCPhys - pRange->GCPhys >= pRange->cb)
+ pVCpu->iom.s.CTX_SUFF(pMMIORangeLast) = pRange
+ = (PIOMMMIORANGE)RTAvlroGCPhysRangeGet(&pVM->iom.s.CTX_SUFF(pTrees)->MMIOTree, GCPhys);
+ return pRange;
+}
+#endif /* VBOX_STRICT */
+
+
+#ifdef VBOX_WITH_STATISTICS
+/**
+ * Gets the MMIO statistics record.
+ *
+ * In ring-3 this will lazily create missing records, while in GC/R0 the caller has to
+ * return the appropriate status to defer the operation to ring-3.
+ *
+ * @returns Pointer to MMIO stats.
+ * @returns NULL if not found (R0/GC), or out of memory (R3).
+ *
+ * @param pVM The cross context VM structure.
+ * @param pVCpu The cross context virtual CPU structure of the calling EMT.
+ * @param GCPhys Physical address to lookup.
+ * @param pRange The MMIO range.
+ *
+ * @remarks The caller holds the IOM critical section with shared access prior
+ * to calling this method. Upon return, the lock has been released!
+ * This is ugly, but it's a necessary evil since we cannot upgrade read
+ * locks to write locks and the whole purpose here is calling
+ * iomR3MMIOStatsCreate.
+ */
+DECLINLINE(PIOMMMIOSTATS) iomMmioGetStats(PVM pVM, PVMCPU pVCpu, RTGCPHYS GCPhys, PIOMMMIORANGE pRange)
+{
+ Assert(IOM_IS_SHARED_LOCK_OWNER(pVM));
+
+ /* For large ranges, we'll put everything on the first byte. */
+ if (pRange->cb > PAGE_SIZE)
+ GCPhys = pRange->GCPhys;
+
+ PIOMMMIOSTATS pStats = pVCpu->iom.s.CTX_SUFF(pMMIOStatsLast);
+ if ( !pStats
+ || pStats->Core.Key != GCPhys)
+ {
+ pStats = (PIOMMMIOSTATS)RTAvloGCPhysGet(&pVM->iom.s.CTX_SUFF(pTrees)->MmioStatTree, GCPhys);
+# ifdef IN_RING3
+ if (!pStats)
+ {
+ IOM_UNLOCK_SHARED(pVM);
+ return iomR3MMIOStatsCreate(pVM, GCPhys, pRange->pszDesc);
+ }
+# endif
+ }
+
+ IOM_UNLOCK_SHARED(pVM);
+ return pStats;
+}
+#endif /* VBOX_WITH_STATISTICS */
+
+
+/** @} */
+
+#endif /* !VMM_INCLUDED_SRC_include_IOMInline_h */
+