Index: /trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp	(revision 85290)
+++ /trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp	(revision 85291)
@@ -1498,5 +1498,5 @@
         if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
         {
-            LogFunc(("Waken due to %s\n", rc == VERR_TIMEOUT ? "timeout" : "getting interrupted"));
+            LogFunc(("Woken due to %s\n", rc == VERR_TIMEOUT ? "timeout" : "getting interrupted"));
             continue;
         }
@@ -1752,5 +1752,5 @@
             paVirtSegsToGuest[cSegs].pvSeg = ((uint8_t *)pvBuf) + uOffset;
             cbBufRemaining -= cbLimited;
-            uOffset        += cbLimited;
+            uOffset += cbLimited;
             cVirtqBufs++;
             cSegs++;
@@ -1923,10 +1923,6 @@
 
         PVIRTIONETVIRTQ pRxVirtq = &pThis->aVirtqs[RXQIDX(uVirtqPair)];
-        if (RT_SUCCESS(!virtioNetR3CheckRxBufsAvail(pDevIns, pThis, pRxVirtq)))
+        if (RT_SUCCESS(virtioNetR3CheckRxBufsAvail(pDevIns, pThis, pRxVirtq)))
         {
-            /* Drop packets if VM is not running or cable is disconnected. */
-            if (!virtioNetIsOperational(pThis, pDevIns) || !IS_LINK_UP(pThis))
-                return VINF_SUCCESS;
-
             STAM_PROFILE_START(&pThis->StatReceive, a);
             virtioNetR3SetReadLed(pThisCC, true);
Index: /trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp
===================================================================
--- /trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp	(revision 85290)
+++ /trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp	(revision 85291)
@@ -324,125 +324,4 @@
     return virtioCoreVirtqAvailBufCount_inline(pDevIns, pVirtio, pVirtq);
 }
