Index: /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 83702)
+++ /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 83703)
@@ -1266,4 +1266,5 @@
 } IOMMU_HW_EVT_STATUS_T;
 AssertCompileSize(IOMMU_HW_EVT_STATUS_T, 8);
+#define IOMMU_HW_EVT_STATUS_VALID_MASK      UINT64_C(0x0000000000000003)
 
 /**
@@ -1842,12 +1843,12 @@
 typedef struct IOMMU
 {
+    /** The event semaphore the command thread waits on. */
+    SUPSEMEVENT                 hEvtCmdThread;
+    /** The MMIO handle. */
+    IOMMMIOHANDLE               hMmio;
     /** Whether this IOMMU is at the top of the PCI tree hierarchy or not. */
     bool                        fRootComplex;
     /** Alignment padding. */
-    bool                        afPadding[3];
-    /** The MMIO handle. */
-    IOMMMIOHANDLE               hMmio;
-    /** The event semaphore the command thread waits on. */
-    SUPSEMEVENT                 hEvtCmdThread;
+    bool                        afPadding[7];
 
     /** @name MMIO: Control and status registers.
@@ -1985,4 +1986,6 @@
 typedef struct IOMMUR3
 {
+    /** Device instance. */
+    PPDMDEVINSR3            pDevInsR3;
     /** The IOMMU helpers. */
     PCPDMIOMMUHLPR3         pIommuHlp;
