Index: /trunk/include/VBox/pdmapi.h
===================================================================
--- /trunk/include/VBox/pdmapi.h	(revision 32934)
+++ /trunk/include/VBox/pdmapi.h	(revision 32935)
@@ -44,4 +44,5 @@
 VMMDECL(int)    PDMIsaSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level);
 VMMDECL(int)    PDMIoApicSetIrq(PVM pVM, uint8_t u8Irq, uint8_t u8Level);
+VMMDECL(int)    PDMIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue);
 VMMDECL(bool)   PDMHasIoApic(PVM pVM);
 VMMDECL(int)    PDMApicHasPendingIrq(PVM pVM, bool *pfPending);
Index: /trunk/include/VBox/pdmdev.h
===================================================================
--- /trunk/include/VBox/pdmdev.h	(revision 32934)
+++ /trunk/include/VBox/pdmdev.h	(revision 32935)
@@ -579,4 +579,15 @@
 
     /**
+     * Send an MSI.
+     *
+     * @param   pDevIns         PCI device instance.
+     * @param   GCAddr          Physical address MSI request was written.
+     * @param   uValue          Value written.
+     * @thread  EMT only.
+     */
+    DECLRCCALLBACKMEMBER(void,  pfnIoApicSendMsi,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue));
+
+
+    /**
      * Acquires the PDM lock.
      *
@@ -603,6 +614,6 @@
 typedef RCPTRTYPE(const PDMPCIHLPRC *) PCPDMPCIHLPRC;
 
-/** Current PDMPCIHLPR3 version number. */
-#define PDM_PCIHLPRC_VERSION                    PDM_VERSION_MAKE(0xfffd, 1, 0)
+/** Current PDMPCIHLPRC version number. */
+#define PDM_PCIHLPRC_VERSION                    PDM_VERSION_MAKE(0xfffd, 2, 0)
 
 
@@ -634,4 +645,15 @@
      */
     DECLR0CALLBACKMEMBER(void,  pfnIoApicSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+
+    /**
+     * Send an MSI.
+     *
+     * @param   pDevIns         PCI device instance.
+     * @param   GCAddr          Physical address MSI request was written.
+     * @param   uValue          Value written.
+     * @thread  EMT only.
+     */
+    DECLR0CALLBACKMEMBER(void,  pfnIoApicSendMsi,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue));
+
 
     /**
@@ -661,5 +683,5 @@
 
 /** Current PDMPCIHLPR0 version number. */
-#define PDM_PCIHLPR0_VERSION                    PDM_VERSION_MAKE(0xfffc, 1, 0)
+#define PDM_PCIHLPR0_VERSION                    PDM_VERSION_MAKE(0xfffc, 2, 0)
 
 /**
@@ -690,4 +712,14 @@
      */
     DECLR3CALLBACKMEMBER(void,  pfnIoApicSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+
+    /**
+     * Send an MSI.
+     *
+     * @param   pDevIns         PCI device instance.
+     * @param   GCAddr          Physical address MSI request was written.
+     * @param   uValue          Value written.
+     * @thread  EMT only.
+     */
+    DECLR3CALLBACKMEMBER(void,  pfnIoApicSendMsi,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue));
 
     /**
@@ -751,5 +783,5 @@
 
 /** Current PDMPCIHLPR3 version number. */
-#define PDM_PCIHLPR3_VERSION                    PDM_VERSION_MAKE(0xfffb, 1, 0)
+#define PDM_PCIHLPR3_VERSION                    PDM_VERSION_MAKE(0xfffb, 2, 0)
 
 
@@ -1449,4 +1481,19 @@
     /** The name of the R0 SetIrq entry point. */
     const char         *pszSetIrqR0;
+
+    /**
+     * Send a MSI.
+     *
+     * @param   pDevIns         Device instance of the I/O APIC.
+     * @param   GCPhys          Request address.
+     * @param   uValue          Request value.
+     */
+    DECLR3CALLBACKMEMBER(void, pfnSendMsiR3,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue));
+
+    /** The name of the GC SendMsi entry point. */
+    const char         *pszSendMsiRC;
+
+    /** The name of the R0 SendMsi entry point. */
+    const char         *pszSendMsiR0;
 } PDMIOAPICREG;
 /** Pointer to an APIC registration structure. */
