Index: /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 87833)
+++ /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 87834)
@@ -351,4 +351,8 @@
     /** The event semaphore the command thread waits on. */
     SUPSEMEVENT                 hEvtCmdThread;
+    /** Whether the command thread has been signaled for wake up. */
+    bool volatile               fCmdThreadSignaled;
+    /** Padding. */
+    bool                        afPadding0[7];
 
 #ifdef IOMMU_WITH_DTE_CACHE
@@ -565,10 +569,4 @@
     /** The command thread handle. */
     R3PTRTYPE(PPDMTHREAD)       pCmdThread;
-    /** Whether the command thread is sleeping. */
-    bool volatile               fCmdThreadSleeping;
-    /** Whether the command thread has been signaled for wake up. */
-    bool volatile               fCmdThreadSignaled;
-    /** Alignment padding. */
-    uint8_t                     afPadding0[6];
 #ifdef IOMMU_WITH_IOTLBE_CACHE
     /** Pointer to array of pre-allocated IOTLBEs. */
@@ -1296,5 +1294,5 @@
 {
     PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    PIOMMUCC pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
+    PIOMMUR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
     IOMMU_LOCK_CACHE_NORET(pDevIns, pThis);
 
@@ -1659,6 +1657,5 @@
 
 /**
- * Wakes up the command thread if there are commands to be processed or if
- * processing is requested to be stopped by software.
+ * Wakes up the command thread if there are commands to be processed.
  *
  * @param   pDevIns     The IOMMU device instance.
@@ -1670,6 +1667,8 @@
     Log4Func(("\n"));
 
-    PCIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    if (pThis->Status.n.u1CmdBufRunning)
+    PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    if (    pThis->Status.n.u1CmdBufRunning
+        &&  pThis->CmdBufTailPtr.n.off != pThis->CmdBufHeadPtr.n.off
+        && !ASMAtomicXchgBool(&pThis->fCmdThreadSignaled, true))
     {
         Log4Func(("Signaling command thread\n"));
@@ -2136,5 +2135,5 @@
                 LogFunc(("Command buffer enabled\n"));
 
-                /* Wake up the command thread to start processing commands. */
+                /* Wake up the command thread to start processing commands if any. */
                 iommuAmdCmdThreadWakeUpIfNeeded(pDevIns);
             }
@@ -4768,5 +4767,5 @@
 {
     PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
+    PIOMMUR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
 
     STAM_COUNTER_INC(&pThis->StatCmd);
@@ -4803,8 +4802,8 @@
                 if (pCmdComWait->n.u1Interrupt)
                 {
-                    IOMMU_LOCK(pDevIns, pThisCC);
+                    IOMMU_LOCK(pDevIns, pThisR3);
                     ASMAtomicOrU64(&pThis->Status.u64, IOMMU_STATUS_COMPLETION_WAIT_INTR);
                     bool const fRaiseInt = pThis->Ctrl.n.u1CompWaitIntrEn;
-                    IOMMU_UNLOCK(pDevIns, pThisCC);
+                    IOMMU_UNLOCK(pDevIns, pThisR3);
 
                     if (fRaiseInt)
@@ -4998,5 +4997,5 @@
 {
     PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    PIOMMUCC pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
+    PIOMMUR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
 
     if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
@@ -5017,18 +5016,13 @@
          * Sleep perpetually until we are woken up to process commands.
          */
-        {
-            ASMAtomicWriteBool(&pThisR3->fCmdThreadSleeping, true);
-            bool fSignaled = ASMAtomicXchgBool(&pThisR3->fCmdThreadSignaled, false);
-            if (!fSignaled)
-            {
-                Assert(ASMAtomicReadBool(&pThisR3->fCmdThreadSleeping));
-                int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtCmdThread, RT_INDEFINITE_WAIT);
-                AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
-                if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
-                    break;
-                Log4Func(("Woken up with rc=%Rrc\n", rc));
-                ASMAtomicWriteBool(&pThisR3->fCmdThreadSignaled, false);
-            }
-            ASMAtomicWriteBool(&pThisR3->fCmdThreadSleeping, false);
+        bool const fSignaled = ASMAtomicXchgBool(&pThis->fCmdThreadSignaled, false);
+        if (!fSignaled)
+        {
+            int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEvtCmdThread, RT_INDEFINITE_WAIT);
+            AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
+            if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
+                break;
+            Log4Func(("Woken up with rc=%Rrc\n", rc));
+            ASMAtomicWriteBool(&pThis->fCmdThreadSignaled, false);
         }
 
@@ -5175,6 +5169,6 @@
     }
 
-    PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
-    IOMMU_LOCK(pDevIns, pThisCC);
+    PIOMMUR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
+    IOMMU_LOCK(pDevIns, pThisR3);
 
     VBOXSTRICTRC rcStrict = VERR_IOMMU_IPE_3;
@@ -5256,5 +5250,5 @@
     }
 
