Index: trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
===================================================================
--- trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp	(revision 80340)
+++ trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp	(revision 80383)
@@ -28,4 +28,5 @@
 #include <iprt/mem.h>
 #include <iprt/assert.h>
+#include <iprt/sg.h>
 #include <VBox/vmm/pdmdev.h>
 #include "Virtio_1_0_impl.h"
@@ -35,5 +36,5 @@
 
 #ifdef LOG_ENABLED
-# define QUEUENAME(s, q) (q->szName)
+# define QUEUENAME(s, q) (q->szVirtqName)
 #endif
 
@@ -93,4 +94,7 @@
 }
 
+/**
+ * See API comments in header file for description
+ */
 int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName)
 {
@@ -98,34 +102,21 @@
     PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     PVIRTQ_PROXY_T pVirtqProxy = &(pVirtio->virtqProxy[qIdx]);
-    if (pVirtio->uQueueEnable[qIdx])
-    {
-        pVirtqProxy->pBufVec = (PVIRTQ_BUF_VECTOR_T)RTMemAllocZ(sizeof(PVIRTQ_BUF_VECTOR_T));
-        if (!pVirtqProxy->pBufVec)
-        {
-            Log(("Out of memory!"));
-            return VERR_NO_MEMORY;
-        }
-        pVirtqProxy->uAvailIdx = 0;
-        pVirtqProxy->uUsedIdx  = 0;
-        pVirtqProxy->fEventThresholdReached = false;
-        RTStrCopy((char *)pVirtqProxy->szName, sizeof(pVirtqProxy->szName), pcszName);
-        return VINF_SUCCESS;
-    }
-    LogFunc(("Couldn't attach to %s: Not enabled\n", pcszName));
-    return VERR_INVALID_STATE;
-}
-
-PVIRTQ_BUF_VECTOR_T virtioQueueGetBuffer(VIRTIOHANDLE hVirtio, uint16_t qIdx)
-{
-    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
-    if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
-    {
-        PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
-        return pVirtqProxy->pBufVec;
-    }
-    LogFunc(("Can't get buffer, driver not ready\n"));
-    return NULL;
-}
-
+    pVirtqProxy->pDescChain = (PVIRTQ_DESC_CHAIN_T)RTMemAllocZ(sizeof(VIRTQ_DESC_CHAIN_T));
+    if (!pVirtqProxy->pDescChain)
+    {
+        Log(("Out of memory!"));
+        return VERR_NO_MEMORY;
+    }
+    pVirtqProxy->uAvailIdx = 0;
+    pVirtqProxy->uUsedIdx  = 0;
+    pVirtqProxy->fEventThresholdReached = false;
+    RTStrCopy((char *)pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName), pcszName);
+    return VINF_SUCCESS;
+
+}
+
+/**
+ * See API comments in header file for description
+ */
 const char *virtioQueueGetName(VIRTIOHANDLE hVirtio, uint16_t qIdx)
 {
@@ -134,7 +125,10 @@
                     ("Guest driver not in ready state.\n"), "<null>");
 
-    return (const char *)((PVIRTIOSTATE)hVirtio)->virtqProxy[qIdx].szName;
-}
-
+    return (const char *)((PVIRTIOSTATE)hVirtio)->virtqProxy[qIdx].szVirtqName;
+}
+
+/**
+ * See API comments in header file for description
+ */
 int virtioQueueSkip(VIRTIOHANDLE hVirtio, uint16_t qIdx)
 {
@@ -150,6 +144,5 @@
         return VERR_NOT_AVAILABLE;
 
-    Log2Func(("%s: %s avail_idx=%u\n", INSTANCE(pVirtio),
-          pVirtqProxy->szName, pVirtqProxy->uAvailIdx));
+    Log2Func(("%s avail_idx=%u\n", pVirtqProxy->szVirtqName, pVirtqProxy->uAvailIdx));
     pVirtqProxy->uAvailIdx++;
 
@@ -157,4 +150,18 @@
 }
 
+
+/**
+ * See API comments in header file for description
+ */
+uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio)
+{
+    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
+    return pVirtio->uDriverFeatures;
+}
+
+
+/**
+ * See API comments in header file for description
+ */
 bool virtioQueueIsEmpty(VIRTIOHANDLE hVirtio, uint16_t qIdx)
 {
@@ -163,15 +170,21 @@
 }
 