@@ -1454,5 +1501,5 @@
 
 /** Current PDMAPICREG version number. */
-#define PDM_IOAPICREG_VERSION                   PDM_VERSION_MAKE(0xfff2, 1, 0)
+#define PDM_IOAPICREG_VERSION                   PDM_VERSION_MAKE(0xfff2, 2, 0)
 
 
Index: /trunk/src/VBox/Devices/Bus/DevPciIch9.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/DevPciIch9.cpp	(revision 32934)
+++ /trunk/src/VBox/Devices/Bus/DevPciIch9.cpp	(revision 32935)
@@ -528,10 +528,13 @@
 static void ich9pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel)
 {
-    if (MSIIsEnabled(pPciDev))
+    if (MsiIsEnabled(pPciDev))
     {
         Log2(("Raise a MSI interrupt: %d\n", iIrq));
         /* We only trigger MSI on level up, as technically it's matching flip-flop best (maybe even assert that level == PDM_IRQ_LEVEL_FLIP_FLOP) */
         if ((iLevel & PDM_IRQ_LEVEL_HIGH) != 0)
-            MSINotify(pGlobals->aPciBus.CTX_SUFF(pDevIns), pPciDev, iIrq);
+        {
+            PPDMDEVINS pDevIns = pGlobals->aPciBus.CTX_SUFF(pDevIns);
+            MsiNotify(pDevIns, pGlobals->aPciBus.CTX_SUFF(pPciHlp), pPciDev, iIrq);
+        }
         return;
     }
@@ -786,5 +789,5 @@
 static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg)
 {
-    return MSIInit(pPciDev, pMsiReg);
+    return MsiInit(pPciDev, pMsiReg);
 }
 
@@ -1686,5 +1689,5 @@
        )
     {
-        return MSIPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
+        return MsiPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
     }
 
@@ -1723,5 +1726,7 @@
        )
     {
-        MSIPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, val, len);
+        MsiPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
+                          aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
+                          aDev, u32Address, val, len);
         return;
     }
Index: /trunk/src/VBox/Devices/Bus/MsiCommon.cpp
===================================================================
--- /trunk/src/VBox/Devices/Bus/MsiCommon.cpp	(revision 32934)
+++ /trunk/src/VBox/Devices/Bus/MsiCommon.cpp	(revision 32935)
@@ -92,5 +92,5 @@
 
 
-void     MSIPciConfigWrite(PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len)
+void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len)
 {
     int32_t iOff = u32Address - pDev->Int.s.u8MsiCapOffset;
@@ -113,5 +113,5 @@
                 /* don't change read-only bits: 1-3,7 */
                 val &= UINT32_C(~0x8e);
-                pDev->config[uAddr] &= ~val;
+                pDev->config[uAddr] = val;
                 break;
             case VBOX_MSI_CAP_MESSAGE_CONTROL + 1:
@@ -149,5 +149,5 @@
                                 /* To ensure that we're no longer masked */
                                 pDev->config[uAddr] &= ~iBit;
-                                MSINotify(pDevIns, pDev, maskUpdated*8 + iBitNum);
+                                MsiNotify(pDevIns, pPciHlp, pDev, maskUpdated*8 + iBitNum);
                             }
                         }
@@ -162,5 +162,5 @@
 }
 