-    IOMMU_UNLOCK(pDevIns, pThisCC);
+    IOMMU_UNLOCK(pDevIns, pThisR3);
 
     Log3Func(("uAddress=%#x (cb=%u) with %#x. rc=%Rrc\n", uAddress, cb, u32Value, VBOXSTRICTRC_VAL(rcStrict)));
@@ -5972,5 +5966,5 @@
             pHlp->pfnPrintf(pHlp, "IOTLBEs for domain %u (%#x):\n", uDomainId, uDomainId);
             PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-            PIOMMUCC pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
+            PIOMMUR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
             IOTLBEINFOARG Args;
             Args.pIommuR3  = pThisR3;
@@ -6128,24 +6122,252 @@
 
 /**
+ * @callback_method_impl{FNSSMDEVLIVEEXEC}
+ */
+static DECLCALLBACK(int) iommuAmdR3LiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
+{
+    PCIOMMU       pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    PCPDMDEVHLPR3 pHlp  = pDevIns->pHlpR3;
+    RT_NOREF(uPass);
+    LogFlowFunc(("\n"));
+
+    /* Save registers that cannot be modified by the guest. */
+    pHlp->pfnSSMPutU64(pSSM, pThis->ExtFeat.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->DevSpecificFeat.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->DevSpecificCtrl.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->DevSpecificStatus.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->MiscInfo.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->RsvdReg);
+
+    return VINF_SSM_DONT_CALL_AGAIN;
+}
+
+
+/**
  * @callback_method_impl{FNSSMDEVSAVEEXEC}
  */
 static DECLCALLBACK(int) iommuAmdR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
 {
-    /** @todo IOMMU: Save state. */
-    RT_NOREF2(pDevIns, pSSM);
+    PCIOMMU       pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    PCPDMDEVHLPR3 pHlp  = pDevIns->pHlpR3;
     LogFlowFunc(("\n"));
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->IommuBar.u64);
+
+    uint8_t const cDevTabBaseAddrs = RT_ELEMENTS(pThis->aDevTabBaseAddrs);
+    pHlp->pfnSSMPutU8(pSSM, cDevTabBaseAddrs);
+    for (uint8_t i = 0; i < cDevTabBaseAddrs; i++)
+        pHlp->pfnSSMPutU64(pSSM, pThis->aDevTabBaseAddrs[i].u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->CmdBufBaseAddr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->EvtLogBaseAddr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->Ctrl.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->ExclRangeBaseAddr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->ExclRangeLimit.u64);
+#if 0
+    pHlp->pfnSSMPutU64(pSSM, pThis->ExtFeat.u64);  /* read-only, done in liveExec */
+#endif
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogBaseAddr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->HwEvtHi.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->HwEvtLo);
+    pHlp->pfnSSMPutU64(pSSM, pThis->HwEvtStatus.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->GALogBaseAddr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->GALogTailAddr.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogBBaseAddr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->EvtLogBBaseAddr.u64);
+
+#if 0
+    pHlp->pfnSSMPutU64(pSSM, pThis->DevSpecificFeat.u64);       /* read-only, done in liveExec */
+    pHlp->pfnSSMPutU64(pSSM, pThis->DevSpecificCtrl.u64);       /* read-only, done in liveExec */
+    pHlp->pfnSSMPutU64(pSSM, pThis->DevSpecificStatus.u64);     /* read-only, done in liveExec */
+#endif
+
+#if 0
+    pHlp->pfnSSMPutU64(pSSM, pThis->MiscInfo.u64);              /* read-only, done in liveExec */
+#endif
+    pHlp->pfnSSMPutU32(pSSM, pThis->PerfOptCtrl.u32);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->XtGenIntrCtrl.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->XtPprIntrCtrl.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->XtGALogIntrCtrl.u64);
+
+    size_t const cMarcApers = RT_ELEMENTS(pThis->aMarcApers);
+    pHlp->pfnSSMPutU8(pSSM, cMarcApers);
+    for (size_t i = 0; i < cMarcApers; i++)
+    {
+        pHlp->pfnSSMPutU64(pSSM, pThis->aMarcApers[i].Base.u64);
+        pHlp->pfnSSMPutU64(pSSM, pThis->aMarcApers[i].Reloc.u64);
+        pHlp->pfnSSMPutU64(pSSM, pThis->aMarcApers[i].Length.u64);
+    }
+
+#if 0
+    pHlp->pfnSSMPutU64(pSSM, pThis->RsvdReg);       /* read-only, done in liveExec */
+#endif
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->CmdBufHeadPtr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->CmdBufTailPtr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->EvtLogHeadPtr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->EvtLogTailPtr.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->Status.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogHeadPtr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogTailPtr.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->GALogHeadPtr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->GALogTailPtr.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogBHeadPtr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogBTailPtr.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->EvtLogBHeadPtr.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->EvtLogBTailPtr.u64);
+
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogAutoResp.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogOverflowEarly.u64);
+    pHlp->pfnSSMPutU64(pSSM, pThis->PprLogBOverflowEarly.u64);
+
+    return pHlp->pfnSSMPutU32(pSSM, UINT32_MAX);
+}
+
+
+/**
+ * @callback_method_impl{FNSSMDEVLOADEXEC}
+ */
+static DECLCALLBACK(int) iommuAmdR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
+{
+    PIOMMU        pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
+    PCPDMDEVHLPR3 pHlp  = pDevIns->pHlpR3;
+    LogFlowFunc(("\n"));
+
+    /* Validate. */
+    if (uPass != SSM_PASS_FINAL)
+        return VINF_SUCCESS;
+    if (uVersion != IOMMU_SAVED_STATE_VERSION)
+        return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
+    int const rcDataError = VERR_SSM_UNEXPECTED_DATA;
+
+    int rc = pHlp->pfnSSMGetU64(pSSM, &pThis->ExtFeat.u64);
+    AssertRCReturn(rc, rc);
+    AssertLogRelMsgReturn(pThis->ExtFeat.n.u2HostAddrTranslateSize < 0x3,
+                          ("ExtFeat invalid %#RX64\n", pThis->ExtFeat.u64), rcDataError);
+
+    pHlp->pfnSSMGetU64(pSSM, &pThis->DevSpecificFeat.u64);
+    pHlp->pfnSSMGetU64(pSSM, &pThis->DevSpecificCtrl.u64);
+    pHlp->pfnSSMGetU64(pSSM, &pThis->DevSpecificStatus.u64);
+    pHlp->pfnSSMGetU64(pSSM, &pThis->MiscInfo.u64);
+    pHlp->pfnSSMGetU64(pSSM, &pThis->RsvdReg);
+
+    /* Device table base address registers. */
+    uint8_t cDevTabBaseAddrs;
+    rc = pHlp->pfnSSMGetU8(pSSM, &cDevTabBaseAddrs);
+    AssertRCReturn(rc, rc);
+    AssertLogRelMsgReturn(cDevTabBaseAddrs <= RT_ELEMENTS(pThis->aDevTabBaseAddrs),
+                          ("Device table segment count invalid %#x\n", cDevTabBaseAddrs), rcDataError);
+    for (uint8_t i = 0; i < cDevTabBaseAddrs; i++)
+    {
+        rc = pHlp->pfnSSMGetU64(pSSM, &pThis->aDevTabBaseAddrs[i].u64);
+        AssertRCReturn(rc, rc);
+        pThis->aDevTabBaseAddrs[i].u64 &= IOMMU_DEV_TAB_BAR_VALID_MASK;
+        AssertLogRelMsgReturn(pThis->aDevTabBaseAddrs[i].n.u9Size <= g_auDevTabSegMaxSizes[0],
+                              ("Device table segment size invalid %#x\n", pThis->aDevTabBaseAddrs[i].n.u9Size), rcDataError);
+    }
+
+    /* Command buffer base address register. */
+    rc = pHlp->pfnSSMGetU64(pSSM, &pThis->CmdBufBaseAddr.u64);
+    AssertRCReturn(rc, rc);
+    pThis->CmdBufBaseAddr.u64 &= IOMMU_CMD_BUF_BAR_VALID_MASK;
+    AssertLogRelMsgReturn(pThis->CmdBufBaseAddr.n.u4Len >= 8,
+                          ("Command buffer base address invalid %#RX64\n", pThis->CmdBufBaseAddr.u64), rcDataError);
+
+    /* Event log base address register. */
+    pHlp->pfnSSMPutU64(pSSM, pThis->EvtLogBaseAddr.u64);
+    rc = pHlp->pfnSSMGetU64(pSSM, &pThis->EvtLogBaseAddr.u64);
+    AssertRCReturn(rc, rc);
+    pThis->EvtLogBaseAddr.u64 &= IOMMU_EVT_LOG_BAR_VALID_MASK;
+    AssertLogRelMsgReturn(pThis->EvtLogBaseAddr.n.u4Len >= 8,
+                          ("Event log base address invalid %#RX64\n", pThis->EvtLogBaseAddr.u64), rcDataError);
+
+    /* Control register. */
+    rc = pHlp->pfnSSMPutU64(pSSM, pThis->Ctrl.u64);
+    AssertRCReturn(rc, rc);
+    pThis->Ctrl.u64 &= IOMMU_CTRL_VALID_MASK;
+    AssertLogRelMsgReturn(pThis->Ctrl.n.u3DevTabSegEn <= pThis->ExtFeat.n.u2DevTabSegSup,
+                          ("Control register invalid %#RX64\n", pThis->Ctrl.u64), rcDataError);
+
+    /** @todo The rest. */
     return VERR_NOT_IMPLEMENTED;
-}
-
-
-/**
- * @callback_method_impl{FNSSMDEVLOADEXEC}
- */
-static DECLCALLBACK(int) iommuAmdR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
-{
-    /** @todo IOMMU: Load state. */
-    RT_NOREF4(pDevIns, pSSM, uVersion, uPass);
-    LogFlowFunc(("\n"));
-    return VERR_NOT_IMPLEMENTED;
+#if 0
+    pThis->ExclRangeBaseAddr.u64
+    pThis->ExclRangeLimit.u64
+#if 0
+    pThis->ExtFeat.u64;  /* read-only, done in liveExec */
+#endif
+
+    pThis->PprLogBaseAddr.u64);
+    pThis->HwEvtHi.u64);
+    pThis->HwEvtLo);
+    pThis->HwEvtStatus.u64);
+
+    pThis->GALogBaseAddr.u64);
+    pThis->GALogTailAddr.u64);
+
+    pThis->PprLogBBaseAddr.u64);
+    pThis->EvtLogBBaseAddr.u64);
+
+#if 0
+    pThis->DevSpecificFeat.u64);       /* read-only, done in liveExec */
+    pThis->DevSpecificCtrl.u64);       /* read-only, done in liveExec */
+    pThis->DevSpecificStatus.u64);     /* read-only, done in liveExec */
+#endif
+
+#if 0
+    pThis->MiscInfo.u64);              /* read-only, done in liveExec */
+#endif
+    pThis->PerfOptCtrl.u32);
+
+    pThis->XtGenIntrCtrl.u64);
+    pThis->XtPprIntrCtrl.u64);
+    pThis->XtGALogIntrCtrl.u64);
+
+    size_t const cMarcApers = RT_ELEMENTS(pThis->aMarcApers);
+    pHlp->pfnSSMPutU8(pSSM, cMarcApers);
+    for (size_t i = 0; i < cMarcApers; i++)
+    {
+        pHlp->pfnSSMPutU64(pSSM, pThis->aMarcApers[i].Base.u64);
+        pHlp->pfnSSMPutU64(pSSM, pThis->aMarcApers[i].Reloc.u64);
+        pHlp->pfnSSMPutU64(pSSM, pThis->aMarcApers[i].Length.u64);
+    }
+
+#if 0
+    pHlp->pfnSSMPutU64(pSSM, pThis->RsvdReg);       /* read-only, done in liveExec */
+#endif
+
+    pThis->CmdBufHeadPtr.u64);
+    pThis->CmdBufTailPtr.u64);
+    pThis->EvtLogHeadPtr.u64);
+    pThis->EvtLogTailPtr.u64);
+
+    pThis->Status.u64);
+
+    pThis->PprLogHeadPtr.u64);
+    pThis->PprLogTailPtr.u64);
+
+    pThis->GALogHeadPtr.u64);
+    pThis->GALogTailPtr.u64);
+
+    pThis->PprLogBHeadPtr.u64);
+    pThis->PprLogBTailPtr.u64);
+
+    pThis->EvtLogBHeadPtr.u64);
+    pThis->EvtLogBTailPtr.u64);
+
+    pThis->PprLogAutoResp.u64);
+    pThis->PprLogOverflowEarly.u64);
+    pThis->PprLogBOverflowEarly.u64);
+
+    return VINF_SUCCESS;
+#endif
 }
 
