Index: /trunk/include/VBox/msi.h
===================================================================
--- /trunk/include/VBox/msi.h	(revision 84676)
+++ /trunk/include/VBox/msi.h	(revision 84677)
@@ -213,7 +213,7 @@
 {
     /** The MSI Address Register. */
-    MSIADDR      MsiAddr;
+    MSIADDR      Addr;
     /** The MSI Data Register. */
-    MSIDATA      MsiData;
+    MSIDATA     Data;
 } MSIMSG;
 /** Pointer to an MSI message struct. */
Index: /trunk/include/VBox/vmm/pdmdev.h
===================================================================
--- /trunk/include/VBox/vmm/pdmdev.h	(revision 84676)
+++ /trunk/include/VBox/vmm/pdmdev.h	(revision 84677)
@@ -48,4 +48,5 @@
 #include <VBox/vmm/pgm.h> /* PGMR3HandlerPhysicalTypeRegister() argument types. */
 #include <VBox/err.h>  /* VINF_EM_DBG_STOP, also 120+ source files expecting this. */
+#include <VBox/msi.h>
 #include <iprt/stdarg.h>
 #include <iprt/list.h>
@@ -1291,13 +1292,10 @@
      * @param   pDevIns     The IOMMU device instance.
      * @param   uDevId      The device identifier (bus, device, function).
-     * @param   GCPhysIn    The source MSI address.
-     * @param   uDataIn     The source MSI data.
-     * @param   pGCPhysOut  Where to store the remapped MSI address.
-     * @param   puDataOut   Where to store the remapped MSI data.
+     * @param   pMsiIn      The source MSI.
+     * @param   pMsiOut     Where to store the remapped MSI.
      *
      * @thread  Any.
      */
-    DECLR0CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn,
-                                           PRTGCPHYS pGCPhysOut, uint32_t *puDataOut));
+    DECLR0CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut));
 
     /** Just a safety precaution. */
@@ -1358,13 +1356,10 @@
      * @param   pDevIns     The IOMMU device instance.
      * @param   uDevId      The device identifier (bus, device, function).
-     * @param   GCPhysIn    The source MSI address.
-     * @param   uDataIn     The source MSI data.
-     * @param   pGCPhysOut  Where to store the remapped MSI address.
-     * @param   puDataOut   Where to store the remapped MSI data.
+     * @param   pMsiIn      The source MSI.
+     * @param   pMsiOut     Where to store the remapped MSI.
      *
      * @thread  Any.
      */
-    DECLRCCALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn,
-                                           PRTGCPHYS pGCPhysOut, uint32_t *puDataOut));
+    DECLRCCALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut));
 
     /** Just a safety precaution. */
@@ -1425,13 +1420,10 @@
      * @param   pDevIns     The IOMMU device instance.
      * @param   uDevId      The device identifier (bus, device, function).
-     * @param   GCPhysIn    The source MSI address.
-     * @param   uDataIn     The source MSI data.
-     * @param   pGCPhysOut  Where to store the remapped MSI address.
-     * @param   puDataOut   Where to store the remapped MSI data.
+     * @param   pMsiIn      The source MSI.
+     * @param   pMsiOut     Where to store the remapped MSI.
      *
      * @thread  Any.
      */
-    DECLR3CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn,
-                                           PRTGCPHYS pGCPhysOut, uint32_t *puDataOut));
+    DECLR3CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut));
 
     /** Just a safety precaution. */
@@ -1793,4 +1785,17 @@
     DECLCALLBACKMEMBER(void,  pfnUnlock)(PPDMDEVINS pDevIns);
 
+    /**
+     * Private interface between the IOAPIC and IOMMU.
+     *
+     * @returns status code.
+     * @param   pDevIns     Device instance of the IOAPIC.
+     * @param   uDevId      The device ID (bus, device, function) for the source MSI.
+     * @param   pMsiIn      The source MSI.
+     * @param   pMsiOut     Where to store the remapped MSI.
+     *
+     * @sa      iommuAmdDeviceMsiRemap().
+     */
+    DECLCALLBACKMEMBER(int, pfnIommuMsiRemap)(PPDMDEVINS pDevIns, uint16_t uDevIt, PCMSIMSG pMsiIn, PMSIMSG pMsiOut);
+
     /** Just a safety precaution. */
     uint32_t                u32TheEnd;