-uint32_t MSIPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len)
+uint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len)
 {
     int32_t iOff = u32Address - pDev->Int.s.u8MsiCapOffset;
@@ -172,8 +172,8 @@
     {
         case 1:
-            rv = PCIDevGetByte(pDev, u32Address);
+            rv = PCIDevGetByte(pDev,  u32Address);
             break;
         case 2:
-            rv = PCIDevGetWord(pDev, u32Address);
+            rv = PCIDevGetWord(pDev,  u32Address);
             break;
         case 4:
@@ -190,5 +190,5 @@
 
 
-int MSIInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
+int MsiInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg)
 {
     uint16_t   cVectors    = pMsiReg->cVectors;
@@ -225,10 +225,10 @@
 
 
-bool     MSIIsEnabled(PPCIDEVICE pDev)
+bool     MsiIsEnabled(PPCIDEVICE pDev)
 {
     return PCIIsMsiCapable(pDev) && msiIsEnabled(pDev);
 }
 
-void MSINotify(PPDMDEVINS pDevIns, PPCIDEVICE pDev, int iVector)
+void MsiNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector)
 {
     Log2(("MSINotify: %d\n", iVector));
@@ -250,4 +250,5 @@
     *upPending &= ~(1<<iVector);
 
-    PDMDevHlpPhysWrite(pDevIns, GCAddr, &u32Value, sizeof(u32Value));
-}
+    Assert(pPciHlp->pfnIoApicSendMsi != NULL);
+    pPciHlp->pfnIoApicSendMsi(pDevIns, GCAddr, u32Value);
+}
Index: /trunk/src/VBox/Devices/Bus/MsiCommon.h
===================================================================
--- /trunk/src/VBox/Devices/Bus/MsiCommon.h	(revision 32934)
+++ /trunk/src/VBox/Devices/Bus/MsiCommon.h	(revision 32935)
@@ -15,13 +15,27 @@
  */
 
+/* Maybe belongs to types.h */
+#ifdef IN_RING3
+typedef PCPDMPCIHLPR3 PCPDMPCIHLP;
+#endif
+
+#ifdef IN_RING0
+typedef PCPDMPCIHLPR0 PCPDMPCIHLP;
+#endif
+
+#ifdef IN_RC
+typedef PCPDMPCIHLPRC PCPDMPCIHLP;
+#endif
+
 /* Init MSI support in the device. */
-int      MSIInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg);
+int      MsiInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg);
 
 /* If MSI is enabled, so that MSINotify() shall be used for notifications.  */
-bool     MSIIsEnabled(PPCIDEVICE pDev);
+bool     MsiIsEnabled(PPCIDEVICE pDev);
+
 /* Device notification (aka interrupt). */
-void     MSINotify(PPDMDEVINS pDevIns, PPCIDEVICE pDev, int iVector);
+void     MsiNotify(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, int iVector);
 
 /* PCI config space accessors for MSI registers */
-void     MSIPciConfigWrite(PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len);
-uint32_t MSIPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len);
+void     MsiPciConfigWrite(PPDMDEVINS pDevIns, PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, uint32_t u32Address, uint32_t val, unsigned len);
+uint32_t MsiPciConfigRead (PPDMDEVINS pDevIns, PPCIDEVICE pDev, uint32_t u32Address, unsigned len);
Index: /trunk/src/VBox/Devices/PC/DevAPIC.cpp
===================================================================
--- /trunk/src/VBox/Devices/PC/DevAPIC.cpp	(revision 32934)
+++ /trunk/src/VBox/Devices/PC/DevAPIC.cpp	(revision 32935)
@@ -356,4 +356,5 @@
 PDMBOTHCBDECL(int)  ioapicMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb);
 PDMBOTHCBDECL(void) ioapicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel);
+PDMBOTHCBDECL(void) ioapicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue);
 
 static void apic_update_tpr(APICDeviceInfo *dev, APICState* s, uint32_t val);
@@ -1531,27 +1532,4 @@
     return val;
 }