@@ -6163,13 +6385,12 @@
      */
     PIOMMU     pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    PIOMMUCC   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
+    PIOMMUR3   pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
     PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
     PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
-
-    IOMMU_LOCK_NORET(pDevIns, pThisCC);
-
     LogFlowFunc(("\n"));
 
-    memset(&pThis->aDevTabBaseAddrs[0], 0, sizeof(pThis->aDevTabBaseAddrs));
+    IOMMU_LOCK_NORET(pDevIns, pThisR3);
+
+    RT_ZERO(pThis->aDevTabBaseAddrs);
 
     pThis->CmdBufBaseAddr.u64        = 0;
@@ -6209,5 +6430,5 @@
     pThis->XtGALogIntrCtrl.u64       = 0;
 
-    memset(&pThis->aMarcApers[0], 0, sizeof(pThis->aMarcApers));
+    RT_ZERO(pThis->aMarcApers);
 
     pThis->CmdBufHeadPtr.u64         = 0;
@@ -6240,5 +6461,5 @@
     PDMPciDevSetCommand(pPciDev, VBOX_PCI_COMMAND_MASTER);
 
-    IOMMU_UNLOCK(pDevIns, pThisCC);
+    IOMMU_UNLOCK(pDevIns, pThisR3);
 
 #ifdef IOMMU_WITH_DTE_CACHE