-
-/** @} */
-
-void virtioCoreGCPhysChainInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs)
-{
-    AssertPtr(pGcSgBuf);
-    Assert(   (cSegs > 0 && VALID_PTR(paSegs)) || (!cSegs && !paSegs));
-    Assert(cSegs < (~(unsigned)0 >> 1));
-
-    pGcSgBuf->paSegs = paSegs;
-    pGcSgBuf->cSegs  = (unsigned)cSegs;
-    pGcSgBuf->idxSeg = 0;
-    if (cSegs && paSegs)
-    {
-        pGcSgBuf->GCPhysCur = paSegs[0].GCPhys;
-        pGcSgBuf->cbSegLeft = paSegs[0].cbSeg;
-    }
-    else
-    {
-        pGcSgBuf->GCPhysCur = 0;
-        pGcSgBuf->cbSegLeft = 0;
-    }
-}
-
-static RTGCPHYS virtioCoreGCPhysChainGet(PVIRTIOSGBUF pGcSgBuf, size_t *pcbData)
-{
-    size_t cbData;
-    RTGCPHYS pGcBuf;
-
-    /* Check that the S/G buffer has memory left. */
-    if (RT_LIKELY(pGcSgBuf->idxSeg < pGcSgBuf->cSegs && pGcSgBuf->cbSegLeft))
-    { /* likely */ }
-    else
-    {
-        *pcbData = 0;
-        return 0;
-    }
-
-    AssertMsg(    pGcSgBuf->cbSegLeft <= 128 * _1M
-              && (RTGCPHYS)pGcSgBuf->GCPhysCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys
-              && (RTGCPHYS)pGcSgBuf->GCPhysCur + pGcSgBuf->cbSegLeft <=
-                   (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg,
-                 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf->GCPhysCur=%p pGcSgBuf->cbSegLeft=%zd "
-                  "pGcSgBuf->paSegs[%d].GCPhys=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n",
-                  pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf->GCPhysCur, pGcSgBuf->cbSegLeft,
-                  pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys, pGcSgBuf->idxSeg,
-                  pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg));
-
-    cbData = RT_MIN(*pcbData, pGcSgBuf->cbSegLeft);
-    pGcBuf = pGcSgBuf->GCPhysCur;
-    pGcSgBuf->cbSegLeft -= cbData;
-    if (!pGcSgBuf->cbSegLeft)
-    {
-        pGcSgBuf->idxSeg++;
-
-        if (pGcSgBuf->idxSeg < pGcSgBuf->cSegs)
-        {
-            pGcSgBuf->GCPhysCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys;
-            pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg;
-        }
-        *pcbData = cbData;
-    }
-    else
-        pGcSgBuf->GCPhysCur = pGcSgBuf->GCPhysCur + cbData;
-
-    return pGcBuf;
-}
-
-void virtioCoreGCPhysChainReset(PVIRTIOSGBUF pGcSgBuf)
-{
-    AssertPtrReturnVoid(pGcSgBuf);
-
-    pGcSgBuf->idxSeg = 0;
-    if (pGcSgBuf->cSegs)
-    {
-        pGcSgBuf->GCPhysCur = pGcSgBuf->paSegs[0].GCPhys;
-        pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[0].cbSeg;
-    }
-    else
-    {
-        pGcSgBuf->GCPhysCur = 0;
-        pGcSgBuf->cbSegLeft = 0;
-    }
-}
-
-RTGCPHYS virtioCoreGCPhysChainAdvance(PVIRTIOSGBUF pGcSgBuf, size_t cbAdvance)
-{
-    AssertReturn(pGcSgBuf, 0);
-
-    size_t cbLeft = cbAdvance;
-    while (cbLeft)
-    {
-        size_t cbThisAdvance = cbLeft;
-        virtioCoreGCPhysChainGet(pGcSgBuf, &cbThisAdvance);
-        if (!cbThisAdvance)
-            break;
-
-        cbLeft -= cbThisAdvance;
-    }
-    return cbAdvance - cbLeft;
-}
-
-RTGCPHYS virtioCoreGCPhysChainGetNextSeg(PVIRTIOSGBUF pGcSgBuf, size_t *pcbSeg)
-{
-    AssertReturn(pGcSgBuf, 0);
-    AssertPtrReturn(pcbSeg, 0);
-
-    if (!*pcbSeg)
-        *pcbSeg = pGcSgBuf->cbSegLeft;
-
-    return virtioCoreGCPhysChainGet(pGcSgBuf, pcbSeg);
-}
-
-size_t virtioCoreGCPhysChainCalcBufSize(PVIRTIOSGBUF pGcSgBuf)
-{
-    size_t   cb = 0;
-    unsigned i  = pGcSgBuf->cSegs;
-     while (i-- > 0)
-         cb += pGcSgBuf->paSegs[i].cbSeg;
-     return cb;
- }
 
 #ifdef IN_RING3
@@ -763,4 +642,99 @@
 
 /** API Function: See header file */
+uint32_t virtioCoreR3VirtqBufRetain(PVIRTQBUF pVirtqBuf)
+{
+    AssertReturn(pVirtqBuf, UINT32_MAX);
+    AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, UINT32_MAX);
+    uint32_t cRefs = ASMAtomicIncU32(&pVirtqBuf->cRefs);
+    Assert(cRefs > 1);
+    Assert(cRefs < 16);
+    return cRefs;
+}
+
+
+/** API Function: See header file */
+uint32_t virtioCoreR3VirtqBufRelease(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf)
+{
+    if (!pVirtqBuf)
+        return 0;
+    AssertReturn(pVirtqBuf, 0);
+    AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, 0);
+    uint32_t cRefs = ASMAtomicDecU32(&pVirtqBuf->cRefs);
+    Assert(cRefs < 16);
+    if (cRefs == 0)
+    {
+        pVirtqBuf->u32Magic = ~VIRTQBUF_MAGIC;
+        RTMemFree(pVirtqBuf);
+        STAM_REL_COUNTER_INC(&pVirtio->StatDescChainsFreed);
+    }
+    return cRefs;
+}
+
+/** API Function: See header file */
+void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio)
+{
+    virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
+}
+
+/** API Function: See header file */
+void virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtq, bool fEnable)
+{
+
+    Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues));
+    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
+
+    if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
+    {
+        uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, pVirtq);
+
+        if (fEnable)
+            fFlags &= ~ VIRTQ_USED_F_NO_NOTIFY;
+        else
+            fFlags |= VIRTQ_USED_F_NO_NOTIFY;
+
+        virtioWriteUsedRingFlags(pVirtio->pDevInsR3, pVirtio, pVirtq, fFlags);
+    }
+}
+
+/** API function: See Header file  */
+void virtioCoreResetAll(PVIRTIOCORE pVirtio)
+{
+    LogFunc(("\n"));
+    pVirtio->fDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
+    if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
+    {
+        pVirtio->fGenUpdatePending = true;
+        virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
+    }
+}
+
+/** API function: See Header file  */
+int virtioCoreR3VirtqAvailBufPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq,
+                         PPVIRTQBUF ppVirtqBuf)
+{
+    return virtioCoreR3VirtqAvailBufGet(pDevIns, pVirtio, uVirtq, ppVirtqBuf, false);
+}
+
+/** API function: See Header file  */
+int virtioCoreR3VirtqAvailBufNext(PVIRTIOCORE pVirtio, uint16_t uVirtq)
+{
+    Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues));
+
+    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
+
+    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
+                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
+
+    if (IS_VIRTQ_EMPTY(pVirtio->pDevInsR3, pVirtio, pVirtq))
+        return VERR_NOT_AVAILABLE;
+
+    Log6Func(("%s avail shadow idx: %u\n", pVirtq->szName, pVirtq->uAvailIdxShadow));
+    pVirtq->uAvailIdxShadow++;
+
+    return VINF_SUCCESS;
+}
+
+
+/** API Function: See header file */
 int virtioCoreR3VirtqAvailBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq,
                              uint16_t uHeadIdx, PPVIRTQBUF ppVirtqBuf)