-/**
- * See chapter 10.11 MESSAGE SIGNALLED INTERRUPTS of IA-32 Intel Architecture
- * Software Developer's Manual, Volume 3A: System Programming Guide, Part 1
- * for details on MSI and LAPIC interaction.
- */
-static int apicSendMsi(APICDeviceInfo* dev, RTGCPHYS addr, uint32_t val)
-{
-    uint8_t  dest = (addr & VBOX_MSI_ADDR_DEST_ID_MASK) >> VBOX_MSI_ADDR_DEST_ID_SHIFT;
-    uint8_t  vector_num = (val & VBOX_MSI_DATA_VECTOR_MASK) >> VBOX_MSI_DATA_VECTOR_SHIFT;
-    uint8_t  dest_mode = (addr >> VBOX_MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
-    uint8_t  trigger_mode = (val >> VBOX_MSI_DATA_TRIGGER_SHIFT) & 0x1;
-    uint8_t  delivery_mode = (val >> VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
-    /**
-     * This bit indicates whether the message should be directed to the
-     * processor with the lowest interrupt priority among
-     * processors that can receive the interrupt, ignored ATM.
-     */
-    uint8_t  redir_hint = (addr >> VBOX_MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
-    uint32_t deliver_bitmask = apic_get_delivery_bitmask(dev, dest, dest_mode);
-
-    return apic_bus_deliver(dev, deliver_bitmask, delivery_mode,
-                            vector_num, 0 /* polarity */, trigger_mode);
-}
 
 static int apic_mem_writel(APICDeviceInfo* dev, APICState *s, RTGCPHYS addr, uint32_t val)
@@ -1564,9 +1542,5 @@
 #endif
 
-    index = (addr >> 4) & 0xff;
-    addr -= (s->apicbase & ~0xfff);
-
-    if (addr > 0xfff || (index == 0))
-        return apicSendMsi(dev, addr, val);
+    index = (addr >> 4) & 0xff;  
 
     switch(index) {
@@ -2503,6 +2477,5 @@
      */
     uint32_t ApicBase = pThis->paLapicsR3[0].apicbase & ~0xfff;
-    /* See comment in msi.h, on why LAPIC and MSI share same region */
-    rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, VBOX_MSI_ADDR_SIZE, pThis,
+    rc = PDMDevHlpMMIORegister(pDevIns, ApicBase, 0x1000, pThis,
                                apicMMIOWrite, apicMMIORead, NULL, "APIC Memory");
     if (RT_FAILURE(rc))
@@ -2513,5 +2486,5 @@
         pThis->pCritSectRC = pThis->pApicHlpR3->pfnGetRCCritSect(pDevIns);
 
-        rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, VBOX_MSI_ADDR_SIZE, 0,
+        rc = PDMDevHlpMMIORegisterRC(pDevIns, ApicBase, 0x1000, 0,
                                      "apicMMIOWrite", "apicMMIORead", NULL);
         if (RT_FAILURE(rc))
@@ -2523,5 +2496,5 @@
         pThis->pCritSectR0 = pThis->pApicHlpR3->pfnGetR0CritSect(pDevIns);
 
-        rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, VBOX_MSI_ADDR_SIZE, 0,
+        rc = PDMDevHlpMMIORegisterR0(pDevIns, ApicBase, 0x1000, 0,
                                      "apicMMIOWrite", "apicMMIORead", NULL);
         if (RT_FAILURE(rc))
@@ -2704,4 +2677,33 @@
 }
 
+PDMBOTHCBDECL(void) ioapicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue)
+{
+    IOAPICState *pThis = PDMINS_2_DATA(pDevIns, IOAPICState *);
+
+    LogFlow(("ioapicSendMsi: Address=%p uValue=%\n", GCAddr, uValue));
+
+    uint8_t  dest = (GCAddr & VBOX_MSI_ADDR_DEST_ID_MASK) >> VBOX_MSI_ADDR_DEST_ID_SHIFT;
+    uint8_t  vector_num = (uValue & VBOX_MSI_DATA_VECTOR_MASK) >> VBOX_MSI_DATA_VECTOR_SHIFT;
+    uint8_t  dest_mode = (GCAddr >> VBOX_MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
+    uint8_t  trigger_mode = (uValue >> VBOX_MSI_DATA_TRIGGER_SHIFT) & 0x1;
+    uint8_t  delivery_mode = (uValue >> VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) & 0x7;
+    /**
+     * This bit indicates whether the message should be directed to the
+     * processor with the lowest interrupt priority among
+     * processors that can receive the interrupt, ignored ATM.
+     */
+    uint8_t  redir_hint = (GCAddr >> VBOX_MSI_ADDR_REDIRECTION_SHIFT) & 0x1;
+
+    int rc = pThis->CTX_SUFF(pIoApicHlp)->pfnApicBusDeliver(pDevIns,
+                                                            dest,
+                                                            dest_mode,
+                                                            delivery_mode,
+                                                            vector_num,
+                                                            0 /* polarity, n/a */,
+                                                            trigger_mode);
+    /* We must be sure that attempts to reschedule in R3
+       never get here */
+    Assert(rc == VINF_SUCCESS);
+}
 
 #ifdef IN_RING3
@@ -2848,7 +2850,11 @@
      */
     IoApicReg.u32Version  = PDM_IOAPICREG_VERSION;
-    IoApicReg.pfnSetIrqR3 = ioapicSetIrq;
+    IoApicReg.pfnSetIrqR3 = ioapicSetIrq;    
     IoApicReg.pszSetIrqRC = fGCEnabled ? "ioapicSetIrq" : NULL;
     IoApicReg.pszSetIrqR0 = fR0Enabled ? "ioapicSetIrq" : NULL;
+    IoApicReg.pfnSendMsiR3 = ioapicSendMsi;
+    IoApicReg.pszSendMsiRC = fGCEnabled ? "ioapicSendMsi" : NULL;
+    IoApicReg.pszSendMsiR0 = fR0Enabled ? "ioapicSendMsi" : NULL;
+
     rc = PDMDevHlpIOAPICRegister(pDevIns, &IoApicReg, &s->pIoApicHlpR3);
     if (RT_FAILURE(rc))
Index: /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp	(revision 32934)
+++ /trunk/src/VBox/Devices/Storage/DevLsiLogicSCSI.cpp	(revision 32935)
@@ -48,4 +48,7 @@
 /** Maximum number of entries in the release log. */
 #define MAX_REL_LOG_ERRORS 1024
+
+/* If LSI shall emulate MSI support */
+#define LSILOGIC_WITH_MSI
 
 /**
@@ -4848,4 +4851,9 @@
     PCIDevSetInterruptPin(&pThis->PciDev,   0x01); /* Interrupt pin A */
 
+#ifdef LSILOGIC_WITH_MSI
+    PCIDevSetStatus(&pThis->PciDev,   VBOX_PCI_STATUS_CAP_LIST);
+    PCIDevSetCapabilityList(&pThis->PciDev, 0x80);
+#endif
+
     pThis->pDevInsR3 = pDevIns;
     pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
@@ -4860,4 +4868,16 @@
     if (RT_FAILURE(rc))
         return rc;
+
+#ifdef LSILOGIC_WITH_MSI
+    PDMMSIREG aMsiReg;
+    aMsiReg.cVectors = 1;
+    aMsiReg.iCapOffset = 0x80;
+    aMsiReg.iNextOffset = 0x0;
+    aMsiReg.iMsiFlags = 0;
+    rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg);
+    AssertRC(rc);
+    if (RT_FAILURE (rc))
+        return rc;
+#endif
 
     rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, LSILOGIC_PCI_SPACE_IO_SIZE, PCI_ADDRESS_SPACE_IO, lsilogicMap);
@@ -5150,3 +5170,2 @@
 #endif /* IN_RING3 */
 #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
-
Index: /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp
===================================================================
--- /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 32934)
+++ /trunk/src/VBox/Devices/VMMDev/VMMDev.cpp	(revision 32935)
@@ -3195,3 +3195,2 @@
 };
 #endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