@@ -1802,5 +1807,5 @@
 
 /** Current PDMIOAPICHLP version number. */
-#define PDM_IOAPICHLP_VERSION                   PDM_VERSION_MAKE(0xfff0, 2, 0)
+#define PDM_IOAPICHLP_VERSION                   PDM_VERSION_MAKE(0xfff0, 2, 1)
 
 
Index: /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 84676)
+++ /trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp	(revision 84677)
@@ -4548,20 +4548,17 @@
  * @param   uDevId      The device ID.
  * @param   pDte        The device table entry.
- * @param   GCPhysIn    The source MSI address.
- * @param   uDataIn     The source MSI data.
  * @param   enmOp       The IOMMU operation being performed.
- * @param   pGCPhysOut  Where to store the remapped MSI address.
- * @param   puDataOut   Where to store the remapped MSI data.
+ * @param   pMsiIn      The source MSI.
+ * @param   pMsiOut     Where to store the remapped MSI.
  *
  * @thread  Any.
  */
-static int iommuAmdRemapIntr(PPDMDEVINS pDevIns, uint16_t uDevId, PCDTE_T pDte, RTGCPHYS GCPhysIn, uint32_t uDataIn,
-                             IOMMUOP enmOp, PRTGCPHYS pGCPhysOut, uint32_t *puDataOut)
-{
-    /** @todo Replace GCPhys[Out|In], uData[Out|In] with MSIMSG. */
+static int iommuAmdRemapIntr(PPDMDEVINS pDevIns, uint16_t uDevId, PCDTE_T pDte, IOMMUOP enmOp, PCMSIMSG pMsiIn,
+                             PMSIMSG pMsiOut)
+{
     Assert(pDte->n.u2IntrCtrl == IOMMU_INTR_CTRL_REMAP);
 
     IRTE_T Irte;
-    int rc = iommuAmdReadIrte(pDevIns, uDevId, pDte, GCPhysIn, uDataIn, enmOp, &Irte);
+    int rc = iommuAmdReadIrte(pDevIns, uDevId, pDte, pMsiIn->Addr.u64, pMsiIn->Data.u32, enmOp, &Irte);
     if (RT_SUCCESS(rc))
     {
@@ -4572,22 +4569,13 @@
                 if (Irte.n.u3IntrType < VBOX_MSI_DELIVERY_MODE_LOWEST_PRIO)
                 {
-                    MSIADDR MsiAddrIn;
-                    MsiAddrIn.u64 = GCPhysIn;
-
-                    MSIDATA MsiDataIn;
-                    MsiDataIn.u32 = uDataIn;
-
-                    PMSIADDR pMsiAddrOut = (PMSIADDR)pGCPhysOut;
-                    PMSIDATA pMsiDataOut = (PMSIDATA)puDataOut;
-
                     /* Preserve all bits from the source MSI address that don't map 1:1 from the IRTE. */
-                    pMsiAddrOut->u64 = GCPhysIn;
-                    pMsiAddrOut->n.u1DestMode = Irte.n.u1DestMode;
-                    pMsiAddrOut->n.u8DestId   = Irte.n.u8Dest;
+                    pMsiOut->Addr.u64 = pMsiIn->Addr.u64;
+                    pMsiOut->Addr.n.u1DestMode = Irte.n.u1DestMode;
+                    pMsiOut->Addr.n.u8DestId   = Irte.n.u8Dest;
 
                     /* Preserve all bits from the source MSI data that don't map 1:1 from the IRTE. */
-                    pMsiDataOut->u32 = uDataIn;
-                    pMsiDataOut->n.u8Vector       = Irte.n.u8Vector;
-                    pMsiDataOut->n.u3DeliveryMode = Irte.n.u3IntrType;
+                    pMsiOut->Data.u32 = pMsiIn->Data.u32;
+                    pMsiOut->Data.n.u8Vector       = Irte.n.u8Vector;
+                    pMsiOut->Data.n.u3DeliveryMode = Irte.n.u3IntrType;
 
                     return VINF_SUCCESS;
@@ -4596,6 +4584,6 @@
                 Log((IOMMU_LOG_PFX ": Interrupt type (%#x) invalid -> IOPF", Irte.n.u3IntrType));
                 EVT_IO_PAGE_FAULT_T EvtIoPageFault;
-                iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, GCPhysIn, Irte.n.u1RemapEnable, true /* fRsvdNotZero */,
-                                             false /* fPermDenied */, enmOp, &EvtIoPageFault);
+                iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable,
+                                             true /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault);
                 iommuAmdRaiseIoPageFaultEvent(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRsvdIntType);
                 return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
@@ -4604,6 +4592,6 @@
             Log((IOMMU_LOG_PFX ": Guest mode not supported -> IOPF"));
             EVT_IO_PAGE_FAULT_T EvtIoPageFault;
-            iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, GCPhysIn, Irte.n.u1RemapEnable, true /* fRsvdNotZero */,
-                                         false /* fPermDenied */, enmOp, &EvtIoPageFault);
+            iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable,
+                                         true /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault);
             iommuAmdRaiseIoPageFaultEvent(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRsvdNotZero);
             return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