@@ -771,11 +745,6 @@
     AssertMsgReturn(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues),
                         ("uVirtq out of range"), VERR_INVALID_PARAMETER);
+
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
-
-    if (!IS_DRIVER_OK(pVirtio) || !pVirtq->uEnable)
-    {
-        LogRelFunc(("Driver not ready or queue not enabled\n"));
-        return 0;
-    }
 
     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
@@ -784,5 +753,5 @@
     uint16_t uDescIdx = uHeadIdx;
 
-    Log6Func(("%s DESC CHAIN: (head) desc_idx=%u\n", pVirtq->szName, uHeadIdx));
+    Log6Func(("%s DESC CHAIN: (head) desc_idx=%u\n", pVirtio->aVirtqueues[uVirtq].szName, uHeadIdx));
 
     /*
@@ -794,5 +763,5 @@
     pVirtqBuf->cRefs     = 1;
     pVirtqBuf->uHeadIdx  = uHeadIdx;
-    pVirtqBuf->uVirtq = uVirtq;
+    pVirtqBuf->uVirtq    = uVirtq;
     *ppVirtqBuf = pVirtqBuf;
 
@@ -802,8 +771,9 @@
     VIRTQ_DESC_T desc;
 
-    uint32_t cbIn = 0;
-    uint32_t cbOut = 0;
-    uint32_t cSegsIn = 0;
+    uint32_t cbIn     = 0;
+    uint32_t cbOut    = 0;
+    uint32_t cSegsIn  = 0;
     uint32_t cSegsOut = 0;
+
     PVIRTIOSGSEG paSegsIn  = pVirtqBuf->aSegsIn;
     PVIRTIOSGSEG paSegsOut = pVirtqBuf->aSegsOut;
@@ -847,4 +817,5 @@
             cbOut += desc.cb;
             pSeg = &paSegsOut[cSegsOut++];
+#ifdef DEEP_DEBUG
             if (LogIs11Enabled())
             {
@@ -852,4 +823,5 @@
                 Log(("\n"));
             }
+#endif
         }
 
@@ -886,97 +858,4 @@
 }
 
-/** API Function: See header file */
-uint32_t virtioCoreR3VirtqBufRetain(PVIRTQBUF pVirtqBuf)
-{
-    AssertReturn(pVirtqBuf, UINT32_MAX);
-    AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, UINT32_MAX);
-    uint32_t cRefs = ASMAtomicIncU32(&pVirtqBuf->cRefs);
-    Assert(cRefs > 1);
-    Assert(cRefs < 16);
-    return cRefs;
-}
-
-
-/** API Function: See header file */
-uint32_t virtioCoreR3VirtqBufRelease(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf)
-{
-    if (!pVirtqBuf)
-        return 0;
-    AssertReturn(pVirtqBuf, 0);
-    AssertReturn(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC, 0);
-    uint32_t cRefs = ASMAtomicDecU32(&pVirtqBuf->cRefs);
-    Assert(cRefs < 16);
-    if (cRefs == 0)
-    {
-        pVirtqBuf->u32Magic = ~VIRTQBUF_MAGIC;
-        RTMemFree(pVirtqBuf);
-        STAM_REL_COUNTER_INC(&pVirtio->StatDescChainsFreed);
-    }
-    return cRefs;
-}
-
-/** API Function: See header file */
-void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio)
-{
-    virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
-}
-
-/** API Function: See header file */
-void virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtq, bool fEnable)
-{
-
-    Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues));
-    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
-
-    if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
-    {
-        uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, pVirtq);
-
-        if (fEnable)
-            fFlags &= ~ VIRTQ_USED_F_NO_NOTIFY;
-        else
-            fFlags |= VIRTQ_USED_F_NO_NOTIFY;
-
-        virtioWriteUsedRingFlags(pVirtio->pDevInsR3, pVirtio, pVirtq, fFlags);
-    }
-}
-
-/** API function: See Header file  */
-void virtioCoreResetAll(PVIRTIOCORE pVirtio)
-{
-    LogFunc(("\n"));
-    pVirtio->fDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
-    if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
-    {
-        pVirtio->fGenUpdatePending = true;
-        virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
-    }
-}
-
-/** API function: See Header file  */
-int virtioCoreR3VirtqAvailBufPeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq,
-                         PPVIRTQBUF ppVirtqBuf)
-{
-    return virtioCoreR3VirtqAvailBufGet(pDevIns, pVirtio, uVirtq, ppVirtqBuf, false);
-}
-
-/** API function: See Header file  */
-int virtioCoreR3VirtqAvailBufNext(PVIRTIOCORE pVirtio, uint16_t uVirtq)
-{
-    Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues));
-    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
-
-    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
-                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
-
-    if (IS_VIRTQ_EMPTY(pVirtio->pDevInsR3, pVirtio, pVirtq))
-        return VERR_NOT_AVAILABLE;
-
-    Log6Func(("%s avail shadow idx: %u\n", pVirtq->szName, pVirtq->uAvailIdxShadow));
-    pVirtq->uAvailIdxShadow++;
-
-    return VINF_SUCCESS;
-}
-
 /** API function: See Header file  */
 int virtioCoreR3VirtqAvailBufGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq,