-
Index: /trunk/src/VBox/VMM/PDMDevHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/PDMDevHlp.cpp	(revision 32934)
+++ /trunk/src/VBox/VMM/PDMDevHlp.cpp	(revision 32935)
@@ -2043,6 +2043,6 @@
     else
     {
-        pPciBus->pfnSetIrqRC = 0;
-        pPciBus->pDevInsRC   = 0;
+        pPciBus->pfnSetIrqRC  = 0;
+        pPciBus->pDevInsRC    = 0;
     }
 
@@ -2555,5 +2555,5 @@
         return VERR_INVALID_PARAMETER;
     }
-    if (!pIoApicReg->pfnSetIrqR3)
+    if (!pIoApicReg->pfnSetIrqR3 || !pIoApicReg->pfnSendMsiR3)
     {
         Assert(pIoApicReg->pfnSetIrqR3);
@@ -2568,8 +2568,22 @@
         return VERR_INVALID_PARAMETER;
     }
+    if (    pIoApicReg->pszSendMsiRC
+        &&  !VALID_PTR(pIoApicReg->pszSendMsiRC))
+    {
+        Assert(VALID_PTR(pIoApicReg->pszSendMsiRC));
+        LogFlow(("pdmR3DevHlp_IOAPICRegister: caller='%s'/%d: returns %Rrc (GC callbacks)\n", pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
+        return VERR_INVALID_PARAMETER;
+    }
     if (    pIoApicReg->pszSetIrqR0
         &&  !VALID_PTR(pIoApicReg->pszSetIrqR0))
     {
         Assert(VALID_PTR(pIoApicReg->pszSetIrqR0));
+        LogFlow(("pdmR3DevHlp_IOAPICRegister: caller='%s'/%d: returns %Rrc (GC callbacks)\n", pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
+        return VERR_INVALID_PARAMETER;
+    }
+    if (    pIoApicReg->pszSendMsiR0
+        &&  !VALID_PTR(pIoApicReg->pszSendMsiR0))
+    {
+        Assert(VALID_PTR(pIoApicReg->pszSendMsiR0));
         LogFlow(("pdmR3DevHlp_IOAPICRegister: caller='%s'/%d: returns %Rrc (GC callbacks)\n", pDevIns->pReg->szName, pDevIns->iInstance, VERR_INVALID_PARAMETER));
         return VERR_INVALID_PARAMETER;
@@ -2631,4 +2645,19 @@
     }
 
+    if (pIoApicReg->pszSendMsiRC)
+    {
+        int rc = PDMR3LdrGetSymbolRCLazy(pVM, pDevIns->pReg->szRCMod, pIoApicReg->pszSetIrqRC, &pVM->pdm.s.IoApic.pfnSendMsiRC);
+        AssertMsgRC(rc, ("%s::%s rc=%Rrc\n", pDevIns->pReg->szRCMod, pIoApicReg->pszSendMsiRC, rc));
+        if (RT_FAILURE(rc))
+        {
+            LogFlow(("pdmR3DevHlp_IOAPICRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+            return rc;
+        }
+    }
+    else
+    {
+        pVM->pdm.s.IoApic.pfnSendMsiRC = 0;
+    }
+
     /*
      * Resolve & initialize the R0 bits.
@@ -2652,4 +2681,20 @@
     }
 
+    if (pIoApicReg->pszSendMsiR0)
+    {
+        int rc = PDMR3LdrGetSymbolR0Lazy(pVM, pDevIns->pReg->szR0Mod, pIoApicReg->pszSetIrqR0, &pVM->pdm.s.IoApic.pfnSendMsiR0);
+        AssertMsgRC(rc, ("%s::%s rc=%Rrc\n", pDevIns->pReg->szR0Mod, pIoApicReg->pszSendMsiR0, rc));
+        if (RT_FAILURE(rc))
+        {
+            LogFlow(("pdmR3DevHlp_IOAPICRegister: caller='%s'/%d: returns %Rrc\n", pDevIns->pReg->szName, pDevIns->iInstance, rc));
+            return rc;
+        }
+    }
+    else
+    {
+        pVM->pdm.s.IoApic.pfnSendMsiR0 = 0;
+    }
+
+
     /*
      * Initialize the R3 bits.
@@ -2657,4 +2702,5 @@
     pVM->pdm.s.IoApic.pDevInsR3   = pDevIns;
     pVM->pdm.s.IoApic.pfnSetIrqR3 = pIoApicReg->pfnSetIrqR3;
+    pVM->pdm.s.IoApic.pfnSendMsiR3 = pIoApicReg->pfnSendMsiR3;
     Log(("PDM: Registered I/O APIC device '%s'/%d pDevIns=%p\n", pDevIns->pReg->szName, pDevIns->iInstance, pDevIns));
 
Index: /trunk/src/VBox/VMM/PDMDevMiscHlp.cpp
===================================================================
--- /trunk/src/VBox/VMM/PDMDevMiscHlp.cpp	(revision 32934)
+++ /trunk/src/VBox/VMM/PDMDevMiscHlp.cpp	(revision 32935)
@@ -458,13 +458,19 @@
 }
 
-
 /** @interface_method_impl{PDMPCIHLPR3,pfnIoApicSetIrq} */
 static DECLCALLBACK(void) pdmR3PciHlp_IoApicSetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel)
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
-    Log4(("pdmR3PciHlp_IsaSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
+    Log4(("pdmR3PciHlp_IoApicSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
     PDMIoApicSetIrq(pDevIns->Internal.s.pVMR3, iIrq, iLevel);
 }
 
+/** @interface_method_impl{PDMPCIHLPR3,pfnIoApicSendMsi} */
+static DECLCALLBACK(void) pdmR3PciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    Log4(("pdmR3PciHlp_IoApicSendMsi: address=%p value=%x\n", GCAddr, uValue));
+    PDMIoApicSendMsi(pDevIns->Internal.s.pVMR3, GCAddr, uValue);
+}
 
 /** @interface_method_impl{PDMPCIHLPR3,pfnIsMMIO2Base} */
@@ -535,4 +541,5 @@
     pdmR3PciHlp_IsaSetIrq,
     pdmR3PciHlp_IoApicSetIrq,
+    pdmR3PciHlp_IoApicSendMsi,
     pdmR3PciHlp_IsMMIO2Base,
     pdmR3PciHlp_GetRCHelpers,
Index: /trunk/src/VBox/VMM/PDMInternal.h
===================================================================
--- /trunk/src/VBox/VMM/PDMInternal.h	(revision 32934)
+++ /trunk/src/VBox/VMM/PDMInternal.h	(revision 32935)
@@ -548,4 +548,6 @@
     /** @copydoc PDMIOAPICREG::pfnSetIrqR3 */
     DECLR3CALLBACKMEMBER(void,      pfnSetIrqR3,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+    /** @copydoc PDMIOAPICREG::pfnSendMsiR3 */
+    DECLR3CALLBACKMEMBER(void,      pfnSendMsiR3,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue));
 
     /** Pointer to the PIC device instance - R0. */
@@ -553,4 +555,6 @@
     /** @copydoc PDMIOAPICREG::pfnSetIrqR3 */
     DECLR0CALLBACKMEMBER(void,      pfnSetIrqR0,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+    /** @copydoc PDMIOAPICREG::pfnSendMsiR3 */
+    DECLR0CALLBACKMEMBER(void,      pfnSendMsiR0,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue));
 
     /** Pointer to the APIC device instance - RC Ptr. */
@@ -558,4 +562,8 @@
     /** @copydoc PDMIOAPICREG::pfnSetIrqR3 */
     DECLRCCALLBACKMEMBER(void,      pfnSetIrqRC,(PPDMDEVINS pDevIns, int iIrq, int iLevel));
+     /** @copydoc PDMIOAPICREG::pfnSendMsiR3 */
+    DECLRCCALLBACKMEMBER(void,      pfnSendMsiRC,(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue));
+
+    uint8_t                         Alignment[4];
 } PDMIOAPIC;
 
Index: /trunk/src/VBox/VMM/VMMAll/PDMAll.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMAll/PDMAll.cpp	(revision 32934)
+++ /trunk/src/VBox/VMM/VMMAll/PDMAll.cpp	(revision 32935)
@@ -154,4 +154,26 @@
 }
 
+/**
+ * Send a MSI to an I/O APIC.
+ *
+ * @returns VBox status code.
+ * @param   pVM             VM handle.
+ * @param   GCAddr          Request address.
+ * @param   u8Value         REquest value.
+ */
+VMMDECL(int) PDMIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue)
+{
+    if (pVM->pdm.s.IoApic.CTX_SUFF(pDevIns))
+    {
+        Assert(pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi));
+        pdmLock(pVM);
+        pVM->pdm.s.IoApic.CTX_SUFF(pfnSendMsi)(pVM->pdm.s.IoApic.CTX_SUFF(pDevIns), GCAddr, uValue);
+        pdmUnlock(pVM);
+        return VINF_SUCCESS;
+    }
+    return VERR_PDM_NO_PIC_INSTANCE;
+}
+
+
 
 /**
Index: /trunk/src/VBox/VMM/VMMGC/PDMGCDevice.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMGC/PDMGCDevice.cpp	(revision 32934)
+++ /trunk/src/VBox/VMM/VMMGC/PDMGCDevice.cpp	(revision 32935)
@@ -55,7 +55,5 @@
 static void pdmRCIsaSetIrq(PVM pVM, int iIrq, int iLevel);
 static void pdmRCIoApicSetIrq(PVM pVM, int iIrq, int iLevel);
-
-
-
+static void pdmRCIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue);
 
 /** @name Raw-Mode Context Device Helpers
@@ -553,6 +551,14 @@
 {
     PDMDEV_ASSERT_DEVINS(pDevIns);
-    Log4(("pdmRCPciHlp_IsaSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
+    Log4(("pdmRCPciHlp_IoApicSetIrq: iIrq=%d iLevel=%d\n", iIrq, iLevel));
     pdmRCIoApicSetIrq(pDevIns->Internal.s.pVMRC, iIrq, iLevel);
+}
+
+/** @interface_method_impl{PDMPCIHLPRC,pfnIoApicSendMsi} */
+static DECLCALLBACK(void) pdmRCPciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    Log4(("pdmRCPciHlp_IoApicSendMsi: Address=%p Value=%d\n", GCAddr, uValue));
+    pdmRCIoApicSendMsi(pDevIns->Internal.s.pVMRC, GCAddr, uValue);
 }
 
@@ -582,4 +588,5 @@
     pdmRCPciHlp_IsaSetIrq,
     pdmRCPciHlp_IoApicSetIrq,
+    pdmRCPciHlp_IoApicSendMsi,
     pdmRCPciHlp_Lock,
     pdmRCPciHlp_Unlock,
@@ -786,2 +793,20 @@
     }
 }