@@ -4612,6 +4600,6 @@
         Log((IOMMU_LOG_PFX ": Remapping disabled -> IOPF"));
         EVT_IO_PAGE_FAULT_T EvtIoPageFault;
-        iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, GCPhysIn, Irte.n.u1RemapEnable, false /* fRsvdNotZero */,
-                                     false /* fPermDenied */, enmOp, &EvtIoPageFault);
+        iommuAmdInitIoPageFaultEvent(uDevId, pDte->n.u16DomainId, pMsiIn->Addr.u64, Irte.n.u1RemapEnable,
+                                     false /* fRsvdNotZero */, false /* fPermDenied */, enmOp, &EvtIoPageFault);
         iommuAmdRaiseIoPageFaultEvent(pDevIns, pDte, &Irte, enmOp, &EvtIoPageFault, kIoPageFaultType_IrteRemapEn);
         return VERR_IOMMU_ADDR_TRANSLATION_FAILED;
@@ -4628,14 +4616,11 @@
  * @param   pDevIns     The IOMMU instance data.
  * @param   uDevId      The device ID.
- * @param   GCPhysIn    The source MSI address.
- * @param   uDataIn     The source MSI data.
  * @param   enmOp       The IOMMU operation being performed.
- * @param   pGCPhysOut  Where to store the remapped MSI address.
- * @param   puDataOut   Where to store the remapped MSI data.
+ * @param   pMsiIn      The source MSI.
+ * @param   pMsiOut     Where to store the remapped MSI.
  *
  * @thread  Any.
  */
-static int iommuAmdLookupIntrTable(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn, IOMMUOP enmOp,
-                                   PRTGCPHYS pGCPhysOut, uint32_t *puDataOut)
+static int iommuAmdLookupIntrTable(PPDMDEVINS pDevIns, uint16_t uDevId, IOMMUOP enmOp, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
 {
     /* Read the device table entry from memory. */
@@ -4658,5 +4643,5 @@
                      fRsvd1));
                 EVT_ILLEGAL_DTE_T Event;
-                iommuAmdInitIllegalDteEvent(uDevId, GCPhysIn, true /* fRsvdNotZero */, enmOp, &Event);
+                iommuAmdInitIllegalDteEvent(uDevId, pMsiIn->Addr.u64, true /* fRsvdNotZero */, enmOp, &Event);
                 iommuAmdRaiseIllegalDteEvent(pDevIns, enmOp, &Event, kIllegalDteType_RsvdNotZero);
                 return VERR_IOMMU_INTR_REMAP_FAILED;