@@ -1027,5 +906,5 @@
         cbRemain = cbTotal = RTSgBufCalcTotalLength(pSgVirtReturn);
         AssertMsgReturn(cbTarget >= cbRemain, ("No space to write data to phys memory"), VERR_BUFFER_OVERFLOW);
-        virtioCoreGCPhysChainReset(pSgPhysReturn); /* Reset ptr because req data may have already been written */
+        virtioCoreGCPhysChainReset(pSgPhysReturn);
         while (cbRemain)
         {
@@ -1064,42 +943,4 @@
 }
 
-/** API function: See Header file  */
-void virtioCoreR3VirqBufFill(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb)
-{
-    uint8_t *pb = (uint8_t *)pv;
-    size_t cbLim = RT_MIN(pVirtqBuf->cbPhysReturn, cb);
-    while (cbLim)
-    {
-        size_t cbSeg = cbLim;
-        RTGCPHYS GCPhys = virtioCoreGCPhysChainGetNextSeg(pVirtqBuf->pSgPhysReturn, &cbSeg);
-        PDMDevHlpPCIPhysWrite(pVirtio->pDevInsR3, GCPhys, pb, cbSeg);
-        pb += cbSeg;
-        cbLim -= cbSeg;
-        pVirtqBuf->cbPhysSend -= cbSeg;
-    }
-    LogFunc(("Added %d/%d bytes to %s buffer, head idx: %u (%d bytes remain)\n",
-             cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq),
-             pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysReturn));
-}
-
-
-/** API function: See Header file  */
-void virtioCoreR3VirtqBufDrain(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb)
-{
-    uint8_t *pb = (uint8_t *)pv;
-    size_t cbLim = RT_MIN(pVirtqBuf->cbPhysSend, cb);
-    while (cbLim)
-    {
-        size_t cbSeg = cbLim;
-        RTGCPHYS GCPhys = virtioCoreGCPhysChainGetNextSeg(pVirtqBuf->pSgPhysSend, &cbSeg);
-        PDMDevHlpPCIPhysRead(pVirtio->pDevInsR3, GCPhys, pb, cbSeg);
-        pb += cbSeg;
-        cbLim -= cbSeg;
-        pVirtqBuf->cbPhysSend -= cbSeg;
-    }
-    LogFunc(("Drained %d/%d bytes from %s buffer, head idx: %u (%d bytes left)\n",
-             cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq),
-             pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysSend));
-}
 
 #endif /* IN_RING3 */