-int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx)
-{
-    return virtioQueueGet(hVirtio, qIdx, false /* fRemove */);
-}
-
- /** See API comments in header file prototype for description */
-int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove)
+/**
+ * See API comments in header file for description
+ */
+int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs)
+{
+    return virtioQueueGet(hVirtio, qIdx, false /* fRemove */, ppInSegs, ppOutSegs);
+}
+
+ /*/**
+ * See API comments in header file for description
+ */
+int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove,
+                PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs)
 {
     PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
-    PVIRTQ_BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;
+    PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain;
 
     AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
@@ -181,10 +194,12 @@
         return VERR_NOT_AVAILABLE;
 
-    pBufVec->cSegsIn = pBufVec->cSegsOut = 0;
-
-    Log2Func(("%s avail_idx=%u\n", INSTANCE(pVirtio), pVirtqProxy->szName, pVirtqProxy->uAvailIdx));
-
-    uint16_t uDescIdx;
-//    pBufVec->uDescIdx = uDescIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx);
+    pDescChain->cSegsIn = pDescChain->cSegsOut = 0;
+
+
+    pDescChain->uHeadIdx = vqReadAvailRingDescIdx(pVirtio, qIdx, pVirtqProxy->uAvailIdx);
+    uint16_t uDescIdx = pDescChain->uHeadIdx;
+
+    Log2Func(("%s DESC CHAIN: (head) desc_idx=%u [avail_idx=%u]\n",
+            pVirtqProxy->szVirtqName, pDescChain->uHeadIdx, pVirtqProxy->uAvailIdx));
 
     if (fRemove)
@@ -194,5 +209,5 @@
     do
     {
-        VIRTQ_SEG_T *pSeg;
+        RTSGSEG *pSeg;
 
         /**
@@ -202,5 +217,5 @@
         * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
         */
-        if (pBufVec->cSegsIn + pBufVec->cSegsOut >= VIRTQ_MAX_SIZE)
+        if (pDescChain->cSegsIn + pDescChain->cSegsOut >= VIRTQ_MAX_SIZE)
         {
             static volatile uint32_t s_cMessages  = 0;
@@ -208,10 +223,9 @@
             if (ASMAtomicIncU32(&s_cMessages) == ASMAtomicReadU32(&s_cThreshold))
             {
-                LogRel(("%s: too many linked descriptors; "
-                        "check if the guest arranges descriptors in a loop.\n",
-                           INSTANCE(pVirtio)));
+                LogRel(("too many linked descriptors; "
+                        "check if the guest arranges descriptors in a loop.\n"));
                 if (ASMAtomicReadU32(&s_cMessages) != 1)
-                    LogRel(("%s: (the above error has occured %u times so far)\n",
-                            INSTANCE(pVirtio), ASMAtomicReadU32(&s_cMessages)));
+                    LogRel(("(the above error has occured %u times so far)\n",
+                            ASMAtomicReadU32(&s_cMessages)));
                 ASMAtomicWriteU32(&s_cThreshold, ASMAtomicReadU32(&s_cThreshold) * 10);
             }
@@ -220,27 +234,37 @@
         RT_UNTRUSTED_VALIDATED_FENCE();
 
-//        vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);
+        vqReadDesc(pVirtio, qIdx, uDescIdx, &desc);
+
         if (desc.fFlags & VIRTQ_DESC_F_WRITE)
         {
-            Log2Func(("%s: %s IN  seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio),
-                  pVirtqProxy->szName, pBufVec->cSegsIn, uDescIdx, desc.pGcPhysBuf, desc.cb));
-            pSeg = &(pBufVec->aSegsIn[pBufVec->cSegsIn++]);
+            Log2Func(("%*s IN  desc_idx=%u seg=%u addr=%RGp cb=%u\n",
+                RTStrNLen(pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName)), "",
+                uDescIdx, pDescChain->cSegsIn, desc.pGcPhysBuf, desc.cb));
+
+            pSeg = &(pDescChain->aSegsIn[pDescChain->cSegsIn++]);
         }
         else
         {
-            Log2Func(("%s: %s IN  seg=%u desc_idx=%u addr=%RTp cb=%u\n", INSTANCE(pVirtio),
-                  pVirtqProxy->szName, pBufVec->cSegsOut, uDescIdx, desc.pGcPhysBuf, desc.cb));
-            pSeg = &(pBufVec->aSegsOut[pBufVec->cSegsOut++]);
-        }
-
-        pSeg->addr = (RTGCPHYS)desc.pGcPhysBuf;
-        pSeg->cb   = desc.cb;
-        pSeg->pv   = NULL;
+            Log2Func(("%*s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n",
+                RTStrNLen(pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName)), "",
+                uDescIdx, pDescChain->cSegsOut, desc.pGcPhysBuf, desc.cb));
+            pSeg = &(pDescChain->aSegsOut[pDescChain->cSegsOut++]);
+        }
+
+        pSeg->pvSeg = (void *)desc.pGcPhysBuf;
+        pSeg->cbSeg = desc.cb;
 
         uDescIdx = desc.uDescIdxNext;
     } while (desc.fFlags & VIRTQ_DESC_F_NEXT);
 