@@ -4680,16 +4665,11 @@
              * See Intel spec. 10.11.1 "Message Address Register Format".
              */
-            MSIADDR MsiAddrIn;
-            MsiAddrIn.u64 = GCPhysIn;
-            if ((MsiAddrIn.u64 & VBOX_MSI_ADDR_ADDR_MASK) == VBOX_MSI_ADDR_BASE)
+            if ((pMsiIn->Addr.u64 & VBOX_MSI_ADDR_ADDR_MASK) == VBOX_MSI_ADDR_BASE)
             {
-                MSIDATA MsiDataIn;
-                MsiDataIn.u32 = uDataIn;
-
                 /*
                  * The IOMMU remaps fixed and arbitrated interrupts using the IRTE.
                  * See AMD IOMMU spec. "2.2.5.1 Interrupt Remapping Tables, Guest Virtual APIC Not Enabled".
                  */
-                uint8_t const u8DeliveryMode = MsiDataIn.n.u3DeliveryMode;
+                uint8_t const u8DeliveryMode = pMsiIn->Data.n.u3DeliveryMode;
                 bool fPassThru = false;
                 switch (u8DeliveryMode)
@@ -4729,10 +4709,10 @@
                                 NOREF(pThis);
 
-                                return iommuAmdRemapIntr(pDevIns, uDevId, &Dte, GCPhysIn, uDataIn, enmOp, pGCPhysOut, puDataOut);
+                                return iommuAmdRemapIntr(pDevIns, uDevId, &Dte, enmOp, pMsiIn, pMsiOut);
                             }
 
                             Log((IOMMU_LOG_PFX ": Invalid interrupt table length %#x -> Illegal DTE\n", uIntTabLen));
                             EVT_ILLEGAL_DTE_T Event;
-                            iommuAmdInitIllegalDteEvent(uDevId, GCPhysIn, false /* fRsvdNotZero */, enmOp, &Event);
+                            iommuAmdInitIllegalDteEvent(uDevId, pMsiIn->Addr.u64, false /* fRsvdNotZero */, enmOp, &Event);
                             iommuAmdRaiseIllegalDteEvent(pDevIns, enmOp, &Event, kIllegalDteType_RsvdIntTabLen);
                             return VERR_IOMMU_INTR_REMAP_FAILED;
@@ -4744,5 +4724,5 @@
                         Log((IOMMU_LOG_PFX ":IntCtl mode invalid %#x -> Illegal DTE", uIntrCtrl));
                         EVT_ILLEGAL_DTE_T Event;
-                        iommuAmdInitIllegalDteEvent(uDevId, GCPhysIn, true /* fRsvdNotZero */, enmOp, &Event);
+                        iommuAmdInitIllegalDteEvent(uDevId, pMsiIn->Addr.u64, true /* fRsvdNotZero */, enmOp, &Event);
                         iommuAmdRaiseIllegalDteEvent(pDevIns, enmOp, &Event, kIllegalDteType_RsvdIntCtl);
                         return VERR_IOMMU_INTR_REMAP_FAILED;
@@ -4764,6 +4744,5 @@
                 if (fPassThru)
                 {
-                    *pGCPhysOut = GCPhysIn;
-                    *puDataOut  = uDataIn;
+                    *pMsiOut = *pMsiIn;
                     return VINF_SUCCESS;
                 }
@@ -4774,5 +4753,5 @@
             else
             {
-                Log((IOMMU_LOG_PFX ":MSI address region invalid %#RX64.", MsiAddrIn.u64));
+                Log((IOMMU_LOG_PFX ":MSI address region invalid %#RX64.", pMsiIn->Addr.u64));
                 return VERR_IOMMU_INTR_REMAP_FAILED;
             }
@@ -4781,6 +4760,5 @@
         {
             /** @todo IOMMU: Add to interrupt remapping cache. */
-            *pGCPhysOut = GCPhysIn;
-            *puDataOut  = uDataIn;
+            *pMsiOut = *pMsiIn;
             return VINF_SUCCESS;
         }