@@ -1255,9 +1096,9 @@
     pVirtq->uAvailIdxShadow  = 0;
     pVirtq->uUsedIdxShadow   = 0;
-    pVirtq->uEnable     = false;
-    pVirtq->uSize       = VIRTQ_MAX_ENTRIES;
-    pVirtq->uNotifyOffset  = uVirtq;
-    pVirtq->uMsix = uVirtq + 2;
-    pVirtq->fUsedRingEvent = false;
+    pVirtq->uEnable          = false;
+    pVirtq->uSize            = VIRTQ_MAX_ENTRIES;
+    pVirtq->uNotifyOffset    = uVirtq;
+    pVirtq->uMsix            = uVirtq + 2;
+    pVirtq->fUsedRingEvent   = false;
 
     if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */
@@ -1527,5 +1368,4 @@
     AssertReturn(cb == 1 || cb == 2 || cb == 4, VERR_INVALID_PARAMETER);
     Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser);
-
 
     uint32_t uOffset;
@@ -1849,5 +1689,9 @@
             break;
         case kvirtIoVmStateChangedResume:
-            virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, 0 /* uVirtq */);
+            for (int uVirtq = 0; uVirtq < VIRTQ_MAX_COUNT; uVirtq++)
+            {
+                if (pVirtio->aVirtqueues[uVirtq].uEnable)
+                    virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, uVirtq);
+            }
             break;
         default:
@@ -1874,24 +1718,5 @@
 }
 
-/**
- * Setup PCI device controller and Virtio state
- *
- * This should be called from PDMDEVREGR3::pfnConstruct.
- *
- * @param   pDevIns                 The device instance.
- * @param   pVirtio                 Pointer to the shared virtio state.  This
- *                                  must be the first member in the shared
- *                                  device instance data!
- * @param   pVirtioCC               Pointer to the ring-3 virtio state.  This
- *                                  must be the first member in the ring-3
- *                                  device instance data!
- * @param   pPciParams              Values to populate industry standard PCI Configuration Space data structure
- * @param   pcszInstance            Device instance name (format-specifier)
- * @param   fDevSpecificFeatures    VirtIO device-specific features offered by
- *                                  client
- * @param   cbDevSpecificCfg        Size of virtio_pci_device_cap device-specific struct
- * @param   pvDevSpecificCfg        Address of client's dev-specific
- *                                  configuration struct.
- */
+/** API Function: See header file */
 int virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, PVIRTIOPCIPARAMS pPciParams,
                      const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg)