@@ -6261,5 +6482,5 @@
     PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
     PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    PIOMMUCC pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
+    PIOMMUR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
     LogFlowFunc(("\n"));
 
@@ -6297,7 +6518,7 @@
 
     PIOMMU   pThis   = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
-    PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC);
+    PIOMMUR3 pThisR3 = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUR3);
     pThis->u32Magic = IOMMU_MAGIC;
-    pThisCC->pDevInsR3 = pDevIns;
+    pThisR3->pDevInsR3 = pDevIns;
 
     LogFlowFunc(("iInstance=%d\n", iInstance));
@@ -6313,15 +6534,15 @@
     IommuReg.pfnMsiRemap      = iommuAmdMsiRemap;
     IommuReg.u32TheEnd        = PDM_IOMMUREGCC_VERSION;
-    int rc = PDMDevHlpIommuRegister(pDevIns, &IommuReg, &pThisCC->CTX_SUFF(pIommuHlp), &pThis->idxIommu);
+    int rc = PDMDevHlpIommuRegister(pDevIns, &IommuReg, &pThisR3->CTX_SUFF(pIommuHlp), &pThis->idxIommu);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as an IOMMU device"));
-    if (pThisCC->CTX_SUFF(pIommuHlp)->u32Version != PDM_IOMMUHLPR3_VERSION)
+    if (pThisR3->CTX_SUFF(pIommuHlp)->u32Version != PDM_IOMMUHLPR3_VERSION)
         return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
                                    N_("IOMMU helper version mismatch; got %#x expected %#x"),