-    Log2Func(("%s: %s head_desc_idx=%u nIn=%u nOut=%u\n", INSTANCE(pVirtio),
-          pVirtqProxy->szName, pBufVec->uDescIdx, pBufVec->cSegsIn, pBufVec->cSegsOut));
+    RTSgBufInit(&pVirtqProxy->inSgBuf, (PCRTSGSEG)&pDescChain->aSegsIn,  pDescChain->cSegsIn);
+    RTSgBufInit(&pVirtqProxy->outSgBuf,(PCRTSGSEG)&pDescChain->aSegsOut, pDescChain->cSegsOut);
+
+    *ppInSegs  = &pVirtqProxy->inSgBuf;
+    *ppOutSegs = &pVirtqProxy->outSgBuf;
+
+    Log2Func(("%*s -- segs out: %u,  segs in: %u --\n",
+              RTStrNLen(pVirtqProxy->szVirtqName, sizeof(pVirtqProxy->szVirtqName)), "",
+              pDescChain->cSegsOut, pDescChain->cSegsIn));
 
     return VINF_SUCCESS;
@@ -254,48 +278,49 @@
     PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)hVirtio;
     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
-    PVIRTQ_BUF_VECTOR_T pBufVec = pVirtqProxy->pBufVec;
+    PVIRTQ_DESC_CHAIN_T pDescChain = pVirtqProxy->pDescChain;
 
     AssertMsgReturn(DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[qIdx],
                     ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
 
-    Log2Func(("%s: %s desc_idx=%u acb=%u\n",
-             INSTANCE(pVirtio), pVirtqProxy->szName, pBufVec->uDescIdx, pBufVec->cSegsIn));
-
-    uint32_t cbRemaining = pBufVec->cSegsIn;
-
-    for (uint32_t iSeg = 0; iSeg < pBufVec->cSegsIn && cbRemaining > 0; ++iSeg)
-    {
-        uint32_t cbSegLen = pBufVec->aSegsIn[iSeg].cb;
+    Log2Func(("%s desc_idx=%u acb=%u\n",
+             pVirtqProxy->szVirtqName, pDescChain->uHeadIdx, pDescChain->cSegsIn));
+
+    uint32_t cbRemaining = pDescChain->cSegsIn;
+
+    for (uint32_t iSeg = 0; iSeg < pDescChain->cSegsIn && cbRemaining > 0; ++iSeg)
+    {
+        uint32_t cbSegLen = pDescChain->aSegsIn[iSeg].cbSeg;
         if (cbSegLen > cbRemaining)   // last segment only partially used?
             cbSegLen = cbRemaining;
 
-
-        if (pBufVec->aSegsIn[iSeg].pv != NULL)
-        {
-            Log2Func(("%s: %s used_idx=%u seg=%u addr=%p pv=%p cb=%u acb=%u\n",
-                     INSTANCE(pVirtio), pVirtqProxy->szName,
-                     pVirtqProxy->uUsedIdx, iSeg,
-                     (void *)pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv,
-                     pBufVec->aSegsIn[iSeg].cb, cbSegLen));
-
-            PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
-                 pBufVec->aSegsIn[iSeg].addr, pBufVec->aSegsIn[iSeg].pv, cbSegLen);
-        }
+//        if (pDescChain->aSegsIn[iSeg].pv != NULL)
+//        {
+//            Log2Func(("%s used_idx=%u seg=%u addr=%p cb=%u acb=%u\n",
+//                     pVirtqProxy->szVirtqName,
+//                     pVirtqProxy->uUsedIdx, iSeg,
+//                     (void *)pDescChain->aSegsIn[iSeg].addr,
+//                     pDescChain->aSegsIn[iSeg].cbSeg, cbSegLen));
+//
+//            PDMDevHlpPCIPhysWrite(pVirtio->CTX_SUFF(pDevIns),
+//                 pDescChain->aSegsIn[iSeg].pvSeg, pDescChain->aSegsIn[iSeg].pv, cbSegLen);
+//        }
         cbRemaining -= cbSegLen;
     }
 
     uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
-    Log2Func(("%s: %s used_idx=%u guest_used_idx=%u id=%u len=%u\n",
-          INSTANCE(pVirtio), pVirtqProxy->szName,
-          pVirtqProxy->uUsedIdx, uDescIdx, pBufVec->uDescIdx, pBufVec->cSegsIn));
+    Log2Func(("%s used_idx=%u guest_used_idx=%u id=%u len=%u\n",
+          pVirtqProxy->szVirtqName,
+          pVirtqProxy->uUsedIdx, uDescIdx, pDescChain->uHeadIdx, pDescChain->cSegsIn));
 
     if (pVirtqProxy->uUsedIdx == vqReadAvailUsedEvent(pVirtio, qIdx))
         pVirtqProxy->fEventThresholdReached = true;
-    vqWriteUsedElem(pVirtio, qIdx, pVirtqProxy->uUsedIdx++, pBufVec->uDescIdx,  pBufVec->cSegsIn);
+    vqWriteUsedElem(pVirtio, qIdx, pVirtqProxy->uUsedIdx++, pDescChain->uHeadIdx,  pDescChain->cSegsIn);
 
     return VINF_SUCCESS;
 }
 