Index: /trunk/src/VBox/Devices/VirtIO/VirtioCore.h
===================================================================
--- /trunk/src/VBox/Devices/VirtIO/VirtioCore.h	(revision 85290)
+++ /trunk/src/VBox/Devices/VirtIO/VirtioCore.h	(revision 85291)
@@ -402,4 +402,28 @@
 
 /**
+ * Setup PCI device controller and Virtio state
+ *
+ * This should be called from PDMDEVREGR3::pfnConstruct.
+ *
+ * @param   pDevIns                 The device instance.
+ * @param   pVirtio                 Pointer to the shared virtio state.  This
+ *                                  must be the first member in the shared
+ *                                  device instance data!
+ * @param   pVirtioCC               Pointer to the ring-3 virtio state.  This
+ *                                  must be the first member in the ring-3
+ *                                  device instance data!
+ * @param   pPciParams              Values to populate industry standard PCI Configuration Space data structure
+ * @param   pcszInstance            Device instance name (format-specifier)
+ * @param   fDevSpecificFeatures    VirtIO device-specific features offered by
+ *                                  client
+ * @param   cbDevSpecificCfg        Size of virtio_pci_device_cap device-specific struct
+ * @param   pvDevSpecificCfg        Address of client's dev-specific
+ *                                  configuration struct.
+ */
+int virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC,
+                          PVIRTIOPCIPARAMS pPciParams, const char *pcszInstance,
+                          uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg);
+
+/**
  * Initiate orderly reset procedure. This is an exposed API for clients that might need it.
  * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)
@@ -621,4 +645,126 @@
 int virtioCoreR3VirtqAvailBufNext(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
 
+
+DECLINLINE(void) virtioCoreGCPhysChainInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs)
+{
+    AssertPtr(pGcSgBuf);
+    Assert((cSegs > 0 && VALID_PTR(paSegs)) || (!cSegs && !paSegs));
+    Assert(cSegs < (~(unsigned)0 >> 1));
+
+    pGcSgBuf->paSegs = paSegs;
+    pGcSgBuf->cSegs  = (unsigned)cSegs;
+    pGcSgBuf->idxSeg = 0;
+    if (cSegs && paSegs)
+    {
+        pGcSgBuf->GCPhysCur = paSegs[0].GCPhys;
+        pGcSgBuf->cbSegLeft = paSegs[0].cbSeg;
+    }
+    else
+    {
+        pGcSgBuf->GCPhysCur = 0;
+        pGcSgBuf->cbSegLeft = 0;
+    }
+}
+
+DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainGet(PVIRTIOSGBUF pGcSgBuf, size_t *pcbData)
+{
+    size_t cbData;
+    RTGCPHYS pGcBuf;
+
+    /* Check that the S/G buffer has memory left. */
+    if (RT_LIKELY(pGcSgBuf->idxSeg < pGcSgBuf->cSegs && pGcSgBuf->cbSegLeft))
+    { /* likely */ }
+    else
+    {
+        *pcbData = 0;
+        return 0;
+    }
+
+    AssertMsg(    pGcSgBuf->cbSegLeft <= 128 * _1M
+              && (RTGCPHYS)pGcSgBuf->GCPhysCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys
+              && (RTGCPHYS)pGcSgBuf->GCPhysCur + pGcSgBuf->cbSegLeft <=
+                   (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg,
+                 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf->GCPhysCur=%p pGcSgBuf->cbSegLeft=%zd "
+                  "pGcSgBuf->paSegs[%d].GCPhys=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n",
+                  pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf->GCPhysCur, pGcSgBuf->cbSegLeft,
+                  pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys, pGcSgBuf->idxSeg,
+                  pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg));
+
+    cbData = RT_MIN(*pcbData, pGcSgBuf->cbSegLeft);
+    pGcBuf = pGcSgBuf->GCPhysCur;
+    pGcSgBuf->cbSegLeft -= cbData;
+    if (!pGcSgBuf->cbSegLeft)
+    {
+        pGcSgBuf->idxSeg++;
+
+        if (pGcSgBuf->idxSeg < pGcSgBuf->cSegs)
+        {
+            pGcSgBuf->GCPhysCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys;
+            pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg;
+        }
+        *pcbData = cbData;
+    }
+    else
+        pGcSgBuf->GCPhysCur = pGcSgBuf->GCPhysCur + cbData;
+
+    return pGcBuf;
+}
+
+DECLINLINE(void) virtioCoreGCPhysChainReset(PVIRTIOSGBUF pGcSgBuf)
+{
+    AssertPtrReturnVoid(pGcSgBuf);
+
+    pGcSgBuf->idxSeg = 0;
+    if (pGcSgBuf->cSegs)
+    {
+        pGcSgBuf->GCPhysCur = pGcSgBuf->paSegs[0].GCPhys;
+        pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[0].cbSeg;
+    }
+    else
+    {
+        pGcSgBuf->GCPhysCur = 0;
+        pGcSgBuf->cbSegLeft = 0;
+    }
+}
+
+DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainAdvance(PVIRTIOSGBUF pGcSgBuf, size_t cbAdvance)
+{
+    AssertReturn(pGcSgBuf, 0);
+
+    size_t cbLeft = cbAdvance;
+    while (cbLeft)
+    {
+        size_t cbThisAdvance = cbLeft;
+        virtioCoreGCPhysChainGet(pGcSgBuf, &cbThisAdvance);
+        if (!cbThisAdvance)
+            break;
+
+        cbLeft -= cbThisAdvance;
+    }
+    return cbAdvance - cbLeft;
+}
+
+DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainGetNextSeg(PVIRTIOSGBUF pGcSgBuf, size_t *pcbSeg)
+{
+    AssertReturn(pGcSgBuf, 0);
+    AssertPtrReturn(pcbSeg, 0);
+
+    if (!*pcbSeg)
+        *pcbSeg = pGcSgBuf->cbSegLeft;
+
+    return virtioCoreGCPhysChainGet(pGcSgBuf, pcbSeg);
+}
+
+DECLINLINE(size_t) virtioCoreGCPhysChainCalcBufSize(PVIRTIOSGBUF pGcSgBuf)
+{
+    size_t   cb = 0;
+    unsigned i  = pGcSgBuf->cSegs;
+     while (i-- > 0)
+         cb += pGcSgBuf->paSegs[i].cbSeg;
+     return cb;
+ }
+
+#define VIRTQNAME(a_pVirtio, a_uVirtq) ((a_pVirtio)->aVirtqueues[(a_uVirtq)].szName)
+
 /**
  * Add some bytes to a virtq (s/g) buffer, converting them from virtual memory to GCPhys
@@ -632,5 +778,21 @@
  * @param   cb          number of bytes to add to the s/g buffer.
  */