-                                   pThisCC->CTX_SUFF(pIommuHlp)->u32Version, PDM_IOMMUHLPR3_VERSION);
-    if (pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd != PDM_IOMMUHLPR3_VERSION)
+                                   pThisR3->CTX_SUFF(pIommuHlp)->u32Version, PDM_IOMMUHLPR3_VERSION);
+    if (pThisR3->CTX_SUFF(pIommuHlp)->u32TheEnd != PDM_IOMMUHLPR3_VERSION)
         return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
                                    N_("IOMMU helper end-version mismatch; got %#x expected %#x"),
-                                   pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd, PDM_IOMMUHLPR3_VERSION);
+                                   pThisR3->CTX_SUFF(pIommuHlp)->u32TheEnd, PDM_IOMMUHLPR3_VERSION);
 
     /*
@@ -6451,8 +6672,6 @@
      * Register saved state.
      */
-    rc = PDMDevHlpSSMRegisterEx(pDevIns, IOMMU_SAVED_STATE_VERSION, sizeof(IOMMU), NULL,
-                                NULL, NULL, NULL,
-                                NULL, iommuAmdR3SaveExec, NULL,
-                                NULL, iommuAmdR3LoadExec, NULL);
+    rc = PDMDevHlpSSMRegister3(pDevIns, IOMMU_SAVED_STATE_VERSION, sizeof(IOMMU), iommuAmdR3LiveExec, iommuAmdR3SaveExec,
+                               iommuAmdR3LoadExec);
     AssertLogRelRCReturn(rc, rc);
 