@@ -4798,19 +4776,13 @@
  * @param   pDevIns     The IOMMU device instance.
  * @param   uDevId      The device ID (bus, device, function).
- * @param   GCPhysIn    The source MSI address.
- * @param   uDataIn     The source MSI data.
- * @param   pGCPhysOut  Where to store the remapped MSI address.
- * @param   puDataOut   Where to store the remapped MSI data.
- */
-static int iommuAmdDeviceMsiRemap(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn,
-                                  PRTGCPHYS pGCPhysOut, uint32_t *puDataOut)
+ * @param   pMsiIn      The source MSI.
+ * @param   pMsiOut     Where to store the remapped MSI.
+ */
+static int iommuAmdDeviceMsiRemap(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
 {
     /* Validate. */
     Assert(pDevIns);
-    Assert(pGCPhysOut);
-    Assert(puDataOut);
-
-    /* Remove later. */
-    RT_NOREF(uDevId, GCPhysIn, uDataIn, pGCPhysOut, puDataOut);
+    Assert(pMsiIn);
+    Assert(pMsiOut);
 
     PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU);
@@ -4822,9 +4794,8 @@
         /** @todo Cache? */
 
-        return iommuAmdLookupIntrTable(pDevIns, uDevId, GCPhysIn, uDataIn, IOMMUOP_INTR_REQ, pGCPhysOut, puDataOut);
-    }
-
-    *pGCPhysOut = GCPhysIn;
-    *puDataOut  = uDataIn;
+        return iommuAmdLookupIntrTable(pDevIns, uDevId, IOMMUOP_INTR_REQ, pMsiIn, pMsiOut);
+    }
+
+    *pMsiOut = *pMsiIn;
     return VINF_SUCCESS;
 }
Index: /trunk/src/VBox/Devices/PC/DevIoApic.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevIoApic.cpp	(revision 84676)
+++ /trunk/src/VBox/Devices/PC/DevIoApic.cpp	(revision 84677)
@@ -432,11 +432,11 @@
      * See Intel spec. 10.11.2 "Message Data Register Format".
      */
-    pIntr->u8Dest         = pMsi->MsiAddr.n.u8DestId;
-    pIntr->u8DestMode     = pMsi->MsiAddr.n.u1DestMode;
-    pIntr->u8RedirHint    = pMsi->MsiAddr.n.u1RedirHint;
-
-    pIntr->u8Vector       = pMsi->MsiData.n.u8Vector;
-    pIntr->u8TriggerMode  = pMsi->MsiData.n.u1TriggerMode;
-    pIntr->u8DeliveryMode = pMsi->MsiData.n.u3DeliveryMode;
+    pIntr->u8Dest         = pMsi->Addr.n.u8DestId;
+    pIntr->u8DestMode     = pMsi->Addr.n.u1DestMode;
+    pIntr->u8RedirHint    = pMsi->Addr.n.u1RedirHint;
+
+    pIntr->u8Vector       = pMsi->Data.n.u8Vector;
+    pIntr->u8TriggerMode  = pMsi->Data.n.u1TriggerMode;
+    pIntr->u8DeliveryMode = pMsi->Data.n.u3DeliveryMode;
 }
 