- /** See API comments in header file prototype for description */
+/**
+ * See API comments in header file for description
+ */
 int virtioQueueSync(VIRTIOHANDLE hVirtio, uint16_t qIdx)
 {
@@ -309,6 +334,6 @@
 
     uint16_t uDescIdx = vqReadUsedDescIdx(pVirtio, qIdx);
-    Log2Func(("%s: %s old_used_idx=%u new_used_idx=%u\n",
-              INSTANCE(pVirtio), uDescIdx, pVirtqProxy->uUsedIdx));
+    Log2Func(("%s old_used_idx=%u new_used_idx=%u\n",
+              uDescIdx, pVirtqProxy->uUsedIdx));
 
     vqWriteUsedRingDescIdx(pVirtio, qIdx, pVirtqProxy->uUsedIdx);
@@ -318,5 +343,7 @@
 }
 
- /** See API comments in header file prototype for description */
+/**
+ * See API comments in header file for description
+ */
 static void virtioQueueNotified(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint16_t uNotifyIdx)
 {
@@ -324,5 +351,5 @@
 
     PVIRTQ_PROXY_T pVirtqProxy = &pVirtio->virtqProxy[qIdx];
-    Log2Func(("%s: %s notified\n", INSTANCE(pVirtio), pVirtqProxy->szName));
+    Log2Func(("%s\n", pVirtqProxy->szVirtqName));
 
     /** Inform client */
@@ -343,6 +370,6 @@
                     ("Guest driver not in ready state.\n"));
 