@@ -6536,5 +6755,5 @@
     RT_ZERO(szDevIommu);
     RTStrPrintf(szDevIommu, sizeof(szDevIommu), "IOMMU-%u", iInstance);
-    rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pCmdThread, pThis, iommuAmdR3CmdThread, iommuAmdR3CmdThreadWakeUp,
+    rc = PDMDevHlpThreadCreate(pDevIns, &pThisR3->pCmdThread, pThis, iommuAmdR3CmdThread, iommuAmdR3CmdThreadWakeUp,
                                0 /* cbStack */, RTTHREADTYPE_IO, szDevIommu);
     AssertLogRelRCReturn(rc, rc);
@@ -6563,9 +6782,9 @@
      */
     size_t const cbIotlbes = sizeof(IOTLBE) * IOMMU_IOTLBE_MAX;
-    pThisCC->paIotlbes = (PIOTLBE)PDMDevHlpMMHeapAllocZ(pDevIns, cbIotlbes);
-    if (!pThisCC->paIotlbes)
+    pThisR3->paIotlbes = (PIOTLBE)PDMDevHlpMMHeapAllocZ(pDevIns, cbIotlbes);
+    if (!pThisR3->paIotlbes)
         return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
                                    N_("Failed to allocate %zu bytes from the hyperheap for the IOTLB cache."), cbIotlbes);
-    RTListInit(&pThisCC->LstLruIotlbe);
+    RTListInit(&pThisR3->LstLruIotlbe);
     LogRel(("%s: Allocated %zu bytes from the hyperheap for the IOTLB cache\n", IOMMU_LOG_PFX, cbIotlbes));
 #endif
@@ -6614,6 +6833,4 @@
     //pThis->ExtFeat.n.u1ForcePhysDstSup       = 0;
 
-    pThis->RsvdReg = 0;
-
     pThis->DevSpecificFeat.u64   = 0;
     pThis->DevSpecificFeat.n.u4RevMajor = IOMMU_DEVSPEC_FEAT_MAJOR_VERSION;
@@ -6629,4 +6846,6 @@
 
     pThis->MiscInfo.u64 = RT_MAKE_U64(uMiscInfoReg0, uMiscInfoReg1);
+
+    pThis->RsvdReg = 0;
 
     /*