@@ -450,14 +450,14 @@
 DECLINLINE(void) ioapicGetMsiFromApicIntr(PCXAPICINTR pIntr, PMSIMSG pMsi)
 {
-    pMsi->MsiAddr.n.u12Addr        = VBOX_MSI_ADDR_BASE >> VBOX_MSI_ADDR_SHIFT;
-    pMsi->MsiAddr.n.u8DestId       = pIntr->u8Dest;
-    pMsi->MsiAddr.n.u1RedirHint    = pIntr->u8RedirHint;
-    pMsi->MsiAddr.n.u1DestMode     = pIntr->u8DestMode;
-
-    pMsi->MsiData.n.u8Vector       = pIntr->u8Vector;
-    pMsi->MsiData.n.u3DeliveryMode = pIntr->u8DeliveryMode;
-    pMsi->MsiData.n.u1TriggerMode  = pIntr->u8TriggerMode;
-
-    /* pMsi->MsiData.n.u1Level     = ??? */
+    pMsi->Addr.n.u12Addr        = VBOX_MSI_ADDR_BASE >> VBOX_MSI_ADDR_SHIFT;
+    pMsi->Addr.n.u8DestId       = pIntr->u8Dest;
+    pMsi->Addr.n.u1RedirHint    = pIntr->u8RedirHint;
+    pMsi->Addr.n.u1DestMode     = pIntr->u8DestMode;
+
+    pMsi->Data.n.u8Vector       = pIntr->u8Vector;
+    pMsi->Data.n.u3DeliveryMode = pIntr->u8DeliveryMode;
+    pMsi->Data.n.u1TriggerMode  = pIntr->u8TriggerMode;
+
+    /* pMsi->Data.n.u1Level     = ??? */
     /** @todo r=ramshankar: Level triggered MSIs don't make much sense though
      *        possible in theory? Maybe document this more explicitly... */
@@ -855,11 +855,11 @@
     LogFlow(("IOAPIC: ioapicSendMsi: GCPhys=%#RGp uValue=%#RX32\n", GCPhys, uValue));
 
-    MSIMSG MsiMsg;
-    MsiMsg.MsiAddr.u64 = GCPhys;
-    MsiMsg.MsiData.u32 = uValue;
+    MSIMSG Msi;
+    Msi.Addr.u64 = GCPhys;
+    Msi.Data.u32 = uValue;
 
     XAPICINTR ApicIntr;
     RT_ZERO(ApicIntr);
-    ioapicGetApicIntrFromMsi(&MsiMsg, &ApicIntr);
+    ioapicGetApicIntrFromMsi(&Msi, &ApicIntr);
 
     /*
Index: /trunk/src/VBox/VMM/VMMR0/PDMR0DevHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/PDMR0DevHlp.cpp	(revision 84676)
+++ /trunk/src/VBox/VMM/VMMR0/PDMR0DevHlp.cpp	(revision 84677)
@@ -1558,4 +1558,34 @@
 
 
+/** @interface_method_impl{PDMIOAPICHLP,pfnIommuMsiRemap} */
+static DECLCALLBACK(int) pdmR0IoApicHlp_IommuMsiRemap(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR0IoApicHlp_IommuMsiRemap: caller='%s'/%d: pMsiIn=(%#RX64, %#RU32)\n", pDevIns->pReg->szName,
+             pDevIns->iInstance, pMsiIn->Addr.u64, pMsiIn->Data.u32));
+
+#ifdef VBOX_WITH_IOMMU_AMD
+    /** @todo IOMMU: Optimize/re-organize things here later. */
+    PGVM        pGVM         = pDevIns->Internal.s.pGVM;
+    PPDMIOMMUR0 pIommu       = &pGVM->pdmr0.s.aIommus[0];
+    PPDMDEVINS  pDevInsIommu = pIommu->CTX_SUFF(pDevIns);
+    if (   pDevInsIommu
+        && pDevInsIommu != pDevIns)
+    {
+        int rc = pIommu->pfnMsiRemap(pDevInsIommu, uDevId, pMsiIn, pMsiOut);
+        if (RT_FAILURE(rc))
+        {
+            Log(("pdmR0IoApicHlp_IommuMsiRemap: IOMMU MSI remap failed. uDevId=%#x pMsiIn=(%#RX64, %#RU32) rc=%Rrc\n",
+                 uDevId, pMsiIn->Addr.u64, pMsiIn->Data.u32, rc));
+            return rc;
+        }
+    }
+#else
+    *pMsiOut = *pMsiIn;
+#endif
+    return VINF_SUCCESS;
+}
+
+
 /**
  * The Ring-0 I/O APIC Helper Callbacks.
@@ -1567,4 +1597,5 @@
     pdmR0IoApicHlp_Lock,
     pdmR0IoApicHlp_Unlock,
+    pdmR0IoApicHlp_IommuMsiRemap,
     PDM_IOAPICHLP_VERSION
 };
Index: /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 84676)
+++ /trunk/src/VBox/VMM/VMMR3/PDMDevMiscHlp.cpp	(revision 84677)
@@ -31,4 +31,5 @@
 #include <VBox/log.h>
 #include <VBox/err.h>
+#include <VBox/msi.h>
 #include <iprt/asm.h>
 #include <iprt/assert.h>
@@ -140,4 +141,34 @@
 
 
+/** @interface_method_impl{PDMIOAPICHLP,pfnIommuMsiRemap} */
+static DECLCALLBACK(int) pdmR3IoApicHlp_IommuMsiRemap(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    LogFlow(("pdmR3IoApicHlp_IommuRemapMsi: caller='%s'/%d: pMsiIn=(%#RX64, %#RU32)\n", pDevIns->pReg->szName,
+             pDevIns->iInstance, pMsiIn->Addr.u64, pMsiIn->Data.u32));
+
+#ifdef VBOX_WITH_IOMMU_AMD
+    /** @todo IOMMU: Optimize/re-organize things here later. */
+    PVM        pVM          = pDevIns->Internal.s.pVMR3;
+    PPDMIOMMU  pIommu       = &pVM->pdm.s.aIommus[0];
+    PPDMDEVINS pDevInsIommu = pIommu->CTX_SUFF(pDevIns);
+    if (   pDevInsIommu
+        && pDevInsIommu != pDevIns)
+    {
+        int rc = pIommu->pfnMsiRemap(pDevInsIommu, uDevId, pMsiIn, pMsiOut);
+        if (RT_FAILURE(rc))
+        {
+            Log(("pdmR3IoApicHlp_IommuRemapMsi: IOMMU MSI remap failed. uDevId=%#x pMsiIn=(%#RX64, %#RU32) rc=%Rrc\n",
+                 uDevId, pMsiIn->Addr.u64, pMsiIn->Data.u32, rc));
+            return rc;
+        }
+    }
+#else
+    *pMsiOut = *pMsiIn;
+#endif
+    return VINF_SUCCESS;
+}
+
+
 /**
  * I/O APIC Device Helpers.
@@ -149,4 +180,5 @@
     pdmR3IoApicHlp_Lock,
     pdmR3IoApicHlp_Unlock,
+    pdmR3IoApicHlp_IommuMsiRemap,
     PDM_IOAPICHLP_VERSION /* the end */
 };
