summaryrefslogtreecommitdiffstats
path: root/src/VBox/VMM/include/IOMInternal.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/VMM/include/IOMInternal.h')
-rw-r--r--src/VBox/VMM/include/IOMInternal.h509
1 files changed, 509 insertions, 0 deletions
diff --git a/src/VBox/VMM/include/IOMInternal.h b/src/VBox/VMM/include/IOMInternal.h
new file mode 100644
index 00000000..64e35089
--- /dev/null
+++ b/src/VBox/VMM/include/IOMInternal.h
@@ -0,0 +1,509 @@
+/* $Id: IOMInternal.h $ */
+/** @file
+ * IOM - Internal header file.
+ */
+
+/*
+ * 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_IOMInternal_h
+#define VMM_INCLUDED_SRC_include_IOMInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define IOM_WITH_CRIT_SECT_RW
+
+#include <VBox/cdefs.h>
+#include <VBox/types.h>
+#include <VBox/vmm/iom.h>
+#include <VBox/vmm/stam.h>
+#include <VBox/vmm/pgm.h>
+#include <VBox/vmm/pdmcritsect.h>
+#ifdef IOM_WITH_CRIT_SECT_RW
+# include <VBox/vmm/pdmcritsectrw.h>
+#endif
+#include <VBox/param.h>
+#include <iprt/assert.h>
+#include <iprt/avl.h>
+
+
+
+/** @defgroup grp_iom_int Internals
+ * @ingroup grp_iom
+ * @internal
+ * @{
+ */
+
+/**
+ * MMIO range descriptor.
+ */
+typedef struct IOMMMIORANGE
+{
+ /** Avl node core with GCPhys as Key and GCPhys + cbSize - 1 as KeyLast. */
+ AVLROGCPHYSNODECORE Core;
+ /** Start physical address. */
+ RTGCPHYS GCPhys;
+ /** Size of the range. */
+ RTGCPHYS cb;
+ /** The reference counter. */
+ uint32_t volatile cRefs;
+ /** Flags, see IOMMMIO_FLAGS_XXX. */
+ uint32_t fFlags;
+
+ /** Pointer to user argument - R0. */
+ RTR0PTR pvUserR0;
+ /** Pointer to device instance - R0. */
+ PPDMDEVINSR0 pDevInsR0;
+ /** Pointer to write callback function - R0. */
+ R0PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR0;
+ /** Pointer to read callback function - R0. */
+ R0PTRTYPE(PFNIOMMMIOREAD) pfnReadCallbackR0;
+ /** Pointer to fill (memset) callback function - R0. */
+ R0PTRTYPE(PFNIOMMMIOFILL) pfnFillCallbackR0;
+
+ /** Pointer to user argument - R3. */
+ RTR3PTR pvUserR3;
+ /** Pointer to device instance - R3. */
+ PPDMDEVINSR3 pDevInsR3;
+ /** Pointer to write callback function - R3. */
+ R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackR3;
+ /** Pointer to read callback function - R3. */
+ R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallbackR3;
+ /** Pointer to fill (memset) callback function - R3. */
+ R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallbackR3;
+
+ /** Description / Name. For easing debugging. */
+ R3PTRTYPE(const char *) pszDesc;
+
+ /** Pointer to user argument - RC. */
+ RTRCPTR pvUserRC;
+ /** Pointer to device instance - RC. */
+ PPDMDEVINSRC pDevInsRC;
+ /** Pointer to write callback function - RC. */
+ RCPTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallbackRC;
+ /** Pointer to read callback function - RC. */
+ RCPTRTYPE(PFNIOMMMIOREAD) pfnReadCallbackRC;
+ /** Pointer to fill (memset) callback function - RC. */
+ RCPTRTYPE(PFNIOMMMIOFILL) pfnFillCallbackRC;
+#if HC_ARCH_BITS == 64
+ /** Padding structure length to multiple of 8 bytes. */
+ RTRCPTR RCPtrPadding;
+#endif
+} IOMMMIORANGE;
+/** Pointer to a MMIO range descriptor, R3 version. */
+typedef struct IOMMMIORANGE *PIOMMMIORANGE;
+
+
+/**
+ * MMIO address statistics. (one address)
+ *
+ * This is a simple way of making on demand statistics, however it's a
+ * bit free with the hypervisor heap memory.
+ */
+typedef struct IOMMMIOSTATS
+{
+ /** Avl node core with the address as Key. */
+ AVLOGCPHYSNODECORE Core;
+
+ /** Number of accesses (subtract ReadRZToR3 and WriteRZToR3 to get the right
+ * number). */
+ STAMCOUNTER Accesses;
+
+ /** Profiling read handler overhead in R3. */
+ STAMPROFILE ProfReadR3;
+ /** Profiling write handler overhead in R3. */
+ STAMPROFILE ProfWriteR3;
+ /** Counting and profiling reads in R0/RC. */
+ STAMPROFILE ProfReadRZ;
+ /** Counting and profiling writes in R0/RC. */
+ STAMPROFILE ProfWriteRZ;
+
+ /** Number of reads to this address from R0/RC which was serviced in R3. */
+ STAMCOUNTER ReadRZToR3;
+ /** Number of writes to this address from R0/RC which was serviced in R3. */
+ STAMCOUNTER WriteRZToR3;
+} IOMMMIOSTATS;
+AssertCompileMemberAlignment(IOMMMIOSTATS, Accesses, 8);
+/** Pointer to I/O port statistics. */
+typedef IOMMMIOSTATS *PIOMMMIOSTATS;
+
+
+/**
+ * I/O port range descriptor, R3 version.
+ */
+typedef struct IOMIOPORTRANGER3
+{
+ /** Avl node core with Port as Key and Port + cPorts - 1 as KeyLast. */
+ AVLROIOPORTNODECORE Core;
+#if HC_ARCH_BITS == 64 && !defined(RT_OS_WINDOWS)
+ uint32_t u32Alignment; /**< The sizeof(Core) differs. */
+#endif
+ /** Start I/O port address. */
+ RTIOPORT Port;
+ /** Size of the range. */
+ uint16_t cPorts;
+ /** Pointer to user argument. */
+ RTR3PTR pvUser;
+ /** Pointer to the associated device instance. */
+ R3PTRTYPE(PPDMDEVINS) pDevIns;
+ /** Pointer to OUT callback function. */
+ R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback;
+ /** Pointer to IN callback function. */
+ R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback;
+ /** Pointer to string OUT callback function. */
+ R3PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback;
+ /** Pointer to string IN callback function. */
+ R3PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback;
+ /** Description / Name. For easing debugging. */
+ R3PTRTYPE(const char *) pszDesc;
+} IOMIOPORTRANGER3;
+/** Pointer to I/O port range descriptor, R3 version. */
+typedef IOMIOPORTRANGER3 *PIOMIOPORTRANGER3;
+
+/**
+ * I/O port range descriptor, R0 version.
+ */
+typedef struct IOMIOPORTRANGER0
+{
+ /** Avl node core with Port as Key and Port + cPorts - 1 as KeyLast. */
+ AVLROIOPORTNODECORE Core;
+#if HC_ARCH_BITS == 64 && !defined(RT_OS_WINDOWS)
+ uint32_t u32Alignment; /**< The sizeof(Core) differs. */
+#endif
+ /** Start I/O port address. */
+ RTIOPORT Port;
+ /** Size of the range. */
+ uint16_t cPorts;
+ /** Pointer to user argument. */
+ RTR0PTR pvUser;
+ /** Pointer to the associated device instance. */
+ R0PTRTYPE(PPDMDEVINS) pDevIns;
+ /** Pointer to OUT callback function. */
+ R0PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback;
+ /** Pointer to IN callback function. */
+ R0PTRTYPE(PFNIOMIOPORTIN) pfnInCallback;
+ /** Pointer to string OUT callback function. */
+ R0PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback;
+ /** Pointer to string IN callback function. */
+ R0PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback;
+ /** Description / Name. For easing debugging. */
+ R3PTRTYPE(const char *) pszDesc;
+} IOMIOPORTRANGER0;
+/** Pointer to I/O port range descriptor, R0 version. */
+typedef IOMIOPORTRANGER0 *PIOMIOPORTRANGER0;
+
+/**
+ * I/O port range descriptor, RC version.
+ */
+typedef struct IOMIOPORTRANGERC
+{
+ /** Avl node core with Port as Key and Port + cPorts - 1 as KeyLast. */
+ AVLROIOPORTNODECORE Core;
+ /** Start I/O port address. */
+ RTIOPORT Port;
+ /** Size of the range. */
+ uint16_t cPorts;
+ /** Pointer to user argument. */
+ RTRCPTR pvUser;
+ /** Pointer to the associated device instance. */
+ RCPTRTYPE(PPDMDEVINS) pDevIns;
+ /** Pointer to OUT callback function. */
+ RCPTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback;
+ /** Pointer to IN callback function. */
+ RCPTRTYPE(PFNIOMIOPORTIN) pfnInCallback;
+ /** Pointer to string OUT callback function. */
+ RCPTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStrCallback;
+ /** Pointer to string IN callback function. */
+ RCPTRTYPE(PFNIOMIOPORTINSTRING) pfnInStrCallback;
+#if HC_ARCH_BITS == 64
+ RTRCPTR RCPtrAlignment; /**< pszDesc is 8 byte aligned. */
+#endif
+ /** Description / Name. For easing debugging. */
+ R3PTRTYPE(const char *) pszDesc;
+} IOMIOPORTRANGERC;
+/** Pointer to I/O port range descriptor, RC version. */
+typedef IOMIOPORTRANGERC *PIOMIOPORTRANGERC;
+
+
+/**
+ * I/O port statistics. (one I/O port)
+ *
+ * This is a simple way of making on demand statistics, however it's a
+ * bit free with the hypervisor heap memory.
+ */
+typedef struct IOMIOPORTSTATS
+{
+ /** Avl node core with the port as Key. */
+ AVLOIOPORTNODECORE Core;
+#if HC_ARCH_BITS != 64 || !defined(RT_OS_WINDOWS)
+ uint32_t u32Alignment; /**< The sizeof(Core) differs. */
+#endif
+ /** Number of INs to this port from R3. */
+ STAMCOUNTER InR3;
+ /** Profiling IN handler overhead in R3. */
+ STAMPROFILE ProfInR3;
+ /** Number of OUTs to this port from R3. */
+ STAMCOUNTER OutR3;
+ /** Profiling OUT handler overhead in R3. */
+ STAMPROFILE ProfOutR3;
+
+ /** Number of INs to this port from R0/RC. */
+ STAMCOUNTER InRZ;
+ /** Profiling IN handler overhead in R0/RC. */
+ STAMPROFILE ProfInRZ;
+ /** Number of INs to this port from R0/RC which was serviced in R3. */
+ STAMCOUNTER InRZToR3;
+
+ /** Number of OUTs to this port from R0/RC. */
+ STAMCOUNTER OutRZ;
+ /** Profiling OUT handler overhead in R0/RC. */
+ STAMPROFILE ProfOutRZ;
+ /** Number of OUTs to this port from R0/RC which was serviced in R3. */
+ STAMCOUNTER OutRZToR3;
+} IOMIOPORTSTATS;
+AssertCompileMemberAlignment(IOMIOPORTSTATS, InR3, 8);
+/** Pointer to I/O port statistics. */
+typedef IOMIOPORTSTATS *PIOMIOPORTSTATS;
+
+
+/**
+ * The IOM trees.
+ * These are offset based the nodes and root must be in the same
+ * memory block in HC. The locations of IOM structure and the hypervisor heap
+ * are quite different in R3, R0 and RC.
+ */
+typedef struct IOMTREES
+{
+ /** Tree containing I/O port range descriptors registered for HC (IOMIOPORTRANGEHC). */
+ AVLROIOPORTTREE IOPortTreeR3;
+ /** Tree containing I/O port range descriptors registered for R0 (IOMIOPORTRANGER0). */
+ AVLROIOPORTTREE IOPortTreeR0;
+ /** Tree containing I/O port range descriptors registered for RC (IOMIOPORTRANGERC). */
+ AVLROIOPORTTREE IOPortTreeRC;
+
+ /** Tree containing the MMIO range descriptors (IOMMMIORANGE). */
+ AVLROGCPHYSTREE MMIOTree;
+
+ /** Tree containing I/O port statistics (IOMIOPORTSTATS). */
+ AVLOIOPORTTREE IOPortStatTree;
+ /** Tree containing MMIO statistics (IOMMMIOSTATS). */
+ AVLOGCPHYSTREE MmioStatTree;
+} IOMTREES;
+/** Pointer to the IOM trees. */
+typedef IOMTREES *PIOMTREES;
+
+
+/**
+ * Converts an IOM pointer into a VM pointer.
+ * @returns Pointer to the VM structure the PGM is part of.
+ * @param pIOM Pointer to IOM instance data.
+ */
+#define IOM2VM(pIOM) ( (PVM)((char*)pIOM - pIOM->offVM) )
+
+/**
+ * IOM Data (part of VM)
+ */
+typedef struct IOM
+{
+ /** Offset to the VM structure. */
+ RTINT offVM;
+
+ /** Pointer to the trees - RC ptr. */
+ RCPTRTYPE(PIOMTREES) pTreesRC;
+ /** Pointer to the trees - R3 ptr. */
+ R3PTRTYPE(PIOMTREES) pTreesR3;
+ /** Pointer to the trees - R0 ptr. */
+ R0PTRTYPE(PIOMTREES) pTreesR0;
+
+ /** MMIO physical access handler type. */
+ PGMPHYSHANDLERTYPE hMmioHandlerType;
+ uint32_t u32Padding;
+
+ /** Lock serializing EMT access to IOM. */
+#ifdef IOM_WITH_CRIT_SECT_RW
+ PDMCRITSECTRW CritSect;
+#else
+ PDMCRITSECT CritSect;
+#endif
+
+ /** @name I/O Port statistics.
+ * @{ */
+ STAMCOUNTER StatInstIn;
+ STAMCOUNTER StatInstOut;
+ STAMCOUNTER StatInstIns;
+ STAMCOUNTER StatInstOuts;
+ /** @} */
+
+ /** @name MMIO statistics.
+ * @{ */
+ STAMPROFILE StatRZMMIOHandler;
+ STAMCOUNTER StatRZMMIOFailures;
+
+ STAMPROFILE StatRZInstMov;
+ STAMPROFILE StatRZInstCmp;
+ STAMPROFILE StatRZInstAnd;
+ STAMPROFILE StatRZInstOr;
+ STAMPROFILE StatRZInstXor;
+ STAMPROFILE StatRZInstBt;
+ STAMPROFILE StatRZInstTest;
+ STAMPROFILE StatRZInstXchg;
+ STAMPROFILE StatRZInstStos;
+ STAMPROFILE StatRZInstLods;
+#ifdef IOM_WITH_MOVS_SUPPORT
+ STAMPROFILEADV StatRZInstMovs;
+ STAMPROFILE StatRZInstMovsToMMIO;
+ STAMPROFILE StatRZInstMovsFromMMIO;
+ STAMPROFILE StatRZInstMovsMMIO;
+#endif
+ STAMCOUNTER StatRZInstOther;
+
+ STAMCOUNTER StatRZMMIO1Byte;
+ STAMCOUNTER StatRZMMIO2Bytes;
+ STAMCOUNTER StatRZMMIO4Bytes;
+ STAMCOUNTER StatRZMMIO8Bytes;
+
+ STAMCOUNTER StatR3MMIOHandler;
+
+ RTUINT cMovsMaxBytes;
+ RTUINT cStosMaxBytes;
+ /** @} */
+} IOM;
+/** Pointer to IOM instance data. */
+typedef IOM *PIOM;
+
+
+/**
+ * IOM per virtual CPU instance data.
+ */
+typedef struct IOMCPU
+{
+ /** For saving stack space, the disassembler state is allocated here instead of
+ * on the stack. */
+ DISCPUSTATE DisState;
+
+ /**
+ * Pending I/O port write commit (VINF_IOM_R3_IOPORT_COMMIT_WRITE).
+ *
+ * This is a converted VINF_IOM_R3_IOPORT_WRITE handler return that lets the
+ * execution engine commit the instruction and then return to ring-3 to complete
+ * the I/O port write there. This avoids having to decode the instruction again
+ * in ring-3.
+ */
+ struct
+ {
+ /** The value size (0 if not pending). */
+ uint16_t cbValue;
+ /** The I/O port. */
+ RTIOPORT IOPort;
+ /** The value. */
+ uint32_t u32Value;
+ } PendingIOPortWrite;
+
+ /**
+ * Pending MMIO write commit (VINF_IOM_R3_MMIO_COMMIT_WRITE).
+ *
+ * This is a converted VINF_IOM_R3_MMIO_WRITE handler return that lets the
+ * execution engine commit the instruction, stop any more REPs, and return to
+ * ring-3 to complete the MMIO write there. The avoid the tedious decoding of
+ * the instruction again once we're in ring-3, more importantly it allows us to
+ * correctly deal with read-modify-write instructions like XCHG, OR, and XOR.
+ */
+ struct
+ {
+ /** Guest physical MMIO address. */
+ RTGCPHYS GCPhys;
+ /** The value to write. */
+ uint8_t abValue[128];
+ /** The number of bytes to write (0 if nothing pending). */
+ uint32_t cbValue;
+ /** Alignment padding. */
+ uint32_t uAlignmentPadding;
+ } PendingMmioWrite;
+
+ /** @name Caching of I/O Port and MMIO ranges and statistics.
+ * (Saves quite some time in rep outs/ins instruction emulation.)
+ * @{ */
+ R3PTRTYPE(PIOMIOPORTRANGER3) pRangeLastReadR3;
+ R3PTRTYPE(PIOMIOPORTRANGER3) pRangeLastWriteR3;
+ R3PTRTYPE(PIOMIOPORTSTATS) pStatsLastReadR3;
+ R3PTRTYPE(PIOMIOPORTSTATS) pStatsLastWriteR3;
+ R3PTRTYPE(PIOMMMIORANGE) pMMIORangeLastR3;
+ R3PTRTYPE(PIOMMMIOSTATS) pMMIOStatsLastR3;
+
+ R0PTRTYPE(PIOMIOPORTRANGER0) pRangeLastReadR0;
+ R0PTRTYPE(PIOMIOPORTRANGER0) pRangeLastWriteR0;
+ R0PTRTYPE(PIOMIOPORTSTATS) pStatsLastReadR0;
+ R0PTRTYPE(PIOMIOPORTSTATS) pStatsLastWriteR0;
+ R0PTRTYPE(PIOMMMIORANGE) pMMIORangeLastR0;
+ R0PTRTYPE(PIOMMMIOSTATS) pMMIOStatsLastR0;
+
+ RCPTRTYPE(PIOMIOPORTRANGERC) pRangeLastReadRC;
+ RCPTRTYPE(PIOMIOPORTRANGERC) pRangeLastWriteRC;
+ RCPTRTYPE(PIOMIOPORTSTATS) pStatsLastReadRC;
+ RCPTRTYPE(PIOMIOPORTSTATS) pStatsLastWriteRC;
+ RCPTRTYPE(PIOMMMIORANGE) pMMIORangeLastRC;
+ RCPTRTYPE(PIOMMMIOSTATS) pMMIOStatsLastRC;
+ /** @} */
+} IOMCPU;
+/** Pointer to IOM per virtual CPU instance data. */
+typedef IOMCPU *PIOMCPU;
+
+
+RT_C_DECLS_BEGIN
+
+void iomMmioFreeRange(PVM pVM, PIOMMMIORANGE pRange);
+#ifdef IN_RING3
+PIOMMMIOSTATS iomR3MMIOStatsCreate(PVM pVM, RTGCPHYS GCPhys, const char *pszDesc);
+#endif /* IN_RING3 */
+
+#ifndef IN_RING3
+DECLEXPORT(FNPGMRZPHYSPFHANDLER) iomMmioPfHandler;
+#endif
+PGM_ALL_CB2_PROTO(FNPGMPHYSHANDLER) iomMmioHandler;
+
+/* IOM locking helpers. */
+#ifdef IOM_WITH_CRIT_SECT_RW
+# define IOM_LOCK_EXCL(a_pVM) PDMCritSectRwEnterExcl(&(a_pVM)->iom.s.CritSect, VERR_SEM_BUSY)
+# define IOM_UNLOCK_EXCL(a_pVM) do { PDMCritSectRwLeaveExcl(&(a_pVM)->iom.s.CritSect); } while (0)
+# if 0 /* (in case needed for debugging) */
+# define IOM_LOCK_SHARED_EX(a_pVM, a_rcBusy) PDMCritSectRwEnterExcl(&(a_pVM)->iom.s.CritSect, (a_rcBusy))
+# define IOM_UNLOCK_SHARED(a_pVM) do { PDMCritSectRwLeaveExcl(&(a_pVM)->iom.s.CritSect); } while (0)
+# define IOM_IS_SHARED_LOCK_OWNER(a_pVM) PDMCritSectRwIsWriteOwner(&(a_pVM)->iom.s.CritSect)
+# else
+# define IOM_LOCK_SHARED_EX(a_pVM, a_rcBusy) PDMCritSectRwEnterShared(&(a_pVM)->iom.s.CritSect, (a_rcBusy))
+# define IOM_UNLOCK_SHARED(a_pVM) do { PDMCritSectRwLeaveShared(&(a_pVM)->iom.s.CritSect); } while (0)
+# define IOM_IS_SHARED_LOCK_OWNER(a_pVM) PDMCritSectRwIsReadOwner(&(a_pVM)->iom.s.CritSect, true)
+# endif
+# define IOM_IS_EXCL_LOCK_OWNER(a_pVM) PDMCritSectRwIsWriteOwner(&(a_pVM)->iom.s.CritSect)
+#else
+# define IOM_LOCK_EXCL(a_pVM) PDMCritSectEnter(&(a_pVM)->iom.s.CritSect, VERR_SEM_BUSY)
+# define IOM_UNLOCK_EXCL(a_pVM) do { PDMCritSectLeave(&(a_pVM)->iom.s.CritSect); } while (0)
+# define IOM_LOCK_SHARED_EX(a_pVM, a_rcBusy) PDMCritSectEnter(&(a_pVM)->iom.s.CritSect, (a_rcBusy))
+# define IOM_UNLOCK_SHARED(a_pVM) do { PDMCritSectLeave(&(a_pVM)->iom.s.CritSect); } while (0)
+# define IOM_IS_SHARED_LOCK_OWNER(a_pVM) PDMCritSectIsOwner(&(a_pVM)->iom.s.CritSect)
+# define IOM_IS_EXCL_LOCK_OWNER(a_pVM) PDMCritSectIsOwner(&(a_pVM)->iom.s.CritSect)
+#endif
+#define IOM_LOCK_SHARED(a_pVM) IOM_LOCK_SHARED_EX(a_pVM, VERR_SEM_BUSY)
+
+
+RT_C_DECLS_END
+
+
+#ifdef IN_RING3
+
+#endif
+
+/** @} */
+
+#endif /* !VMM_INCLUDED_SRC_include_IOMInternal_h */
+