@@ -1998,4 +2001,6 @@
 typedef struct IOMMUR0
 {
+    /** Device instance. */
+    PPDMDEVINSR0            pDevInsR0;
     /** The IOMMU helpers. */
     PCPDMIOMMUHLPR0         pIommuHlp;
@@ -2009,4 +2014,6 @@
 typedef struct IOMMURC
 {
+    /** Device instance. */
+    PPDMDEVINSR0            pDevInsRC;
     /** The IOMMU helpers. */
     PCPDMIOMMUHLPRC         pIommuHlp;
@@ -2016,5 +2023,5 @@
 
 /** The IOMMU device state for the current context. */
-typedef CTX_SUFF(IOMMU) IOMMUCC;
+typedef CTX_SUFF(IOMMU)  IOMMUCC;
 /** Pointer to the IOMMU device state for the current context. */
 typedef CTX_SUFF(PIOMMU) PIOMMUCC;
@@ -2117,4 +2124,5 @@
 }
 
+
 /**
  * Writes the Event Log Base Address Register.
@@ -2159,4 +2167,57 @@
     pThis->PprLogBaseAddr.u64 = u64Value & IOMMU_PPR_LOG_BAR_VALID_MASK;
     iommuAmdCheckBufferLength(pThis->PprLogBaseAddr.n.u4PprLogLen, __PRETTY_FUNCTION__);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Writes the Hardware Event Register (Hi).
+ */
+static VBOXSTRICTRC iommuAmdHwEvtHi_w(PPDMDEVINS pDevIns, PIOMMU pThis, uint32_t iReg, uint64_t u64Value)
+{
+    /** @todo IOMMU: Why the heck is this marked read/write by the AMD IOMMU spec? */
+    RT_NOREF(pDevIns, iReg);
+    Log((IOMMU_LOG_PFX ": Writing %#RX64 to hardware event (Hi) register!\n", u64Value));
+    pThis->HwEvtHi.u64 = u64Value;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Writes the Hardware Event Register (Lo).
+ */
+static VBOXSTRICTRC iommuAmdHwEvtLo_w(PPDMDEVINS pDevIns, PIOMMU pThis, uint32_t iReg, uint64_t u64Value)
+{
+    /** @todo IOMMU: Why the heck is this marked read/write by the AMD IOMMU spec? */
+    RT_NOREF(pDevIns, iReg);
+    Log((IOMMU_LOG_PFX ": Writing %#RX64 to hardware event (Lo) register!\n", u64Value));
+    pThis->HwEvtLo = u64Value;
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Writes the Hardware Event Status Register.
+ */
+static VBOXSTRICTRC iommuAmdHwEvtStatus_w(PPDMDEVINS pDevIns, PIOMMU pThis, uint32_t iReg, uint64_t u64Value)
+{
+    RT_NOREF(pDevIns, iReg);
+
+    /* Ignore all unrecognized bits. */
+    u64Value &= IOMMU_HW_EVT_STATUS_VALID_MASK;
+
+    /*
+     * The two bits (HEO and HEV) are RW1C (Read/Write 1-to-Clear; writing 0 has no effect).
+     * If the current status bits or the bits being written are both 0, we've nothing to do.
+     * The Overflow bit (bit 1) is only valid when the Valid bit (bit 0) is 1.
+     */
+    uint64_t HwStatus = pThis->HwEvtStatus.u64;
+    if (!(HwStatus & RT_BIT(0)))
+        return VINF_SUCCESS;
+    if (u64Value & HwStatus & RT_BIT(0))
+        HwStatus &= ~RT_BIT(0);
+    if (u64Value & HwStatus & RT_BIT(1))
+        HwStatus &= ~RT_BIT(1);
+    pThis->HwEvtStatus.u64 = HwStatus;
     return VINF_SUCCESS;
 }
@@ -2354,7 +2415,7 @@
 
         case IOMMU_MMIO_OFF_PPR_LOG_BAR:         return iommuAmdPprLogBar_w(pDevIns, pThis, off, uValue);
-        case IOMMU_MMIO_OFF_HW_EVT_HI:
-        case IOMMU_MMIO_OFF_HW_EVT_LO:           return iommuAmdIgnore_w(pDevIns, pThis, off, uValue);
-        case IOMMU_MMIO_OFF_HW_EVT_STATUS:       /** @todo IOMMU: HW Event Status is RW. Figure this out later. */
+        case IOMMU_MMIO_OFF_HW_EVT_HI:           return iommuAmdHwEvtHi_w(pDevIns, pThis, off, uValue);
+        case IOMMU_MMIO_OFF_HW_EVT_LO:           return iommuAmdHwEvtLo_w(pDevIns, pThis, off, uValue);
+        case IOMMU_MMIO_OFF_HW_EVT_STATUS:       return iommuAmdHwEvtStatus_w(pDevIns, pThis, off, uValue);
 
         case IOMMU_MMIO_OFF_GALOG_BAR:
@@ -2474,12 +2535,15 @@
  *
  * @returns Strict VBox status code.
- * @param   pThis       The IOMMU device state.
+ * @param   pDevIns     The device instance.
  * @param   off         Offset in bytes.
  * @param   puResult    Where to store the value being read.
  */
-static VBOXSTRICTRC iommuAmdReadRegister(PCIOMMU pThis, uint32_t off, uint64_t *puResult)
+static VBOXSTRICTRC iommuAmdReadRegister(PPDMDEVINS pDevIns, uint32_t off, uint64_t *puResult)
 {
     Assert(off < IOMMU_MMIO_REGION_SIZE);
     Assert(!(off & 7) || !(off & 3));
+
+    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    Assert(pThis);
 
     /** @todo IOMMU: fine-grained locking? */
@@ -2618,6 +2682,5 @@
 
     uint64_t uResult;
-    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    VBOXSTRICTRC rcStrict = iommuAmdReadRegister(pThis, off, &uResult);
+    VBOXSTRICTRC rcStrict = iommuAmdReadRegister(pDevIns, off, &uResult);
     if (cb == 8)
         *(uint64_t *)pv = uResult;
@@ -3366,5 +3429,5 @@
     LogFlowFunc(("\n"));
 
-    NOREF(pThisCC); /** @todo IOMMU: populate CC data. */
+    pThisCC->pDevInsR3 = pDevIns;
 
     /*
@@ -3536,4 +3599,12 @@
 {
     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
+    PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
+
+    pThisCC->CTX_SUFF(pDevIns) = pDevIns;
+
+    int rc = PDMDevHlpMmioSetUpContext(pDevIns, pThis->hMmio, iommuAmdMmioWrite, iommuAmdMmioRead, NULL /* pvUser */);
+    AssertRCReturn(rc, rc);
+
     return VINF_SUCCESS;
 }