Index: /trunk/src/VBox/VMM/include/PDMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 84676)
+++ /trunk/src/VBox/VMM/include/PDMInternal.h	(revision 84677)
@@ -39,4 +39,5 @@
 #include <VBox/vmm/pdmtask.h>
 #include <VBox/sup.h>
+#include <VBox/msi.h>
 #include <iprt/assert.h>
 #include <iprt/critsect.h>
@@ -704,6 +705,5 @@
                                              PRTGCPHYS pGCPhysSpa));
     /** @copydoc PDMIOMMUREGR3::pfnMsiRemap */
-    DECLR3CALLBACKMEMBER(int,   pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn,
-                                             PRTGCPHYS pGCPhysOut, uint32_t *puDataOut));
+    DECLR3CALLBACKMEMBER(int,   pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut));
 } PDMIOMMU;
 
@@ -727,6 +727,5 @@
                                              PRTGCPHYS pGCPhysSpa));
     /** @copydoc PDMIOMMUREGR3::pfnMsiRemap */
-    DECLR0CALLBACKMEMBER(int,   pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, RTGCPHYS GCPhysIn, uint32_t uDataIn,
-                                             PRTGCPHYS pGCPhysOut, uint32_t *puDataOut));
+    DECLR0CALLBACKMEMBER(int,   pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t uDevId, PCMSIMSG pMsiIn, PMSIMSG pMsiOut));
 } PDMIOMMUR0;
 /** Pointer to a ring-0 IOMMU data. */