+
+
+/**
+ * Sends an MSI to I/O APIC.
+ *
+ * @param   pVM     The VM handle.
+ * @param   GCAddr  Address of the message.
+ * @param   uValue  Value of the message.
+ */
+static void pdmRCIoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue)
+{
+    if (pVM->pdm.s.IoApic.pDevInsRC)
+    {
+        pdmLock(pVM);
+        pVM->pdm.s.IoApic.pfnSendMsiRC(pVM->pdm.s.IoApic.pDevInsRC, GCAddr, uValue);
+        pdmUnlock(pVM);
+    }
+}
Index: /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp
===================================================================
--- /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp	(revision 32934)
+++ /trunk/src/VBox/VMM/VMMR0/PDMR0Device.cpp	(revision 32935)
@@ -57,5 +57,5 @@
 static void pdmR0IsaSetIrq(PVM pVM, int iIrq, int iLevel);
 static void pdmR0IoApicSetIrq(PVM pVM, int iIrq, int iLevel);
-
+static void pdmR0IoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue);
 
 
@@ -592,4 +592,11 @@
 }
 
+/** @interface_method_impl{PDMPCIHLPR0,pfnIoApicSendMsi} */
+static DECLCALLBACK(void) pdmR0PciHlp_IoApicSendMsi(PPDMDEVINS pDevIns, RTGCPHYS GCAddr, uint32_t uValue)
+{
+    PDMDEV_ASSERT_DEVINS(pDevIns);
+    Log4(("pdmR0PciHlp_IoApicSendMsi: Address=%p Value=%d\n", GCAddr, uValue));
+    pdmR0IoApicSendMsi(pDevIns->Internal.s.pVMR0, GCAddr, uValue);
+}
 
 /** @interface_method_impl{PDMPCIHLPR0,pfnLock} */
@@ -617,4 +624,5 @@
     pdmR0PciHlp_IsaSetIrq,
     pdmR0PciHlp_IoApicSetIrq,
+    pdmR0PciHlp_IoApicSendMsi,
     pdmR0PciHlp_Lock,
     pdmR0PciHlp_Unlock,
@@ -846,2 +854,19 @@
 }
 
+/**
+ * Sends an MSI to I/O APIC.
+ *
+ * @param   pVM     The VM handle.
+ * @param   GCAddr  Address of the message.
+ * @param   uValue  Value of the message.
+ */
+static void pdmR0IoApicSendMsi(PVM pVM, RTGCPHYS GCAddr, uint32_t uValue)
+{
+    if (pVM->pdm.s.IoApic.pDevInsR0)
+    {
+        pdmLock(pVM);
+        pVM->pdm.s.IoApic.pfnSendMsiR0(pVM->pdm.s.IoApic.pDevInsR0, GCAddr, uValue);
+        pdmUnlock(pVM);
+    }
+}
+