-void virtioCoreR3VirqBufFill(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb);
+DECLINLINE(void) virtioCoreR3VirqBufFill(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb)
+{
+    uint8_t *pb = (uint8_t *)pv;
+    size_t cbLim = RT_MIN(pVirtqBuf->cbPhysReturn, cb);
+    while (cbLim)
+    {
+        size_t cbSeg = cbLim;
+        RTGCPHYS GCPhys = virtioCoreGCPhysChainGetNextSeg(pVirtqBuf->pSgPhysReturn, &cbSeg);
+        PDMDevHlpPCIPhysWrite(pVirtio->pDevInsR3, GCPhys, pb, cbSeg);
+        pb += cbSeg;
+        cbLim -= cbSeg;
+        pVirtqBuf->cbPhysSend -= cbSeg;
+    }
+    LogFunc(("Added %d/%d bytes to %s buffer, head idx: %u (%d bytes remain)\n",
+             cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq),
+             pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysReturn));
+}
 
 /**
@@ -645,5 +807,23 @@
  * @param   cb          number of bytes to Drain from buffer
  */
-void virtioCoreR3VirtqBufDrain(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb);
+DECLINLINE(void) virtioCoreR3VirtqBufDrain(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb)
+{
+    uint8_t *pb = (uint8_t *)pv;
+    size_t cbLim = RT_MIN(pVirtqBuf->cbPhysSend, cb);
+    while (cbLim)
+    {
+        size_t cbSeg = cbLim;
+        RTGCPHYS GCPhys = virtioCoreGCPhysChainGetNextSeg(pVirtqBuf->pSgPhysSend, &cbSeg);
+        PDMDevHlpPCIPhysRead(pVirtio->pDevInsR3, GCPhys, pb, cbSeg);
+        pb += cbSeg;
+        cbLim -= cbSeg;
+        pVirtqBuf->cbPhysSend -= cbSeg;
+    }
+    LogFunc(("Drained %d/%d bytes from %s buffer, head idx: %u (%d bytes left)\n",
+             cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq),
+             pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysSend));
+}
+
+#undef VIRTQNAME
 
 /**
@@ -820,6 +1000,4 @@
 void     virtioCoreR3VmStateChanged(PVIRTIOCORE pVirtio, VIRTIOVMSTATECHANGED enmState);
 void     virtioCoreR3Term(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC);
-int      virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, PVIRTIOPCIPARAMS pPciParams,
-                          const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg);
 int      virtioCoreRZInit(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio);
 const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState);