-    LogFlowFunc(("%s: %s availFlags=%x guestFeatures=%x virtioQueue is %sempty\n",
-        INSTANCE(pVirtio), pVirtqProxy->szName, vqReadAvailFlags(pVirtio, qIdx),
+    LogFlowFunc(("%s availFlags=%x guestFeatures=%x virtioQueue is %sempty\n",
+        pVirtqProxy->szVirtqName, vqReadAvailFlags(pVirtio, qIdx),
             pVirtio->uDriverFeatures, vqIsEmpty(pVirtio, qIdx) ? "" : "not "));
 
@@ -390,5 +417,5 @@
     RT_NOREF(offDelta);
     PVIRTIOSTATE pVirtio = *PDMINS_2_DATA(pDevIns, PVIRTIOSTATE *);
-    LogFunc(("%s\n", INSTANCE(pVirtio)));
+    LogFunc(("\n"));
 
     pVirtio->pDevInsR3 = pDevIns;
@@ -406,8 +433,8 @@
 {
    if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
-       LogFlowFunc(("%s: Cause: queue interrupt\n", INSTANCE(pVirtio)));
+       LogFlowFunc(("Cause: queue interrupt\n"));
    else
    if (uCause == VIRTIO_ISR_DEVICE_CONFIG)
-       LogFlowFunc(("%s: Cause: device config\n", INSTANCE(pVirtio)));
+       LogFlowFunc(("Cause: device config\n"));
 
     pVirtio->uISR |= uCause;
@@ -423,5 +450,5 @@
 static void virtioLowerInterrupt(PVIRTIOSTATE pVirtio)
 {
-    LogFlowFunc(("%s\n", INSTANCE(pVirtio)));
+    LogFlowFunc(("\n"));
     PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 0);
 }
@@ -713,5 +740,5 @@
         {
             ++pVirtio->uConfigGeneration;
-            Log2Func(("Bumped cfg. generation to %d because %s %s\n",
+            Log2Func(("Bumped cfg. generation to %d because %s%s\n",
                 pVirtio->uConfigGeneration,
                 fDevSpecificFieldChanged ? "<dev cfg changed> " : "",
@@ -1024,5 +1051,5 @@
     pVirtio->pDevSpecificCfg  = pDevSpecificCfg;
 
-    pVirtio->pPrevDevSpecificCfg = RTMemAlloc(cbDevSpecificCfg);
+    pVirtio->pPrevDevSpecificCfg = RTMemAllocZ(cbDevSpecificCfg);
     if (!pVirtio->pPrevDevSpecificCfg)
     {
@@ -1131,5 +1158,5 @@
      * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. Example/diagram
      * of spec shows it as a 32-bit field with upper bits 'reserved'
-     * Will take spec words very literally for now and check linux driver.
+     * Will take spec words more literally than the diagram for now.
      */
     pCfg = (PVIRTIO_PCI_CAP_T)&pVirtio->dev.abConfig[pCfg->uCapNext];
@@ -1201,5 +1228,5 @@
      *  out size, so pad with an extra page */
 
-    rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_PCI_CAP,  RT_ALIGN_32(cbRegion + 4096, 4096),
+    rc = PDMDevHlpPCIIORegionRegister(pDevIns, VIRTIOSCSI_REGION_PCI_CAP,  RT_ALIGN_32(cbRegion + 0x1000, 0x1000),
                                       PCI_ADDRESS_SPACE_MEM, virtioR3Map);
     if (RT_FAILURE(rc))
@@ -1253,10 +1280,10 @@
     {
         Log2Func(("%s queue:\n",
-                  "  virtqProxy[%u].uAvailIdx   = %u\n  virtqProxy[%u].uUsedIdx    = %u\n"
+                  "  virtqProxy[%u].uAvailIdx    = %u\n  virtqProxy[%u].uUsedIdx    = %u\n"
                   "  uQueueSize[%u]              = %u\n  uQueueNotifyOff[%u]         = %04x\n"
                   "  uQueueMsixVector[%u]        = %04x\n  uQueueEnable[%u]            = %04x\n"
                   "  pGcPhysQueueDesc[%u]        = %RGp\n  pGcPhysQueueAvail[%u]       = %RGp\n"
                   "  pGcPhysQueueUsed[%u]        = %RGp\n",
-                        i, pVirtio->virtqProxy[i].szName, i, pVirtio->virtqProxy[i].uAvailIdx,
+                        i, pVirtio->virtqProxy[i].szVirtqName, i, pVirtio->virtqProxy[i].uAvailIdx,
                         i, pVirtio->virtqProxy[i].uUsedIdx, i, pVirtio->uQueueSize[i],
                         i, pVirtio->uQueueNotifyOff[i],i, pVirtio->uQueueMsixVector[i],
@@ -1319,5 +1346,5 @@
         rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uAvailIdx);
         rc = SSMR3PutU16(pSSM,      pVirtio->virtqProxy[i].uUsedIdx);
-        rc = SSMR3PutMem(pSSM,      pVirtio->virtqProxy[i].szName, 32);
+        rc = SSMR3PutMem(pSSM,      pVirtio->virtqProxy[i].szVirtqName, 32);
     }
 
@@ -1378,5 +1405,5 @@
             rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uAvailIdx);
             rc = SSMR3GetU16(pSSM,      &pVirtio->virtqProxy[i].uUsedIdx);
-            rc = SSMR3GetMem(pSSM,      (void *)&pVirtio->virtqProxy[i].szName, 32);
+            rc = SSMR3GetMem(pSSM,      (void *)&pVirtio->virtqProxy[i].szVirtqName, 32);
         }
     }
Index: trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
===================================================================
--- trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h	(revision 80340)
+++ trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h	(revision 80383)
@@ -23,8 +23,8 @@
 
 #include <iprt/ctype.h>
+#include <iprt/sg.h>
 
 typedef void * VIRTIOHANDLE;                                     /**< Opaque handle to the VirtIO framework */
 
-#define DISABLE_GUEST_DRIVER 0
 
 /**
@@ -37,24 +37,9 @@
 #define VIRTQ_MAX_SIZE                      1024                 /**< Max size (# desc elements) of a virtq    */
 #define VIRTQ_MAX_CNT                       24                   /**< Max queues we allow guest to create      */
-#define VIRTQ_DESC_MAX_SIZE                 (2 * 1024 * 1024)
+
 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
 #define VIRTIOSCSI_REGION_MEM_IO            0                    /**< BAR for MMIO (implementation specific)   */
 #define VIRTIOSCSI_REGION_PORT_IO           1                    /**< BAR for PORT I/O (impl specific)         */
 #define VIRTIOSCSI_REGION_PCI_CAP           2                    /**< BAR for VirtIO Cap. MMIO (impl specific) */
-typedef struct VIRTQ_SEG                                         /**< Describes one segment of a buffer vector */
-{
-    RTGCPHYS addr;                                               /**< Physical addr. of this segment's buffer  */
-    void    *pv;                                                 /**< Buf to hold value to write or read       */
-    uint32_t cb;                                                 /**< Number of bytes to write or read         */
-} VIRTQ_SEG_T;
-
-    typedef struct VIRTQ_BUF_VECTOR                                  /**< Scatter/gather buffer vector             */
-{
-    uint32_t    uDescIdx;                                        /**< Desc at head of this vector list         */
-    uint32_t    cSegsIn;                                         /**< Count of segments in aSegsIn[]           */
-    uint32_t    cSegsOut;                                        /**< Count of segments in aSegsOut[]          */
-    VIRTQ_SEG_T aSegsIn[VIRTQ_MAX_SIZE];                         /**< List of segments to write to guest       */
-    VIRTQ_SEG_T aSegsOut[VIRTQ_MAX_SIZE];                        /**< List of segments read from guest         */
-} VIRTQ_BUF_VECTOR_T, *PVIRTQ_BUF_VECTOR_T;
 
 /**
@@ -72,5 +57,5 @@
     uint16_t  uRevisionId;                                       /**< PCI Cfg Revision ID                      */
     uint16_t  uInterruptLine;                                    /**< PCI Cfg Interrupt line                   */
-    uint16_t  uInterruptPin;                                     /**< PCI Cfg InterruptPin                     */
+    uint16_t  uInterruptPin;                                     /**< PCI Cfg Interrupt pin                    */
 } VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS;
 
@@ -151,5 +136,5 @@
  * Allocate client context for client to work with VirtIO-provided with queue
  * As a side effect creates a buffer vector a client can get a pointer to
- * with a call to virtioQueueBufVec()
+ * with a call to virtioQueueDescChain()
  *
  * @param  hVirtio   - Handle to VirtIO framework
@@ -164,4 +149,14 @@
  */
 int virtioQueueAttach(VIRTIOHANDLE hVirtio, uint16_t qIdx, const char *pcszName);
+
+
+/**
+ * Get the features VirtIO is running withnow.
+ *
+ * @returns Features the guest driver has accepted, finalizing the operational features
+ *
+ */
+uint64_t virtioGetNegotiatedFeatures(VIRTIOHANDLE hVirtio);
+
 /**
  * Detaches from queue and release resources
@@ -172,14 +167,4 @@
  */
 int virtioQueueDetach(VIRTIOHANDLE hVirtio, uint16_t qIdx);
-
-/**
- * Return pointer to buffer vector object associated with queue
- *
- * @param hVirtio   - Handle for VirtIO framework
- * @param qIdx      - Queue number
- *
- * @returns           Pointer pBufVec if success, else NULL
- */
-PVIRTQ_BUF_VECTOR_T virtioQueueGetBuffer(VIRTIOHANDLE hVirtio, uint16_t qIdx);
 
 /**
@@ -200,9 +185,11 @@
  * @param hVirtio   - Handle for VirtIO framework
  * @param qIdx      - Queue number
+ * @param ppInSegs  - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
+ * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
  *
  * @returns status    VINF_SUCCESS         - Success
  *                    VERR_INVALID_STATE   - VirtIO not in ready state
  */
-int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove);
+int virtioQueueGet(VIRTIOHANDLE hVirtio, uint16_t qIdx, bool fRemove, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs);
 
 /**
@@ -211,4 +198,6 @@
  * @param hVirtio   - Handle for VirtIO framework
  * @param qIdx      - Queue number
+ * @param ppInSegs  - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
+ * @param ppOutSegs - Address to store pointer to host-to-guest data retrieved from virtq as RTSGBUF
  *
  * @returns           VINF_SUCCESS         - Success
@@ -216,5 +205,5 @@
  *                    VERR_NOT_AVAILABLE   - Queue is empty
  */
-int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx);
+int virtioQueuePeek(VIRTIOHANDLE hVirtio, uint16_t qIdx, PPRTSGBUF ppInSegs, PPRTSGBUF ppOutSegs);
 
 /**
Index: trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
===================================================================
--- trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h	(revision 80340)
+++ trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h	(revision 80383)
@@ -59,5 +59,5 @@
 #define VIRTIO_STATUS_DEVICE_NEEDS_RESET             0x40        /**< Device experienced unrecoverable error    */
 
-/* @def Virtio Device PCI Capabilities type codes */
+/** @def Virtio Device PCI Capabilities type codes */
 #define VIRTIO_PCI_CAP_COMMON_CFG                       1        /**< Common configuration PCI capability ID    */
 #define VIRTIO_PCI_CAP_NOTIFY_CFG                       2        /**< Notification area PCI capability ID       */
@@ -85,13 +85,28 @@
 
 /**
+ * Translation of the descriptor chain associated with one element of virtq avail ring into its
+ * IN and OUT components and represented as respective arrays of SG segments.
+ */
+typedef struct VIRTQ_DESC_CHAIN                                  /**< Describes a single queue element          */
+{
+    RTSGSEG     aSegsIn[VIRTQ_MAX_SIZE];                         /**< List of segments to write to guest        */
+    RTSGSEG     aSegsOut[VIRTQ_MAX_SIZE];                        /**< List of segments read from guest          */
+    uint32_t    uHeadIdx;                                        /**< Index at head desc (source of seg arrays) */
+    uint32_t    cSegsIn;                                         /**< Count of segments in aSegsIn[]            */
+    uint32_t    cSegsOut;                                        /**< Count of segments in aSegsOut[]           */
+} VIRTQ_DESC_CHAIN_T, *PVIRTQ_DESC_CHAIN_T;
+
+/**
  * Local implementation's usage context of a queue (e.g. not part of VirtIO specification)
  */
 typedef struct VIRTQ_PROXY
 {
-    const char          szName[32];                              /**< Dev-specific name of queue                */
-    PVIRTQ_BUF_VECTOR_T pBufVec;                                 /**< Per-queue s/g data. Serialize access!     */
-    uint16_t            uAvailIdx;                               /**< Consumer's position in avail ring         */
-    uint16_t            uUsedIdx;                                /**< Consumer's position in used ring          */
-    bool                fEventThresholdReached;                  /**< Don't lose track while queueing ahead     */
+    RTSGBUF     inSgBuf;                                         /**< host-to-guest buffers                     */
+    RTSGBUF     outSgBuf;                                        /**< guest-to-host buffers                     */
+    const char  szVirtqName[32];                                 /**< Dev-specific name of queue                */
+    uint16_t    uAvailIdx;                                       /**< Consumer's position in avail ring         */
+    uint16_t    uUsedIdx;                                        /**< Consumer's position in used ring          */
+    bool        fEventThresholdReached;                          /**< Don't lose track while queueing ahead     */
+    PVIRTQ_DESC_CHAIN_T pDescChain;                              /**< Per-queue s/g data.                       */
 } VIRTQ_PROXY_T, *PVIRTQ_PROXY_T;
 
@@ -107,8 +122,8 @@
     uint32_t  uDeviceFeatures;                                   /**< RO (device reports features to driver)    */
     uint32_t  uDriverFeaturesSelect;                             /**< RW (driver selects driver features)       */
-    uint32_t  uDriverFeatures;                                   /**< RW (driver accepts device features)       */
+    uint32_t  uDriverFeatures;                                   /**< RW (driver-accepted device features)      */
     uint16_t  uMsixConfig;                                       /**< RW (driver sets MSI-X config vector)      */
     uint16_t  uNumQueues;                                        /**< RO (device specifies max queues)          */
-    uint8_t   uDeviceStatus;                                     /**< RW (driver writes device status, 0 resets)*/
+    uint8_t   uDeviceStatus;                                     /**< RW (driver writes device status, 0=reset) */
     uint8_t   uConfigGeneration;                                 /**< RO (device changes when changing configs) */
 
@@ -136,5 +151,4 @@
 } VIRTIO_PCI_CFG_CAP_T,   *PVIRTIO_PCI_CFG_CAP_T;
 
-
 /**
  * The core (/common) state of the VirtIO PCI device
@@ -146,5 +160,5 @@
     PDMPCIDEV                 dev;                               /**< PCI device                                */
     char                      szInstance[16];                    /**< Instance name, e.g. "VIRTIOSCSI0"         */
-    void *                    pClientContext;                     /**< Client callback returned on callbacks     */
+    void *                    pClientContext;                    /**< Client callback returned on callbacks     */
 
     PPDMDEVINSR3              pDevInsR3;                         /**< Device instance - R3                      */
@@ -177,5 +191,5 @@
     uint8_t                   uConfigGeneration;                 /**< (MMIO) Device config sequencer       HOST */
 
-    VIRTQ_PROXY_T             virtqProxy[VIRTQ_MAX_CNT];        /**< Local impl-specific queue context         */
+    VIRTQ_PROXY_T             virtqProxy[VIRTQ_MAX_CNT];         /**< Local impl-specific queue context         */
     VIRTIOCALLBACKS           virtioCallbacks;                   /**< Callback vectors to client                */
 
@@ -223,5 +237,5 @@
     uint16_t  uDescIdx;                                          /**< idx        Index of next free ring slot   */
     uint16_t  auRing[1];                                         /**< ring       Ring: avail drv to dev bufs    */
-    uint16_t  uUsedEventIdx;                                     /**< used_event (if VIRTQ_USED_F_NO_NOTIFY)    */
+    uint16_t  uUsedEventIdx;                                     /**< used_event (if VIRTQ_USED_F_EVENT_IDX)    */
 } VIRTQ_AVAIL_T, *PVIRTQ_AVAIL_T;
 
@@ -237,5 +251,5 @@
     uint16_t  uDescIdx;                                          /**< idx         Index of next ring slot       */
     VIRTQ_USED_ELEM_T auRing[1];                                 /**< ring        Ring: used dev to drv bufs    */
-    uint16_t  uAvailEventIdx;                                    /**< avail_event if (VIRTQ_USED_F_NO_NOTIFY)   */
+    uint16_t  uAvailEventIdx;                                    /**< avail_event if (VIRTQ_USED_F_EVENT_IDX)   */
 } VIRTQ_USED_T, *PVIRTQ_USED_T;
 
@@ -335,5 +349,5 @@
  */
 
-static int         vqIsEventNeeded(uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
+static int         vqIsEventNeeded        (uint16_t uEventIdx, uint16_t uDescIdxNew, uint16_t uDescIdxOld);
 static bool        vqIsEmpty              (PVIRTIOSTATE pVirtio, uint16_t qIdx);
 static void        vqReadDesc             (PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc);
@@ -361,5 +375,5 @@
 
 /**
- * Accessor for virtq descspVirtio
+ * Accessor for virtq descriptor
  */
 DECLINLINE(void) vqReadDesc(PVIRTIOSTATE pVirtio, uint16_t qIdx, uint32_t uDescIdx, PVIRTQ_DESC_T pDesc)
