Index: /trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp
===================================================================
--- /trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp	(revision 91702)
+++ /trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp	(revision 91703)
@@ -119,5 +119,5 @@
  */
 
-#define FEATURE_ENABLED(feature)        RT_BOOL(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)
+#define FEATURE_ENABLED(feature)        RT_BOOL(!!(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature))
 #define FEATURE_DISABLED(feature)       (!FEATURE_ENABLED(feature))
 #define FEATURE_OFFERED(feature)        VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature
@@ -165,14 +165,10 @@
             (virtioCoreVirtqAvailBufCount(pDevIns, pVirtio, uVirtqNbr) == 0)
 
-#define PCI_DEVICE_ID_VIRTIONET_HOST               0x1041      /**< Informs guest driver of type of VirtIO device   */
-#define PCI_CLASS_BASE_NETWORK_CONTROLLER          0x02        /**< PCI Network device class                        */
+
+#define PCI_DEVICE_ID_VIRTIONET_HOST               0x1000      /**< VirtIO transitional device ID for network card  */
+#define PCI_CLASS_BASE_NETWORK_CONTROLLER          0x0200      /**< PCI Network device class                        */
 #define PCI_CLASS_SUB_NET_ETHERNET_CONTROLLER      0x00        /**< PCI NET Controller subclass                     */
 #define PCI_CLASS_PROG_UNSPECIFIED                 0x00        /**< Programming interface. N/A.                     */
 #define VIRTIONET_PCI_CLASS                        0x01        /**< Base class Mass Storage?                        */
-
-
-/*********************************************************************************************************************************
-*   Structures and Typedefs                                                                                                      *
-*********************************************************************************************************************************/
 
 /**
@@ -373,5 +369,5 @@
 
     /** Number of virtqueues total (which includes each queue of each pair plus one control queue */
-    uint16_t                cVirtVirtqs;
+    uint16_t                cVirtqs;
 
     /** Number of worker threads (one for the control queue and one for each Tx queue) */
@@ -444,4 +440,6 @@
     bool                    fCableConnected;
 
+    /** True if guest has not reported modern virtio driver */
+    bool                    fIsLegacy;
     /** @name Statistic
      * @{ */
@@ -553,4 +551,30 @@
 static int virtioNetR3CreateWorkerThreads(PPDMDEVINS, PVIRTIONET, PVIRTIONETCC);
 
+typedef enum VIRTIONETPKTHDRTYPE
+{
+    kVirtioNetModernPktHdr_1_0          = 0,
+    kVirtioNetLegacyPktHdr              = 1,
+    kVirtioNetLegacyPktHdrWithoutMrgRx  = 2,
+    kVirtioNetFor32BitHack              = 0x7fffffff
+} VIRTIONETPKTHDRTYPE;
+
+DECLINLINE(int) virtioNetPktHdrType(PVIRTIOCORE pVirtio, PVIRTIONET pThis)
+{
+    if (!virtioCoreIsLegacyMode(pVirtio))
+        return kVirtioNetModernPktHdr_1_0;
+    else /* legacy mode */
+        if (FEATURE_ENABLED(MRG_RXBUF))
+            return kVirtioNetLegacyPktHdrWithoutMrgRx;
+    return kVirtioNetLegacyPktHdr;
+}
+
+DECLINLINE(size_t) virtioNetCalcPktHdrSize(PVIRTIOCORE pVirtio, PVIRTIONET pThis)
+{
+    size_t cbHdr = sizeof(VIRTIONETPKTHDR);
+    if (virtioCoreIsLegacyMode(pVirtio) & !FEATURE_ENABLED(MRG_RXBUF))
+        cbHdr -= RT_SIZEOFMEMB(VIRTIONETPKTHDR, uNumBuffers);
+    return cbHdr;
+}
+
 DECLINLINE(const char *) virtioNetThreadStateName(PPDMTHREAD pThread)
 {
@@ -594,5 +618,5 @@
     if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT)
     {
-        Log10Func(("%s Waking downstream device's Rx buf waiter thread\n", pThis->szInst));
+        Log10Func(("[%s] Waking downstream device's Rx buf waiter thread\n", pThis->szInst));
         int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEventRxDescAvail);
         AssertRC(rc);
@@ -600,6 +624,4 @@
 }
 
-
-
 /**
  * @callback_method_impl{VIRTIOCORER0,pfnVirtqNotified}
@@ -614,9 +636,6 @@
 
 #if defined (IN_RING3) && defined (LOG_ENABLED)
-
-     RTLogFlush(NULL);
-
+    RTLogFlush(NULL);
 #endif
-
     if (IS_RX_VIRTQ(uVirtqNbr))
     {
@@ -640,5 +659,5 @@
             if (ASMAtomicReadBool(&pWorker->fSleeping))
             {
-                Log10Func(("%s %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
+                Log10Func(("[%s] %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
 
                 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
@@ -647,14 +666,14 @@
             else
             {
-                Log10Func(("%s %s has available buffers - worker already awake\n", pThis->szInst, pVirtq->szName));
+                Log10Func(("[%s] %s has available buffers - worker already awake\n", pThis->szInst, pVirtq->szName));
             }
         }
         else
         {
-            Log10Func(("%s %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
+            Log10Func(("[%s] %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
         }
     }
     else
-        LogRelFunc(("%s unrecognized queue %s (idx=%d) notified\n", pThis->szInst, pVirtq->szName, uVirtqNbr));
+        LogRelFunc(("[%s] unrecognized queue %s (idx=%d) notified\n", pThis->szInst, pVirtq->szName, uVirtqNbr));
 }
 
@@ -669,7 +688,6 @@
     PVIRTIONETWORKER pWorker = (PVIRTIONETWORKER)pThread->pvUser;
 
-    Log10Func(("%s\n", pThis->szInst));
+    Log10Func(("[%s]\n", pThis->szInst));
     RT_NOREF(pThis);
-
     return PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
 }
@@ -770,16 +788,17 @@
     {
         LogFunc(("-------------------------------------------------------------------\n"));
-        LogFunc(("rxPktHdr\n"
-                 "    uFlags ......... %2.2x\n"
-                 "    uGsoType ....... %2.2x\n"
-                 "    uHdrLen ........ %4.4x\n"
-                 "    uGsoSize ....... %4.4x\n"
-                 "    uChksumStart ... %4.4x\n"
-                 "    uChksumOffset .. %4.4x\n"
-                 "    uNumBuffers .... %4.4x\n",
-                        pRxPktHdr->uFlags,
-                        pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
-                        pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers));
-
+        if (!virtioCoreIsLegacyMode(&pThis->Virtio) || FEATURE_ENABLED(MRG_RXBUF))
+                LogFunc(("rxPktHdr\n"
+                         "    uFlags ......... %2.2x\n    uGsoType ....... %2.2x\n    uHdrLen ........ %4.4x\n"
+                         "    uGsoSize ....... %4.4x\n    uChksumStart ... %4.4x\n    uChksumOffset .. %4.4x\n"
+                         "    uNumBuffers .... %4.4x\n",
+                                pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
+                                pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers));
+        else
+                LogFunc(("rxPktHdr\n"
+                         "    uFlags ......... %2.2x\n    uGsoType ....... %2.2x\n    uHdrLen ........ %4.4x\n"
+                         "    uGsoSize ....... %4.4x\n    uChksumStart ... %4.4x\n    uChksumOffset .. %4.4x\n",
+                                pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
+                                pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset));
         virtioCoreHexDump((uint8_t *)pRxPktHdr, sizeof(VIRTIONETPKTHDR), 0, "Dump of virtual rPktHdr");
     }
@@ -833,6 +852,5 @@
     {
         pHlp->pfnPrintf(pHlp, "Virtq information:\n\n");
-
-        for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
+        for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
         {
             PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr];
@@ -879,7 +897,5 @@
     if (fAll || fPointers)
     {
-
         pHlp->pfnPrintf(pHlp, "Internal Pointers:\n\n");
-
         pHlp->pfnPrintf(pHlp, "    pDevIns ................... %p\n",   pDevIns);
         pHlp->pfnPrintf(pHlp, "    PVIRTIONET ................ %p\n",   pThis);
@@ -889,5 +905,4 @@
         pHlp->pfnPrintf(pHlp, "    pDrv ...................... %p\n",   pThisCC->pDrv);
         pHlp->pfnPrintf(pHlp, "\n");
-
     }
 
@@ -908,5 +923,5 @@
         pHlp->pfnPrintf(pHlp, "    uDeviceStatus ............. 0x%x\n", pThis->Virtio.fDeviceStatus);
         pHlp->pfnPrintf(pHlp, "    cVirtqPairs .,............. %d\n",   pThis->cVirtqPairs);
-        pHlp->pfnPrintf(pHlp, "    cVirtVirtqs .,............. %d\n",   pThis->cVirtVirtqs);
+        pHlp->pfnPrintf(pHlp, "    cVirtqs .,................. %d\n",   pThis->cVirtqs);
         pHlp->pfnPrintf(pHlp, "    cWorkers .................. %d\n",   pThis->cWorkers);
         pHlp->pfnPrintf(pHlp, "    MMIO mapping name ......... %d\n",   pThisCC->Virtio.pcszMmioName);
@@ -918,5 +933,4 @@
     {
         pHlp->pfnPrintf(pHlp, "Network configuration:\n\n");
-
         pHlp->pfnPrintf(pHlp, "    MAC: ...................... %RTmac\n", &pThis->macConfigured);
         pHlp->pfnPrintf(pHlp, "\n");
@@ -952,5 +966,4 @@
         pHlp->pfnPrintf(pHlp, "    Leaf starved: ............. %s\n",      pThis->fLeafWantsEmptyRxBufs ? "true" : "false");
         pHlp->pfnPrintf(pHlp, "\n");
-
     }
     /** @todo implement this
@@ -1001,5 +1014,5 @@
 }
 
-static int virtioNetR3CfgAccessed(PVIRTIONET pThis, uint32_t uOffsetOfAccess, void *pv, uint32_t cb, bool fWrite)
+static int virtioNetR3DevCfgAccess(PVIRTIONET pThis, uint32_t uOffsetOfAccess, void *pv, uint32_t cb, bool fWrite)
 {
     AssertReturn(pv && cb <= sizeof(uint32_t), fWrite ? VINF_SUCCESS : VINF_IOM_MMIO_UNUSED_00);
@@ -1033,7 +1046,6 @@
     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
 
-    LogFunc((" %s uOffset: %d, cb: %d\n",  pThis->szInst, uOffset, cb));
     RT_NOREF(pThis);
-    return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, pv, cb, false /*fRead*/);
+    return virtioNetR3DevCfgAccess(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, pv, cb, false /*fRead*/);
 }
 
@@ -1045,7 +1057,7 @@
     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
 
-    Log10Func(("%s uOffset: %d, cb: %d: %.*Rhxs\n", pThis->szInst, uOffset, cb, RT_MAX(cb, 8) , pv));
+    Log10Func(("[%s] uOffset: %d, cb: %d: %.*Rhxs\n", pThis->szInst, uOffset, cb, RT_MAX(cb, 8) , pv));
     RT_NOREF(pThis);
-    return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, (void *)pv, cb, true /*fWrite*/);
+    return virtioNetR3DevCfgAccess(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, (void *)pv, cb, true /*fWrite*/);
 }
 
@@ -1065,5 +1077,5 @@
 
     RT_NOREF(pThisCC);
-    Log7Func(("%s LOAD EXEC!!\n", pThis->szInst));
+    Log7Func(("[%s] LOAD EXEC!!\n", pThis->szInst));
 
     AssertReturn(uPass == SSM_PASS_FINAL, VERR_SSM_UNEXPECTED_PASS);
@@ -1075,6 +1087,6 @@
     pHlp->pfnSSMGetU64(     pSSM, &pThis->fNegotiatedFeatures);
 
-    pHlp->pfnSSMGetU16(     pSSM, &pThis->cVirtVirtqs);
-    AssertReturn(pThis->cVirtVirtqs <= (VIRTIONET_MAX_QPAIRS * 2), VERR_OUT_OF_RANGE);
+    pHlp->pfnSSMGetU16(     pSSM, &pThis->cVirtqs);
+    AssertReturn(pThis->cVirtqs <= (VIRTIONET_MAX_QPAIRS * 2), VERR_OUT_OF_RANGE);
 
     pHlp->pfnSSMGetU16(     pSSM, &pThis->cWorkers);
@@ -1082,5 +1094,5 @@
 
 
-    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
+    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
         pHlp->pfnSSMGetBool(pSSM, &pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore);
 
@@ -1148,5 +1160,5 @@
         if (pVirtq->fAttachedToVirtioCore)
         {
-            Log7Func(("%s Waking %s worker.\n", pThis->szInst, pVirtq->szName));
+            Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName));
             rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
             AssertRCReturn(rc, rc);
@@ -1166,12 +1178,12 @@
 
     RT_NOREF(pThisCC);
-    Log7Func(("%s SAVE EXEC!!\n", pThis->szInst));
+    Log7Func(("[%s] SAVE EXEC!!\n", pThis->szInst));
 
     pHlp->pfnSSMPutU64(     pSSM, pThis->fNegotiatedFeatures);
 
-    pHlp->pfnSSMPutU16(     pSSM, pThis->cVirtVirtqs);
+    pHlp->pfnSSMPutU16(     pSSM, pThis->cVirtqs);
     pHlp->pfnSSMPutU16(     pSSM, pThis->cWorkers);
 
-    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
+    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
         pHlp->pfnSSMPutBool(pSSM, pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore);
 
@@ -1249,5 +1261,4 @@
 void virtioNetR3SetReadLed(PVIRTIONETR3 pThisR3, bool fOn)
 {
-    Log10Func(("%s\n", fOn ? "on" : "off"));
     if (fOn)
         pThisR3->led.Asserted.s.fReading = pThisR3->led.Actual.s.fReading = 1;
@@ -1301,15 +1312,15 @@
 
     if (!virtioNetIsOperational(pThis, pDevIns))
-        Log8Func(("%s No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));
+        Log8Func(("[%s] No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));
 
     else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio, pRxVirtq->uIdx))
-        Log8Func(("%s No Rx bufs available. (%s not enabled)\n",  pThis->szInst, pRxVirtq->szName));
+        Log8Func(("[%s] No Rx bufs available. (%s not enabled)\n",  pThis->szInst, pRxVirtq->szName));
 
     else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxVirtq->uIdx))
-        Log8Func(("%s No Rx bufs available. (%s empty)\n",  pThis->szInst, pRxVirtq->szName));
+        Log8Func(("[%s] No Rx bufs available. (%s empty)\n",  pThis->szInst, pRxVirtq->szName));
 
     else
     {
-        Log8Func(("%s Empty guest buffers available in %s\n",  pThis->szInst,pRxVirtq->szName));
+        Log8Func(("[%s] %s has empty guest bufs avail\n",  pThis->szInst, pRxVirtq->szName));
         rc = VINF_SUCCESS;
     }
@@ -1347,5 +1358,5 @@
     if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
     {
-        Log10Func(("%s Rx bufs now available, releasing waiter...\n", pThis->szInst));
+        Log10Func(("[%s] Rx bufs now available, releasing waiter...\n", pThis->szInst));
         return VINF_SUCCESS;
     }
@@ -1353,5 +1364,5 @@
         return VERR_NET_NO_BUFFER_SPACE;
 
-    LogFunc(("%s %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : ""));
+    LogFunc(("[%s] %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : ""));
 
 
@@ -1362,9 +1373,9 @@
         if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
         {
-            Log10Func(("%s Rx bufs now available, releasing waiter...\n", pThis->szInst));
+            Log10Func(("[%s] Rx bufs now available, releasing waiter...\n", pThis->szInst));
             ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, false);
             return VINF_SUCCESS;
         }
-        Log9Func(("%s Starved for empty guest Rx bufs. Waiting...\n", pThis->szInst));
+        Log9Func(("[%s] Starved for empty guest Rx bufs. Waiting...\n", pThis->szInst));
 
         int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventRxDescAvail, timeoutMs);
@@ -1388,5 +1399,5 @@
     ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, false);
 
-    Log7Func(("%s Wait for Rx buffers available was interrupted\n", pThis->szInst));
+    Log7Func(("[%s] Wait for Rx buffers available was interrupted\n", pThis->szInst));
     return VERR_INTERRUPTED;
 }
@@ -1487,19 +1498,21 @@
         char *pszType;
         if (virtioNetR3IsMulticast(pvBuf))
-            pszType = (char *)"Multicast";
+            pszType = (char *)"mcast";
         else if (virtioNetR3IsBroadcast(pvBuf))
-            pszType = (char *)"Broadcast";
+            pszType = (char *)"bcast";
         else
-            pszType = (char *)"Unicast";
-
-        LogFunc(("%s node(%RTmac %s%s), pkt(%RTmac %s)\n",
-                 pThis->szInst, pThis->virtioNetConfig.uMacAddress.au8,
-                 pThis->fPromiscuous ? "promiscuous" : "",
-                 pThis->fAllMulticast ? " all-multicast" : "",
+            pszType = (char *)"ucast";
+
+        LogFunc(("node(%RTmac%s%s), pkt(%RTmac, %s) ",
+                 pThis->virtioNetConfig.uMacAddress.au8,
+                 pThis->fPromiscuous ? " promisc" : "",
+                 pThis->fAllMulticast ? " all-mcast" : "",
                  pvBuf,  pszType));
     }
 
-    if (pThis->fPromiscuous)
+    if (pThis->fPromiscuous) {
+        Log11(("\n"));
         return true;
+    }
 
     /* Ignore everything outside of our VLANs */
@@ -1510,5 +1523,5 @@
         && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_U16(uPtr[7]) & 0xFFF))
     {
-        Log11Func(("\n%s not our VLAN, returning false\n", pThis->szInst));
+        Log11Func(("\n[%s] not our VLAN, returning false\n", pThis->szInst));
         return false;
     }
@@ -1516,5 +1529,5 @@
     if (virtioNetR3IsBroadcast(pvBuf))
     {
-        Log11(("... accept (broadcast)\n"));
+        Log11(("acpt (bcast)\n"));
         if (LogIs12Enabled())
             virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
@@ -1523,5 +1536,5 @@
     if (pThis->fAllMulticast && virtioNetR3IsMulticast(pvBuf))
     {
-        Log11(("... accept (all-multicast mode)\n"));
+        Log11(("acpt (all-mcast)\n"));
         if (LogIs12Enabled())
             virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
@@ -1531,5 +1544,5 @@
     if (!memcmp(pThis->virtioNetConfig.uMacAddress.au8, pvBuf, sizeof(RTMAC)))
     {
-        Log11((". . . accept (direct to this node)\n"));
+        Log11(("acpt (to-node)\n"));
         if (LogIs12Enabled())
             virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
@@ -1541,5 +1554,5 @@
         if (!memcmp(&pThis->aMacMulticastFilter[i], pvBuf, sizeof(RTMAC)))
         {
-            Log11(("... accept (in multicast array)\n"));
+            Log11(("acpt (mcast whitelist)\n"));
             if (LogIs12Enabled())
                 virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
@@ -1551,9 +1564,9 @@
         if (!memcmp(&pThis->aMacUnicastFilter[i], pvBuf, sizeof(RTMAC)))
         {
-            Log11(("... accept (in unicast array)\n"));
+            Log11(("acpt (ucast whitelist)\n"));
             return true;
         }
 
-    if (LogIs12Enabled())
+    if (LogIs11Enabled())
         Log(("... reject\n"));
 
@@ -1570,4 +1583,6 @@
     uint16_t cVirtqBufs  = 0;
     uint64_t uOffset = 0;
+
+    int uPktHdrType = virtioNetPktHdrType(&pThis->Virtio,  pThis);
 
     while (uOffset < cb)
@@ -1584,15 +1599,16 @@
                             VERR_INTERNAL_ERROR);
 
-        /* Length of first seg of guest Rx S/G buf should never be less than sizeof(virtio_net_pkt_hdr).
+        /* Length of first seg of guest Rx S/G buf should never be less than sthe packet header.
          * Otherwise code has to become more complicated, e.g. locate & cache seg idx & offset of
-         * virtio_net_header.num_buffers, to facilitate deferring updating GCPhys memory. Re-visit if needed */
-
-        AssertMsgReturnStmt(pVirtqBuf->pSgPhysReturn->paSegs[0].cbSeg >= sizeof(VIRTIONETPKTHDR),
-                            ("Desc chain's first seg has insufficient space for pkt header!\n"),
-                            virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf),
-                            VERR_INTERNAL_ERROR);
+         * virtio_net_header.num_buffers, to facilitate deferring updating GCPhys memory.
+         * Re-visit if needed */
+
+        size_t cbPktHdr = virtioNetCalcPktHdrSize(&pThis->Virtio, pThis);
+
+        AssertMsgReturn(pVirtqBuf->pSgPhysReturn->paSegs[0].cbSeg >= cbPktHdr,
+                            ("Out of Memory"), VERR_NO_MEMORY);
 
         size_t cbBufRemaining = pVirtqBuf->cbPhysReturn;
-        uint8_t  cbHdr = sizeof(VIRTIONETPKTHDR);
+
 
         /* Fill the Guest Rx buffer with data received from the interface */
@@ -1602,14 +1618,17 @@
             {
                 /* Lead with packet header */
-                paVirtSegsToGuest[0].cbSeg = cbHdr;
-                paVirtSegsToGuest[0].pvSeg = RTMemAlloc(cbHdr);
+                paVirtSegsToGuest[0].cbSeg = cbPktHdr;
+                paVirtSegsToGuest[0].pvSeg = RTMemAlloc(cbPktHdr);
                 AssertReturn(paVirtSegsToGuest[0].pvSeg, VERR_NO_MEMORY);
-                cbBufRemaining -= cbHdr;
-
-                memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, cbHdr);
-
-                /* Calculate & cache GCPhys addr of field to update after final value is known */
-                GCPhysPktHdrNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys
-                                       + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers);
+                cbBufRemaining -= cbPktHdr;
+
+                memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, cbPktHdr);
+
+                if (uPktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx)
+                {
+                    /* Calculate & cache GCPhys addr of field to update after final value is known */
+                    GCPhysPktHdrNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys
+                                           + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers);
+                }
                 fAddPktHdr = false;
                 cSegs++;
@@ -1648,12 +1667,15 @@
     if (uOffset < cb)
     {
-        LogFunc(("%s Packet did not fit into RX queue (packet size=%u)!\n", pThis->szInst, cb));
+        LogFunc(("[%s] Packet did not fit into RX queue (packet size=%u)!\n", pThis->szInst, cb));
         return VERR_TOO_MUCH_DATA;
     }
 
-    /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */
-
-    int rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhysPktHdrNumBuffers, &cVirtqBufs, sizeof(cVirtqBufs));
-    AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc);
+
+    if (uPktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx)
+    {
+        /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */
+        int rc = virtioCoreGCPhysWrite(&pThis->Virtio, pDevIns, GCPhysPktHdrNumBuffers, &cVirtqBufs, sizeof(cVirtqBufs));
+        AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc);
+    }
 
     virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, pRxVirtq->uIdx);
@@ -1683,10 +1705,10 @@
     RT_NOREF(pThisCC);
 
-    LogFunc(("%s (%RTmac) pGso %s\n", pThis->szInst, pvBuf, pGso ? "present" : "not present"));
+    LogFunc(("[%s] (%RTmac) pGso %s\n", pThis->szInst, pvBuf, pGso ? "present" : "not present"));
     VIRTIONETPKTHDR rxPktHdr;
 
     if (pGso)
     {
-        Log2Func(("%s gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
+        Log2Func(("[%s] gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
               pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal,
               pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
@@ -1783,10 +1805,10 @@
         if (!uFeatures)
         {
-            LogFunc(("%s GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type));
+            LogFunc(("[%s] GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type));
             return VERR_NOT_SUPPORTED;
         }
     }
 
-    Log10Func(("%s pvBuf=%p cb=%3u pGso=%p ...\n", pThis->szInst, pvBuf, cb, pGso));
+    Log10Func(("[%s] pvBuf=%p cb=%3u pGso=%p ...\n", pThis->szInst, pvBuf, cb, pGso));
 
     /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue
@@ -1830,7 +1852,7 @@
 {
 
-#define LOG_VIRTIONET_FLAG(fld) LogFunc(("%s Setting %s=%d\n", pThis->szInst, #fld, pThis->fld))
-
-    LogFunc(("%s Processing CTRL Rx command\n", pThis->szInst));
+#define LOG_VIRTIONET_FLAG(fld) LogFunc(("[%s] Setting %s=%d\n", pThis->szInst, #fld, pThis->fld))
+
+    LogFunc(("[%s] Processing CTRL Rx command\n", pThis->szInst));
     switch(pCtrlPktHdr->uCmd)
     {
@@ -1893,5 +1915,6 @@
 static uint8_t virtioNetR3CtrlMac(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
 {
-    LogFunc(("%s Processing CTRL MAC command\n", pThis->szInst));
+    LogFunc(("[%s] Processing CTRL MAC command\n", pThis->szInst));
+
 
     AssertMsgReturn(pVirtqBuf->cbPhysSend >= sizeof(*pCtrlPktHdr),
@@ -1925,5 +1948,5 @@
             cbRemaining -= sizeof(cMacs);
 
-            Log7Func(("%s Guest provided %d unicast MAC Table entries\n", pThis->szInst, cMacs));
+            Log7Func(("[%s] Guest provided %d unicast MAC Table entries\n", pThis->szInst, cMacs));
 
             if (cMacs)
@@ -1950,5 +1973,5 @@
             cbRemaining -= sizeof(cMacs);
 
-            Log10Func(("%s Guest provided %d multicast MAC Table entries\n", pThis->szInst, cMacs));
+            Log10Func(("[%s] Guest provided %d multicast MAC Table entries\n", pThis->szInst, cMacs));
 
 
@@ -1968,9 +1991,9 @@
 
 #ifdef LOG_ENABLED
-            LogFunc(("%s unicast MACs:\n", pThis->szInst));
+            LogFunc(("[%s] unicast MACs:\n", pThis->szInst));
             for(unsigned i = 0; i < cMacs; i++)
                 LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
 
-            LogFunc(("%s multicast MACs:\n", pThis->szInst));
+            LogFunc(("[%s] multicast MACs:\n", pThis->szInst));
             for(unsigned i = 0; i < cMacs; i++)
                 LogFunc(("         %RTmac\n", &pThis->aMacMulticastFilter[i]));
@@ -1987,5 +2010,5 @@
 static uint8_t virtioNetR3CtrlMultiQueue(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMDEVINS pDevIns, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
 {
-    LogFunc(("%s Processing CTRL MQ command\n", pThis->szInst));
+    LogFunc(("[%s] Processing CTRL MQ command\n", pThis->szInst));
 
     uint16_t cVirtqPairs;
@@ -2003,7 +2026,7 @@
 
             AssertMsgReturn(cVirtqPairs > VIRTIONET_MAX_QPAIRS,
-                ("%s Guest CTRL MQ virtq pair count out of range)\n", pThis->szInst, cVirtqPairs), VIRTIONET_ERROR);
-
-            LogFunc(("%s Guest specifies %d VQ pairs in use\n", pThis->szInst, cVirtqPairs));
+                ("[%s] Guest CTRL MQ virtq pair count out of range)\n", pThis->szInst, cVirtqPairs), VIRTIONET_ERROR);
+
+            LogFunc(("[%s] Guest specifies %d VQ pairs in use\n", pThis->szInst, cVirtqPairs));
             pThis->cVirtqPairs = cVirtqPairs;
             break;
@@ -2035,5 +2058,5 @@
 static uint8_t virtioNetR3CtrlVlan(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
 {
-    LogFunc(("%s Processing CTRL VLAN command\n", pThis->szInst));
+    LogFunc(("[%s] Processing CTRL VLAN command\n", pThis->szInst));
 
     uint16_t uVlanId;
@@ -2049,5 +2072,5 @@
         ("%s VLAN ID out of range (VLAN ID=%u)\n", pThis->szInst, uVlanId), VIRTIONET_ERROR);
 
-    LogFunc(("%s uCommand=%u VLAN ID=%u\n", pThis->szInst, pCtrlPktHdr->uCmd, uVlanId));
+    LogFunc(("[%s] uCommand=%u VLAN ID=%u\n", pThis->szInst, pCtrlPktHdr->uCmd, uVlanId));
 
     switch (pCtrlPktHdr->uCmd)
@@ -2069,14 +2092,14 @@
                             PVIRTQBUF pVirtqBuf)
 {
-    LogFunc(("%s Received CTRL packet from guest\n", pThis->szInst));
+    LogFunc(("[%s] Received CTRL packet from guest\n", pThis->szInst));
 
     if (pVirtqBuf->cbPhysSend < 2)
     {
-        LogFunc(("%s CTRL packet from guest driver incomplete. Skipping ctrl cmd\n", pThis->szInst));
+        LogFunc(("[%s] CTRL packet from guest driver incomplete. Skipping ctrl cmd\n", pThis->szInst));
         return;
     }
     else if (pVirtqBuf->cbPhysReturn < sizeof(VIRTIONET_CTRL_HDR_T_ACK))
     {
-        LogFunc(("%s Guest driver didn't allocate memory to receive ctrl pkt ACK. Skipping ctrl cmd\n", pThis->szInst));
+        LogFunc(("[%s] Guest driver didn't allocate memory to receive ctrl pkt ACK. Skipping ctrl cmd\n", pThis->szInst));
         return;
     }
@@ -2095,5 +2118,5 @@
                          RT_MIN(pVirtqBuf->cbPhysSend, sizeof(VIRTIONET_CTRL_HDR_T)));
 
-    Log7Func(("%s CTRL COMMAND: class=%d command=%d\n", pThis->szInst, pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd));
+    Log7Func(("[%s] CTRL COMMAND: class=%d command=%d\n", pThis->szInst, pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd));
 
     uint8_t uAck;
@@ -2122,9 +2145,9 @@
             if (pCtrlPktHdr->uCmd != VIRTIONET_CTRL_ANNOUNCE_ACK)
             {
-                LogFunc(("%s Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE. Unrecognized uCmd\n", pThis->szInst));
+                LogFunc(("[%s] Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE. Unrecognized uCmd\n", pThis->szInst));
                 break;
             }
             pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_ANNOUNCE;
-            Log7Func(("%s Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst));
+            Log7Func(("[%s] Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst));
             break;
         default:
@@ -2171,7 +2194,8 @@
 }
 
-static int virtioNetR3ReadHeader(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame)
-{
-    int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pPktHdr, sizeof(*pPktHdr));
+static int virtioNetR3ReadHeader(PVIRTIOCORE pVirtio, PVIRTIONET pThis, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame)
+{
+    size_t cbPktHdr = virtioNetCalcPktHdrSize(pVirtio, pThis);
+    int rc = virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys, pPktHdr, cbPktHdr);
     if (RT_FAILURE(rc))
         return rc;
@@ -2273,5 +2297,5 @@
 }
 
-static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
+static int virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
                                          PVIRTIONETVIRTQ pTxVirtq, bool fOnWorkerThread)
 {
@@ -2282,13 +2306,13 @@
     if (!pThis->fVirtioReady)
     {
-        LogFunc(("%s Ignoring Tx requests. VirtIO not ready (status=0x%x).\n",
+        LogFunc(("%s Ignoring Tx requests. VirtIO not ready (status=0x%x)\n",
                 pThis->szInst, pThis->virtioNetConfig.uStatus));
-        return;
+        return VERR_IGNORED;
     }
 
     if (!pThis->fCableConnected)
     {
-        Log(("%s Ignoring transmit requests while cable is disconnected.\n", pThis->szInst));
-        return;
+        Log(("[%s] Ignoring transmit requests while cable is disconnected.\n", pThis->szInst));
+        return VERR_IGNORED;
     }
 
@@ -2299,5 +2323,5 @@
      */
     if (!ASMAtomicCmpXchgU32(&pThis->uIsTransmitting, 1, 0))
-        return;
+        return VERR_IGNORED;
 
 
@@ -2311,5 +2335,5 @@
         {
             ASMAtomicWriteU32(&pThis->uIsTransmitting, 0);
-            return;
+            return VERR_TRY_AGAIN;
         }
     }
@@ -2318,5 +2342,5 @@
     if (!cPkts)
     {
-        LogFunc(("%s No packets to send found on %s\n", pThis->szInst, pTxVirtq->szName));
+        LogFunc(("[%s] No packets to send found on %s\n", pThis->szInst, pTxVirtq->szName));
 
         if (pDrv)
@@ -2324,7 +2348,7 @@
 
         ASMAtomicWriteU32(&pThis->uIsTransmitting, 0);
-        return;
-    }
-    LogFunc(("%s About to transmit %d pending packet%c\n", pThis->szInst, cPkts, cPkts == 1 ? ' ' : 's'));
+        return VERR_MISSING;
+    }
+    LogFunc(("[%s] About to transmit %d pending packet%c\n", pThis->szInst, cPkts, cPkts == 1 ? ' ' : 's'));
 
     virtioNetR3SetWriteLed(pThisCC, true);
@@ -2334,14 +2358,19 @@
     while ((rc = virtioCoreR3VirtqAvailBufPeek(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx, &pVirtqBuf)) == VINF_SUCCESS)
     {
-        Log10Func(("%s fetched descriptor chain from %s\n", pThis->szInst, pTxVirtq->szName));
+        Log10Func(("[%s] fetched descriptor chain from %s\n", pThis->szInst, pTxVirtq->szName));
 
         PVIRTIOSGBUF pSgPhysSend = pVirtqBuf->pSgPhysSend;
         PVIRTIOSGSEG paSegsFromGuest = pSgPhysSend->paSegs;
         uint32_t cSegsFromGuest = pSgPhysSend->cSegs;
-
-        VIRTIONETPKTHDR PktHdr;
         size_t uSize = 0;
 
-        Assert(paSegsFromGuest[0].cbSeg >= sizeof(PktHdr));
+        size_t cbPktHdr = virtioNetCalcPktHdrSize(pVirtio, pThis);
+
+        AssertMsgReturn(paSegsFromGuest[0].cbSeg >= cbPktHdr,
+                        ("Desc chain's first seg has insufficient space for pkt header!\n"),
+                        VERR_INTERNAL_ERROR);
+
+        PVIRTIONETPKTHDR pPktHdr = (PVIRTIONETPKTHDR)RTMemAllocZ(cbPktHdr);
+        AssertMsgReturn(pPktHdr, ("Out of Memory\n"), VERR_NO_MEMORY);
 
         /* Compute total frame size. */
@@ -2349,5 +2378,5 @@
             uSize +=  paSegsFromGuest[i].cbSeg;
 
-        Log5Func(("%s complete frame is %u bytes.\n", pThis->szInst, uSize));
+        Log5Func(("[%s] complete frame is %u bytes.\n", pThis->szInst, uSize));
         Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE);
 
@@ -2360,11 +2389,11 @@
             uint64_t uOffset;
 
-            uSize -= sizeof(PktHdr);
-            rc = virtioNetR3ReadHeader(pDevIns, paSegsFromGuest[0].GCPhys, &PktHdr, uSize);
+            uSize -= cbPktHdr;
+            rc = virtioNetR3ReadHeader(pVirtio, pThis, pDevIns, paSegsFromGuest[0].GCPhys, pPktHdr, uSize);
             if (RT_FAILURE(rc))
-                return;
-            virtioCoreGCPhysChainAdvance(pSgPhysSend, sizeof(PktHdr));
-
-            PDMNETWORKGSO  Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr);
+                return rc;
+            virtioCoreGCPhysChainAdvance(pSgPhysSend, cbPktHdr);
+
+            PDMNETWORKGSO  Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, pPktHdr);
 
             PPDMSCATTERGATHER pSgBufToPdmLeafDevice;
@@ -2386,5 +2415,5 @@
                     uint64_t srcSgCur   = (uint64_t)pSgPhysSend->GCPhysCur;
                     cbCopied = RT_MIN((uint64_t)cbRemain, srcSgLen - (srcSgCur - srcSgStart));
-                    PDMDevHlpPCIPhysRead(pDevIns,
+                    virtioCoreGCPhysRead(pVirtio, pDevIns,
                                          (RTGCPHYS)pSgPhysSend->GCPhysCur,
                                          ((uint8_t *)pSgBufToPdmLeafDevice->aSegs[0].pvSeg) + uOffset, cbCopied);
@@ -2398,8 +2427,8 @@
                      cbTotal, pVirtqBuf->cbPhysSend, pVirtqBuf->cbPhysSend - cbTotal));
 
-                rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, &PktHdr);
+                rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, pPktHdr);
                 if (RT_FAILURE(rc))
                 {
-                    LogFunc(("%s Failed to transmit frame, rc = %Rrc\n", pThis->szInst, rc));
+                    LogFunc(("[%s] Failed to transmit frame, rc = %Rrc\n", pThis->szInst, rc));
                     STAM_PROFILE_STOP(&pThis->StatTransmitSend, a);
                     STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
@@ -2436,4 +2465,5 @@
 
     ASMAtomicWriteU32(&pThis->uIsTransmitting, 0);
+    return VINF_SUCCESS;
 }
 
@@ -2450,5 +2480,5 @@
     STAM_COUNTER_INC(&pThis->StatTransmitByNetwork);
 
-    virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/);
+    (void)virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/);
 }
 
@@ -2466,5 +2496,5 @@
     virtioNetWakeupRxBufWaiter(pDevIns);
 
-    LogFunc(("%s Link is up\n", pThis->szInst));
+    LogFunc(("[%s] Link is up\n", pThis->szInst));
 
     if (pThisCC->pDrv)
@@ -2496,5 +2526,5 @@
         AssertRC(rc);
 
-        LogFunc(("%s Link is down temporarily\n", pThis->szInst));
+        LogFunc(("[%s] Link is down temporarily\n", pThis->szInst));
     }
 }
@@ -2513,5 +2543,5 @@
     if (LogIs7Enabled())
     {
-        LogFunc(("%s", pThis->szInst));
+        LogFunc(("[%s]", pThis->szInst));
         switch(enmState)
         {
@@ -2548,5 +2578,5 @@
         if (fRequestedLinkStateIsUp)
         {
-            Log(("%s Link is up\n", pThis->szInst));
+            Log(("[%s] Link is up\n", pThis->szInst));
             pThis->fCableConnected = true;
             SET_LINK_UP(pThis);
@@ -2557,5 +2587,5 @@
             /* The link was brought down explicitly, make sure it won't come up by timer.  */
             PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer);
-            Log(("%s Link is down\n", pThis->szInst));
+            Log(("[%s] Link is down\n", pThis->szInst));
             pThis->fCableConnected = false;
             SET_LINK_DOWN(pThis);
@@ -2580,5 +2610,5 @@
 static int virtioNetR3DestroyWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
 {
-    Log10Func(("%s\n", pThis->szInst));
+    Log10Func(("[%s]\n", pThis->szInst));
     int rc = VINF_SUCCESS;
     for (unsigned uIdxWorker = 0; uIdxWorker < pThis->cWorkers; uIdxWorker++)
@@ -2608,5 +2638,5 @@
                                             PVIRTIONETVIRTQ pVirtq)
 {
-    Log10Func(("%s\n", pThis->szInst));
+    Log10Func(("[%s]\n", pThis->szInst));
     RT_NOREF(pThis);
 
@@ -2637,11 +2667,17 @@
 static int virtioNetR3CreateWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
 {
-
-
-    Log10Func(("%s\n", pThis->szInst));
+    Log10Func(("[%s]\n", pThis->szInst));
+    int rc;
+
+
+    /* Create the Control Queue worker anyway whether or not it is feature-negotiated or utilized by the guest,
+     * as it's relatively low overhead resource-wise.  This is for two reasons: First, at the time of this comment
+     * queues and workers are configured pre-feature negotiation; secondly, legacy guest drivers are allowed to start
+     * using the device prior to feature negotiation, and we can only know we are dealing with a modern guest driver
+     * after feature negotiation. */
 
     PVIRTIONETVIRTQ pCtlVirtq = &pThis->aVirtqs[CTRLQIDX];
-    int rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis,
-                                              &pThis->aWorkers[CTRLQIDX], &pThisCC->aWorkers[CTRLQIDX], pCtlVirtq);
+    rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis,
+                                          &pThis->aWorkers[CTRLQIDX], &pThisCC->aWorkers[CTRLQIDX], pCtlVirtq);
     AssertRCReturn(rc, rc);
 
@@ -2654,5 +2690,5 @@
 
         rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, &pThis->aWorkers[TXQIDX(uVirtqPair)],
-                                                              &pThisCC->aWorkers[TXQIDX(uVirtqPair)], pTxVirtq);
+                                              &pThisCC->aWorkers[TXQIDX(uVirtqPair)], pTxVirtq);
         AssertRCReturn(rc, rc);
 
@@ -2665,4 +2701,5 @@
 
     pThis->cWorkers = pThis->cVirtqPairs + 1 /* One control virtq */;
+
     return rc;
 }
@@ -2686,5 +2723,5 @@
         return VINF_SUCCESS;
 
-    LogFunc(("%s worker thread idx=%d started for %s (virtq idx=%d)\n", pThis->szInst,  pWorker->uIdx, pVirtq->szName, pVirtq->uIdx));
+    LogFunc(("[%s] worker thread idx=%d started for %s (virtq idx=%d)\n", pThis->szInst,  pWorker->uIdx, pVirtq->szName, pVirtq->uIdx));
 
     /** @todo Race w/guest enabling/disabling guest notifications cyclically.
@@ -2703,5 +2740,5 @@
             if (!fNotificationSent)
             {
-                Log10Func(("%s %s worker sleeping...\n\n", pThis->szInst, pVirtq->szName));
+                Log10Func(("[%s] %s worker sleeping...\n\n", pThis->szInst, pVirtq->szName));
                 Assert(ASMAtomicReadBool(&pWorker->fSleeping));
 
@@ -2723,10 +2760,10 @@
          if (pVirtq->fCtlVirtq)
          {
-             Log10Func(("%s %s worker woken. Fetching desc chain\n", pThis->szInst, pVirtq->szName));
+             Log10Func(("[%s] %s worker woken. Fetching desc chain\n", pThis->szInst, pVirtq->szName));
              PVIRTQBUF pVirtqBuf = NULL;
              int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pVirtq->uIdx, &pVirtqBuf, true);
              if (rc == VERR_NOT_AVAILABLE)
              {
-                Log10Func(("%s %s worker woken. Nothing found in queue/n", pThis->szInst, pVirtq->szName));
+                Log10Func(("[%s] %s worker woken. Nothing found in queue/n", pThis->szInst, pVirtq->szName));
                 continue;
              }
@@ -2736,5 +2773,5 @@
          else /* Must be Tx queue */
          {
-             Log10Func(("%s %s worker woken. Virtq has data to transmit\n",  pThis->szInst, pVirtq->szName));
+             Log10Func(("[%s] %s worker woken. Virtq has data to transmit\n",  pThis->szInst, pVirtq->szName));
              virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */);
          }
@@ -2746,5 +2783,5 @@
           */
     }
-    Log10(("%s %s worker thread exiting\n", pThis->szInst, pVirtq->szName));
+    Log10(("[%s] %s worker thread exiting\n", pThis->szInst, pVirtq->szName));
     return VINF_SUCCESS;
 }
@@ -2753,5 +2790,5 @@
  * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged}
  */
-static DECLCALLBACK(void) virtioNetR3StatusChanged(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady)
+static DECLCALLBACK(void) virtioNetR3StatusChg(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady)
 {
     PVIRTIONET     pThis     = RT_FROM_MEMBER(pVirtio,  VIRTIONET, Virtio);
@@ -2762,6 +2799,7 @@
     if (fVirtioReady)
     {
-        LogFunc(("%s VirtIO ready\n-----------------------------------------------------------------------------------------\n",
-                 pThis->szInst));
+        Log(("-----------------------------------------------------------------------------------------\n"));
+        Log(("%-23s: %s *** VirtIO Ready ***\n-----------------------------------------------------------------------------------------\n",
+                 __FUNCTION__, pThis->szInst));
 
         pThis->fNegotiatedFeatures = virtioCoreGetNegotiatedFeatures(pVirtio);
@@ -2776,5 +2814,5 @@
         pThis->fResetting = false;
 
-        for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
+        for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
         {
             PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr];
@@ -2794,8 +2832,8 @@
     else
     {
-        LogFunc(("%s VirtIO is resetting\n", pThis->szInst));
+        Log(("%-23s: %s VirtIO is resetting\n", __FUNCTION__, pThis->szInst));
 
         pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0;
-        Log7Func(("%s Link is %s\n", pThis->szInst, pThis->fCableConnected ? "up" : "down"));
+        Log7(("%-23s: %s Link is %s\n", __FUNCTION__, pThis->szInst, pThis->fCableConnected ? "up" : "down"));
 
         pThis->fPromiscuous         = true;
@@ -2815,5 +2853,5 @@
         pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, true);
 
-        for (uint16_t uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
+        for (uint16_t uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
             pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore = false;
     }
@@ -2834,12 +2872,9 @@
     PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
 
-    Log7Func(("%s\n", pThis->szInst));
+    Log7Func(("[%s]\n", pThis->szInst));
+    RT_NOREF(pThis);
+
     AssertLogRelReturnVoid(iLUN == 0);
 
-    RT_NOREF(pThis);
-
-    /*
-     * Zero important members.
-     */
     pThisCC->pDrvBase = NULL;
     pThisCC->pDrv     = NULL;
@@ -2858,5 +2893,5 @@
     RT_NOREF(fFlags);
 
-    Log7Func(("%s", pThis->szInst));
+    Log7Func(("[%s]", pThis->szInst));
 
     AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
@@ -2873,5 +2908,5 @@
     else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
              || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
-                    Log(("%s No attached driver!\n", pThis->szInst));
+                    Log(("[%s] No attached driver!\n", pThis->szInst));
 
     return rc;
@@ -2897,5 +2932,4 @@
 {
     PVIRTIONETR3 pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, IBase);
-LogFunc(("pInterface=%p %s\n", pInterface, pszIID));
     PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN,   &pThisCC->INetworkDown);
     PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig);
@@ -2915,5 +2949,5 @@
     PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
 
-    Log(("%s Destroying instance\n", pThis->szInst));
+    Log(("[%s] Destroying instance\n", pThis->szInst));
 
     if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT)
@@ -2945,12 +2979,7 @@
      */
     Log7Func(("PDM device instance: %d\n", iInstance));
-
-    RTStrPrintf(pThis->szInst, sizeof(pThis->szInst), "VNET%d", iInstance);
-
-    /** @todo Remove next line (temporary hack used for less logging clutter for single-instance debugging) */
-    *pThis->szInst = '\0';
+    RTStrPrintf(pThis->szInst, sizeof(pThis->szInst), "virtio-net #%d", iInstance);
 
     pThisCC->pDevIns     = pDevIns;
-
     pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface;
     pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed;
@@ -2997,9 +3026,12 @@
                 pThis->szInst, pThis->cMsLinkUpDelay / 1000));
 
-    Log(("%s Link up delay is set to %u seconds\n", pThis->szInst, pThis->cMsLinkUpDelay / 1000));
+    Log(("[%s] Link up delay is set to %u seconds\n", pThis->szInst, pThis->cMsLinkUpDelay / 1000));
 
     /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */
     memcpy(pThis->virtioNetConfig.uMacAddress.au8, pThis->macConfigured.au8, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */
 
+    Log(("Using MAC address for %s: %2x:%2x:%2x:%2x:%2x:%2x\n", pThis->szInst,
+            pThis->macConfigured.au8[0], pThis->macConfigured.au8[1], pThis->macConfigured.au8[2],
+            pThis->macConfigured.au8[3], pThis->macConfigured.au8[4], pThis->macConfigured.au8[5]));
 
     LogFunc(("RC=%RTbool R0=%RTbool\n", pDevIns->fRCEnabled, pDevIns->fR0Enabled));
@@ -3015,5 +3047,5 @@
 
     pThisCC->Virtio.pfnVirtqNotified        = virtioNetVirtqNotified;
-    pThisCC->Virtio.pfnStatusChanged        = virtioNetR3StatusChanged;
+    pThisCC->Virtio.pfnStatusChanged        = virtioNetR3StatusChg;
     pThisCC->Virtio.pfnDevCapRead           = virtioNetR3DevCapRead;
     pThisCC->Virtio.pfnDevCapWrite          = virtioNetR3DevCapWrite;
@@ -3033,4 +3065,5 @@
         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create event semaphore"));
 
+
     /* Initialize VirtIO core. (pfnStatusChanged callback when both host VirtIO core & guest driver are ready) */
     rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInst,
@@ -3044,19 +3077,21 @@
         return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated."));
 
+
+    /*
+     * Initialize queues.  Due to this being a transitional device (e.g. accommodating both modern
+     * and legacy drivers), the control queue must be created whether or not the VIRTIO_NET_F_CTRL_VQ
+     * is negotiated, because legacy drivers are not bound to begin configuration and I/O until
+     * feature negotiation is complete.  In the final analysis, there may be no good reason to
+     * enforce VIRTIO_NET_F_CTRL_VQ as a prerequisite to handling guest control queue transactions,
+     * but merely to log violations (e.g. control transactions without feature explicitly enabled),
+     * once, thus not being strict with regard to misbehaving modern drivers.
+     */
+
     pThis->cVirtqPairs = 1;  /* default, VirtIO 1.0, 5.1.6.5.5 */
-
-    pThis->cVirtVirtqs += pThis->cVirtqPairs * 2 + 1;
-
-    /* Create Link Up Timer */
-    rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, virtioNetR3LinkUpTimer, NULL,
-                              TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
-                              "VirtioNet Link Up", &pThisCC->hLinkUpTimer);
-
-    /*
-     * Initialize queues.
-     */
+    pThis->cVirtqs += pThis->cVirtqPairs * 2 + 1;
+    pThis->aVirtqs[CTRLQIDX].fCtlVirtq = true;
+
     virtioNetR3SetVirtqNames(pThis);
-    pThis->aVirtqs[CTRLQIDX].fCtlVirtq = true;
-    for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
+    for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
     {
         PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr];
@@ -3067,5 +3102,4 @@
         pWorkerR3->uIdx = uVirtqNbr;
     }
-
     /*
      * Create queue workers for life of instance. (I.e. they persist through VirtIO bounces)
@@ -3075,5 +3109,8 @@
         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create worker threads"));
 
-
+    /* Create Link Up Timer */
+    rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, virtioNetR3LinkUpTimer, NULL,
+                              TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
+                              "VirtioNet Link Up", &pThisCC->hLinkUpTimer);
     /*
      * Attach network driver instance
@@ -3088,6 +3125,5 @@
     else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
              || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
-                    Log(("%s No attached driver!\n", pThis->szInst));
-
+                    Log(("[%s] No attached driver!\n", pThis->szInst));
     /*
      * Status driver
@@ -3111,4 +3147,5 @@
      * The /Public/ bits are official and used by session info in the GUI.
      */
+# ifdef VBOX_WITH_STATISTICS
     PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
                            "Amount of data received",    "/Public/NetAdapter/%u/BytesReceived", uStatNo);
@@ -3124,5 +3161,4 @@
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTransmitGSO,         STAMTYPE_COUNTER, "Packets/Transmit-Gso",   STAMUNIT_COUNT,          "Number of sent GSO packets");
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTransmitCSum,        STAMTYPE_COUNTER, "Packets/Transmit-Csum",  STAMUNIT_COUNT,          "Number of completed TX checksums");
-# ifdef VBOX_WITH_STATISTICS
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatReceive,             STAMTYPE_PROFILE, "Receive/Total",          STAMUNIT_TICKS_PER_CALL, "Profiling receive");
     PDMDevHlpSTAMRegister(pDevIns, &pThis->StatReceiveStore,        STAMTYPE_PROFILE, "Receive/Store",          STAMUNIT_TICKS_PER_CALL, "Profiling receive storing");
Index: /trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
===================================================================
--- /trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp	(revision 91702)
+++ /trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp	(revision 91703)
@@ -358,5 +358,5 @@
 {
     R3PTRTYPE(PPDMTHREAD)           pThread;                    /**< pointer to worker thread's handle                 */
-    uint16_t                        auRedoDescs[VIRTQ_MAX_ENTRIES];/**< List of previously suspended reqs to re-submit    */
+    uint16_t                        auRedoDescs[VIRTQ_SIZE];/**< List of previously suspended reqs to re-submit    */
     uint16_t                        cRedoDescs;                 /**< Number of redo desc chain head desc idxes in list */
 } VIRTIOSCSIWORKERR3;
@@ -457,11 +457,11 @@
     uint32_t                        fHasT10pi;
 
-    /** True if VIRTIO_SCSI_F_T10_PI was negotiated */
+    /** True if VIRTIO_SCSI_F_HOTPLUG was negotiated */
     uint32_t                        fHasHotplug;
 
-    /** True if VIRTIO_SCSI_F_T10_PI was negotiated */
+    /** True if VIRTIO_SCSI_F_INOUT was negotiated */
     uint32_t                        fHasInOutBufs;
 
-    /** True if VIRTIO_SCSI_F_T10_PI was negotiated */
+    /** True if VIRTIO_SCSI_F_CHANGE was negotiated */
     uint32_t                        fHasLunChange;
 
@@ -559,8 +559,8 @@
     uint16_t                       uVirtqNbr;                   /**< Index of queue this request arrived on            */
     PVIRTQBUF                      pVirtqBuf;                   /**< Prepared desc chain pulled from virtq avail ring  */
-    size_t                         cbDataIn;                    /**< size of dataout buffer                            */
+    size_t                         cbDataIn;                    /**< size of datain buffer                             */
     size_t                         cbDataOut;                   /**< size of dataout buffer                            */
     uint16_t                       uDataInOff;                  /**< Fixed size of respHdr + sense (precede datain)    */
-    uint16_t                       uDataOutOff;                 /**< Fixed size of respHdr + sense (precede datain)    */
+    uint16_t                       uDataOutOff;                 /**< Fixed size of reqhdr + cdb (precede dataout)      */
     uint32_t                       cbSenseAlloc;                /**< Size of sense buffer                              */
     size_t                         cbSenseLen;                  /**< Receives \# bytes written into sense buffer       */
@@ -828,5 +828,5 @@
     RTSGSEG aReqSegs[2];
 
-    /* Segment #1: Request header*/
+    /* Segment #1: Response header*/
     aReqSegs[0].pvSeg = pRespHdr;
     aReqSegs[0].cbSeg = sizeof(*pRespHdr);
@@ -1164,5 +1164,5 @@
      */
     size_t const cbReqHdr = sizeof(REQ_CMD_HDR_T) + cbCdb;
-    AssertReturn(pVirtqBuf->cbPhysSend >= cbReqHdr, VERR_INVALID_PARAMETER);
+    AssertReturn(pVirtqBuf && pVirtqBuf->cbPhysSend >= cbReqHdr, VERR_INVALID_PARAMETER);
 
     AssertCompile(VIRTIOSCSI_CDB_SIZE_MAX < 4096);
@@ -1714,5 +1714,5 @@
         /*
          * BIOS may change these values. When the OS comes up, and KVM driver accessed
-         * through the Windows, assumes they are the default size. So as per the VirtIO 1.0 spec,
+         * through Windows, it assumes they are the default size. So as per the VirtIO 1.0 spec,
          * 5.6.4, these device configuration values must be set to default upon device reset.
          */
@@ -1958,8 +1958,8 @@
         rc = pHlp->pfnSSMGetU16(pSSM, &cReqsRedo);
         AssertRCReturn(rc, rc);
-        AssertReturn(cReqsRedo < VIRTQ_MAX_ENTRIES,
+        AssertReturn(cReqsRedo < VIRTQ_SIZE,
                      pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
                                               N_("Bad count of I/O transactions to re-do in saved state (%#x, max %#x - 1)"),
-                                              cReqsRedo, VIRTQ_MAX_ENTRIES));
+                                              cReqsRedo, VIRTQ_SIZE));
 
         for (uint16_t uVirtqNbr = VIRTQ_REQ_BASE; uVirtqNbr < VIRTIOSCSI_VIRTQ_CNT; uVirtqNbr++)
@@ -1982,12 +1982,12 @@
             rc = pHlp->pfnSSMGetU16(pSSM, &idxHead);
             AssertRCReturn(rc, rc);
-            AssertReturn(idxHead < VIRTQ_MAX_ENTRIES,
+            AssertReturn(idxHead < VIRTQ_SIZE,
                          pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
                                                   N_("Bad queue element index for re-do in saved state (%#x, max %#x)"),
-                                                  idxHead, VIRTQ_MAX_ENTRIES - 1));
+                                                  idxHead, VIRTQ_SIZE - 1));
 
             PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[uVirtqNbr];
             pWorkerR3->auRedoDescs[pWorkerR3->cRedoDescs++] = idxHead;
-            pWorkerR3->cRedoDescs %= VIRTQ_MAX_ENTRIES;
+            pWorkerR3->cRedoDescs %= VIRTQ_SIZE;
         }
     }
Index: /trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp
===================================================================
--- /trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp	(revision 91702)
+++ /trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp	(revision 91703)
@@ -45,7 +45,11 @@
 #define VIRTQNAME(a_pVirtio, a_uVirtq)      ((a_pVirtio)->aVirtqueues[(a_uVirtq)].szName)
 
+
+#define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq) \
+            (virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq) == 0)
+
+
 #define IS_DRIVER_OK(a_pVirtio)             ((a_pVirtio)->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
-#define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq) \
-            (virtioCoreVirtqAvailBufCount_inline(pDevIns, pVirtio, pVirtq) == 0)
+#define WAS_DRIVER_OK(a_pVirtio)            ((a_pVirtio)->fPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
 
 /**
@@ -149,10 +153,10 @@
                                 uint32_t idxDesc, PVIRTQ_DESC_T pDesc)
 {
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    uint16_t const cVirtqItems = RT_MAX(pVirtq->uSize, 1); /* Make sure to avoid div-by-zero. */
-    PDMDevHlpPCIPhysRead(pDevIns,
-                      pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
-                      pDesc, sizeof(VIRTQ_DESC_T));
+    AssertMsg(IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */
+
+        virtioCoreGCPhysRead(pVirtio, pDevIns,
+                          pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
+                          pDesc, sizeof(VIRTQ_DESC_T));
 }
 #endif
@@ -165,8 +169,8 @@
 {
     uint16_t uDescIdx;
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    uint16_t const cVirtqItems = RT_MAX(pVirtq->uSize, 1); /* Make sure to avoid div-by-zero. */
-    PDMDevHlpPCIPhysRead(pDevIns,
+
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */
+    virtioCoreGCPhysRead(pVirtio, pDevIns,
                          pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % cVirtqItems]),
                          &uDescIdx, sizeof(uDescIdx));
@@ -178,8 +182,7 @@
     uint16_t uUsedEventIdx;
     /* VirtIO 1.0 uUsedEventIdx (used_event) immediately follows ring */
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    PDMDevHlpPCIPhysRead(pDevIns,
-                         pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uSize]),
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    virtioCoreGCPhysRead(pVirtio, pDevIns,
+                         pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uQueueSize]),
                          &uUsedEventIdx, sizeof(uUsedEventIdx));
     return uUsedEventIdx;
@@ -190,7 +193,6 @@
 {
     uint16_t uIdx = 0;
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    PDMDevHlpPCIPhysRead(pDevIns,
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    virtioCoreGCPhysRead(pVirtio, pDevIns,
                          pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
                          &uIdx, sizeof(uIdx));
@@ -201,9 +203,9 @@
 {
     uint16_t fFlags = 0;
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    PDMDevHlpPCIPhysRead(pDevIns,
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    virtioCoreGCPhysRead(pVirtio, pDevIns,
                          pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
                          &fFlags, sizeof(fFlags));
+
     return fFlags;
 }
@@ -220,8 +222,7 @@
 {
     VIRTQ_USED_ELEM_T elem = { uDescIdx,  uLen };
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    uint16_t const cVirtqItems = RT_MAX(pVirtq->uSize, 1); /* Make sure to avoid div-by-zero. */
-    PDMDevHlpPCIPhysWrite(pDevIns,
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */
+    virtioCoreGCPhysWrite(pVirtio, pDevIns,
                           pVirtq->GCPhysVirtqUsed
                         + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[usedIdx % cVirtqItems]),
@@ -231,8 +232,7 @@
 DECLINLINE(void) virtioWriteUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq, uint16_t fFlags)
 {
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
-    PDMDevHlpPCIPhysWrite(pDevIns,
+    virtioCoreGCPhysWrite(pVirtio, pDevIns,
                           pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
                           &fFlags, sizeof(fFlags));
@@ -242,7 +242,7 @@
 DECLINLINE(void) virtioWriteUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq, uint16_t uIdx)
 {
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    PDMDevHlpPCIPhysWrite(pDevIns,
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
+    virtioCoreGCPhysWrite(pVirtio, pDevIns,
                           pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
                           &uIdx, sizeof(uIdx));
@@ -254,7 +254,6 @@
 {
     uint16_t uIdx = 0;
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    PDMDevHlpPCIPhysRead(pDevIns,
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    virtioCoreGCPhysRead(pVirtio, pDevIns,
                          pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
                          &uIdx, sizeof(uIdx));
@@ -265,7 +264,6 @@
 {
     uint16_t fFlags = 0;
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    PDMDevHlpPCIPhysRead(pDevIns,
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    virtioCoreGCPhysRead(pVirtio, pDevIns,
                          pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
                          &fFlags, sizeof(fFlags));
@@ -276,14 +274,13 @@
 {
     /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */
-    AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
-    RT_NOREF(pVirtio);
-    PDMDevHlpPCIPhysWrite(pDevIns,
+    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
+    virtioCoreGCPhysWrite(pVirtio, pDevIns,
                           pVirtq->GCPhysVirtqUsed
-                        + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtq->uSize]),
+                        + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtq->uQueueSize]),
                           &uAvailEventIdx, sizeof(uAvailEventIdx));
 }
 #endif
 
-DECLINLINE(uint16_t) virtioCoreVirtqAvailBufCount_inline(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq)
+DECLINLINE(uint16_t) virtioCoreVirtqAvailCnt(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq)
 {
     uint16_t uIdxActual = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtq);
@@ -292,11 +289,10 @@
 
     if (uIdxActual < uIdxShadow)
-        uIdxDelta = (uIdxActual + VIRTQ_MAX_ENTRIES) - uIdxShadow;
+        uIdxDelta = (uIdxActual + VIRTQ_SIZE) - uIdxShadow;
     else
         uIdxDelta = uIdxActual - uIdxShadow;
 
-    LogFunc(("%s has %u %s (idx=%u shadow=%u)\n",
-        pVirtq->szName, uIdxDelta, uIdxDelta == 1 ? "entry" : "entries",
-        uIdxActual, uIdxShadow));
+    LogFunc(("%s, %u %s\n",
+        pVirtq->szName, uIdxDelta, uIdxDelta == 1 ? "entry" : "entries"));
 
     return uIdxDelta;
@@ -316,11 +312,17 @@
     AssertMsgReturn(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues), ("uVirtq out of range"), 0);
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
-    if (!IS_DRIVER_OK(pVirtio) || !pVirtq->uEnable)
-    {
-        LogRelFunc(("Driver not ready or queue not enabled\n"));
+
+    if (!IS_DRIVER_OK(pVirtio))
+    {
+        LogRelFunc(("Driver not ready\n"));
         return 0;
     }
-
-    return virtioCoreVirtqAvailBufCount_inline(pDevIns, pVirtio, pVirtq);
+    if (!pVirtio->fLegacyDriver && !pVirtq->uEnable)
+    {
+        LogRelFunc(("virtq: %d (%s) not enabled\n", uVirtq, VIRTQNAME(pVirtio, uVirtq)));
+        return 0;
+    }
+
+    return virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq);
 }
 
@@ -414,4 +416,5 @@
 void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle)
 {
+    PVIRTIOCORE pVirtio = PDMDEVINS_2_DATA(pDevIns, PVIRTIOCORE);
 #define ADJCURSOR(cb) pszOut += cb; cbRemain -= cb;
     size_t cbPrint = 0, cbRemain = ((cb / 16) + 1) * 80;
@@ -431,5 +434,5 @@
         {
            uint32_t idx = row * 16 + col;
-           PDMDevHlpPCIPhysRead(pDevIns, GCPhys + idx, &c, 1);
+           virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys + idx, &c, 1);
            if (idx >= cb)
                cbPrint = RTStrPrintf(pszOut, cbRemain, "-- %s", (col + 1) % 8 ? "" : "  ");
@@ -440,5 +443,5 @@
         for (uint16_t idx = row * 16; idx < row * 16 + 16; idx++)
         {
-           PDMDevHlpPCIPhysRead(pDevIns, GCPhys + idx, &c, 1);
+           virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys + idx, &c, 1);
            cbPrint = RTStrPrintf(pszOut, cbRemain, "%c", (idx >= cb) ? ' ' : (c >= 0x20 && c <= 0x7e ? c : '.'));
            ADJCURSOR(cbPrint);
@@ -455,4 +458,11 @@
 
 /** API function: See header file */
+int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio)
+{
+    Log12Func(("%s", pVirtio->fLegacyDriver ? "Legacy Guest Driver handling mode\n" : ""));
+    return pVirtio->fLegacyDriver;
+}
+
+/** API function: See header file */
 void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
                                 const void *pv, uint32_t cb, uint32_t uOffset, int fWrite,
@@ -553,5 +563,5 @@
 int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t uVirtq, const char *pcszName)
 {
-    LogFunc(("%s\n", pcszName));
+    LogFunc(("Attaching %s to VirtIO core\n", pcszName));
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
     pVirtq->uVirtq = uVirtq;
@@ -596,10 +606,9 @@
     bool fUsedNoNotify       = virtioReadUsedRingFlags(pDevIns, pVirtio, pVirtq) & VIRTQ_USED_F_NO_NOTIFY;
 
-
     pHlp->pfnPrintf(pHlp, "       queue enabled: ........... %s\n", pVirtq->uEnable ? "true" : "false");
-    pHlp->pfnPrintf(pHlp, "       size: .................... %d\n", pVirtq->uSize);
+    pHlp->pfnPrintf(pHlp, "       size: .................... %d\n", pVirtq->uQueueSize);
     pHlp->pfnPrintf(pHlp, "       notify offset: ........... %d\n", pVirtq->uNotifyOffset);
     if (pVirtio->fMsiSupport)
-        pHlp->pfnPrintf(pHlp, "       MSIX vector: ....... %4.4x\n", pVirtq->uMsix);
+        pHlp->pfnPrintf(pHlp, "       MSIX vector: ....... %4.4x\n", pVirtq->uMsixVector);
     pHlp->pfnPrintf(pHlp, "\n");
     pHlp->pfnPrintf(pHlp, "       avail ring (%d entries):\n", uAvailIdx - uAvailIdxShadow);
@@ -684,5 +693,5 @@
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
 
-    if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
+    if (IS_DRIVER_OK(pVirtio))
     {
         uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, pVirtq);
@@ -702,7 +711,8 @@
     LogFunc(("\n"));
     pVirtio->fDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
-    if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
-    {
-        pVirtio->fGenUpdatePending = true;
+    if (IS_DRIVER_OK(pVirtio))
+    {
+        if (!pVirtio->fLegacyDriver)
+            pVirtio->fGenUpdatePending = true;
         virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
     }
@@ -722,6 +732,7 @@
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
 
-    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
-                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
+    if (!pVirtio->fLegacyDriver)
+        AssertMsgReturn((pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) && pVirtq->uEnable,
+            ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
 
     if (IS_VIRTQ_EMPTY(pVirtio->pDevInsR3, pVirtio, pVirtq))
@@ -747,10 +758,11 @@
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
 
-    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
-                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
+    if (!pVirtio->fLegacyDriver)
+        AssertMsgReturn((pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) && pVirtq->uEnable,
+            ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
 
     uint16_t uDescIdx = uHeadIdx;
 
-    Log6Func(("%s DESC CHAIN: (head) desc_idx=%u\n", pVirtio->aVirtqueues[uVirtq].szName, uHeadIdx));
+    Log6Func(("%s DESC CHAIN: (head idx = %u)\n", pVirtio->aVirtqueues[uVirtq].szName, uHeadIdx));
 
     /*
@@ -788,5 +800,5 @@
          * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
          */
-        if (cSegsIn + cSegsOut >= VIRTQ_MAX_ENTRIES)
+        if (cSegsIn + cSegsOut >= VIRTQ_SIZE)
         {
             static volatile uint32_t s_cMessages  = 0;
@@ -807,5 +819,5 @@
         if (desc.fFlags & VIRTQ_DESC_F_WRITE)
         {
-            Log6Func(("%s IN  desc_idx=%u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
+            Log6Func(("%s IN  idx=%u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
             cbIn += desc.cb;
             pSeg = &paSegsIn[cSegsIn++];
@@ -893,6 +905,6 @@
     AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
 
-    Log6Func(("Copying client data to %s, desc chain (head desc_idx %d)\n",
-              VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
+    Log6Func(("    Copying device data to %s (%s guest), desc chain idx %d\n",
+              VIRTQNAME(pVirtio, uVirtq), pVirtio->fLegacyDriver ? "legacy" : "modern", virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
 
     /* Copy s/g buf (virtual memory) to guest phys mem (IN direction). */
@@ -910,5 +922,5 @@
             cbCopy = RT_MIN(pSgVirtReturn->cbSegLeft,  pSgPhysReturn->cbSegLeft);
             Assert(cbCopy > 0);
-            PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->GCPhysCur, pSgVirtReturn->pvSegCur, cbCopy);
+            virtioCoreGCPhysWrite(pVirtio, pDevIns, (RTGCPHYS)pSgPhysReturn->GCPhysCur, pSgVirtReturn->pvSegCur, cbCopy);
             RTSgBufAdvance(pSgVirtReturn, cbCopy);
             virtioCoreGCPhysChainAdvance(pSgPhysReturn, cbCopy);
@@ -922,5 +934,5 @@
     }
 
-    /* If this write-ahead crosses threshold where the driver wants to get an event flag it */
+    /* If this write-ahead crosses threshold where the driver wants to get an event, flag it */
     if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
         if (pVirtq->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq))
@@ -933,9 +945,8 @@
 
     if (pSgVirtReturn)
-        Log6Func((".... Copied %zu bytes in %d segs to %u byte buffer, residual=%zu\n",
-                  cbTotal - cbRemain, pSgVirtReturn->cSegs, pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal));
-
-    Log6Func(("Write ahead used_idx=%u, %s used_idx=%u\n",
-              pVirtq->uUsedIdxShadow, VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
+        Log6Func(("     ... %d segs, %zu bytes, copied to %u byte buf. residual: %zu bytes\n",
+                  pSgVirtReturn->cSegs, cbTotal - cbRemain,  pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal));
+
+    Log6Func(("    %s used_idx=%u\n", VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
 
     return VINF_SUCCESS;
@@ -951,8 +962,9 @@
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
 
-    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
-                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
-
-    Log6Func(("Updating %s used_idx to %u\n", pVirtq->szName, pVirtq->uUsedIdxShadow));
+    if (!pVirtio->fLegacyDriver)
+        AssertMsgReturn((pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) && pVirtq->uEnable,
+            ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
+
+    Log6Func(("    %s ++used_idx=%u\n", pVirtq->szName, pVirtq->uUsedIdxShadow));
 
     virtioWriteUsedRingIdx(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow);
@@ -976,5 +988,4 @@
     PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
 
-
     /* See VirtIO 1.0, section 4.1.5.2 It implies that uVirtq and uNotifyIdx should match.
      * Disregarding this notification may cause throughput to stop, however there's no way to know
@@ -990,5 +1001,5 @@
 
     Log6Func(("%s (desc chains: %u)\n", pVirtq->szName,
-        virtioCoreVirtqAvailBufCount_inline(pDevIns, pVirtio, pVirtq)));
+        virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq)));
 
     /* Inform client */
@@ -1027,5 +1038,5 @@
                    pVirtq->szName, (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq)));
 #endif
-            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsix);
+            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
             pVirtq->fUsedRingEvent = false;
             return;
@@ -1041,5 +1052,5 @@
         if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, pVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT))
         {
-            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsix);
+            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
             return;
         }
@@ -1056,5 +1067,5 @@
  * @param   uVec        MSI-X vector, if enabled
  */
-static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixtor)
+static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixVector)
 {
     if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
@@ -1069,6 +1080,6 @@
         PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
     }
-    else if (uMsixtor != VIRTIO_MSI_NO_VECTOR)
-        PDMDevHlpPCISetIrq(pDevIns, uMsixtor, 1);
+    else if (uMsixVector != VIRTIO_MSI_NO_VECTOR)
+        PDMDevHlpPCISetIrq(pDevIns, uMsixVector, 1);
     return VINF_SUCCESS;
 }
@@ -1079,10 +1090,10 @@
  * @param   pDevIns     The device instance.
  */
-static void virtioLowerInterrupt(PPDMDEVINS pDevIns, uint16_t uMsixtor)
+static void virtioLowerInterrupt(PPDMDEVINS pDevIns, uint16_t uMsixVector)
 {
     PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
     if (!pVirtio->fMsiSupport)
         PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
-    else if (uMsixtor != VIRTIO_MSI_NO_VECTOR)
+    else if (uMsixVector != VIRTIO_MSI_NO_VECTOR)
         PDMDevHlpPCISetIrq(pDevIns, pVirtio->uMsixConfig, PDM_IRQ_LEVEL_LOW);
 }
@@ -1094,21 +1105,22 @@
     PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
 
+    pVirtq->uQueueSize       = VIRTQ_SIZE;
+    pVirtq->uEnable          = false;
+    pVirtq->uNotifyOffset    = uVirtq;
+    pVirtq->fUsedRingEvent   = false;
     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->uMsixVector      = uVirtq + 2;
 
     if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */
-        pVirtq->uMsix = VIRTIO_MSI_NO_VECTOR;
-
-    virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtq->uMsix);
+        pVirtq->uMsixVector = VIRTIO_MSI_NO_VECTOR;
+
+    virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtq->uMsixVector);
 }
 
 static void virtioResetDevice(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio)
 {
-    Log2Func(("\n"));
+    LogFunc(("Resetting device VirtIO state\n"));
+    pVirtio->fLegacyDriver          = 1;   /* Assume this. Cleared if VIRTIO_F_VERSION_1 feature ack'd */
     pVirtio->uDeviceFeaturesSelect  = 0;
     pVirtio->uDriverFeaturesSelect  = 0;
@@ -1123,5 +1135,5 @@
         virtioLowerInterrupt(pDevIns, pVirtio->uMsixConfig);
         for (int i = 0; i < VIRTQ_MAX_COUNT; i++)
-            virtioLowerInterrupt(pDevIns, pVirtio->aVirtqueues[i].uMsix);
+            virtioLowerInterrupt(pDevIns, pVirtio->aVirtqueues[i].uMsixVector);
     }
 
@@ -1139,8 +1151,8 @@
 static void virtioGuestR3WasReset(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC)
 {
-    LogFunc(("Guest reset the device\n"));
+    Log(("%-23s: Guest reset the device\n", __FUNCTION__));
 
     /* Let the client know */
-    pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, 0);
+    pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, 0 /* fDriverOk */);
     virtioResetDevice(pDevIns, pVirtio);
 }
@@ -1210,4 +1222,6 @@
                 case 1:
                     memcpy((char *)&pVirtio->uDriverFeatures + sizeof(uint32_t), pv, cb);
+                    if (pVirtio->uDriverFeatures & VIRTIO_F_VERSION_1)
+                        pVirtio->fLegacyDriver = 0;
                     VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess + sizeof(uint32_t));
                     break;
@@ -1218,5 +1232,5 @@
             }
         }
-        /* Guest READ pCommonCfg->udriverFeatures */
+        else /* Guest READ pCommonCfg->udriverFeatures */
         {
             switch (pVirtio->uDriverFeaturesSelect)
@@ -1262,8 +1276,7 @@
                 char szOut[80] = { 0 };
                 virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut));
-                LogFunc(("Guest wrote fDeviceStatus ................ (%s)\n", szOut));
+                Log(("%-23s: Guest wrote fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut));
             }
-            bool const fStatusChanged =
-                (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) != (pVirtio->uPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
+            bool const fStatusChanged = IS_DRIVER_OK(pVirtio) != WAS_DRIVER_OK(pVirtio);
 
             if (fDeviceReset || fStatusChanged)
@@ -1272,5 +1285,5 @@
                 /* Since VirtIO status changes are cumbersome by nature, e.g. not a benchmark priority,
                  * handle the rest in R3 to facilitate logging or whatever dev-specific client needs to do */
-                Log6Func(("RING0 => RING3 (demote)\n"));
+                Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__));
                 return VINF_IOM_R3_MMIO_WRITE;
 #endif
@@ -1285,10 +1298,10 @@
 
             if (fStatusChanged)
-                pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
+                pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, IS_DRIVER_OK(pVirtio));
 #endif
             /*
              * Save the current status for the next write so we can see what changed.
              */
-            pVirtio->uPrevDeviceStatus = pVirtio->fDeviceStatus;
+            pVirtio->fPrevDeviceStatus = pVirtio->fDeviceStatus;
         }
         else /* Guest READ pCommonCfg->fDeviceStatus */
@@ -1329,6 +1342,6 @@
         VIRTIO_DEV_CONFIG_ACCESS_INDEXED( GCPhysVirtqUsed,   uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
     else
-    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uSize,                      VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
-        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uSize,             uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uQueueSize,                 VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
+        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uQueueSize,        uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
     else
     if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uEnable,                    VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
@@ -1338,6 +1351,6 @@
         VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uNotifyOffset,     uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
     else
-    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsix,                      VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
-        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsix,             uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixVector,                VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
+        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsixVector,       uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
     else
     {
@@ -1352,4 +1365,286 @@
     return rc;
 }
+
+/**
+ * @callback_method_impl{FNIOMIOPORTNEWIN)
+ *
+ * This I/O handler exists only to handle access from legacy drivers.
+ */
+
+static DECLCALLBACK(VBOXSTRICTRC) virtioLegacyIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
+{
+
+    PVIRTIOCORE   pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
+    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatRead), a);
+
+    RT_NOREF(pvUser);
+//    LogFunc((" Read from port offset=%RTiop cb=%#x\n",  offPort, cb));
+
+    void *pv = pu32; /* To use existing macros */
+    int fWrite = 0;  /* To use existing macros */
+
+    uint16_t uVirtq = pVirtio->uVirtqSelect;
+
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDeviceFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        uint32_t val = pVirtio->uDeviceFeatures & UINT32_C(0xffffffff);
+        memcpy(pu32, &val, cb);
+        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDeviceFeatures,   VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        uint32_t val = pVirtio->uDriverFeatures & 0xffffffff;
+        memcpy(pu32, &val, cb);
+        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fDeviceStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        *(uint8_t *)pu32 = pVirtio->fDeviceStatus;
+
+        if (LogIs7Enabled())
+        {
+            char szOut[80] = { 0 };
+            virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut));
+            Log(("%-23s: Guest read  fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut));
+        }
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        ASSERT_GUEST_MSG(cb == 1, ("%d\n", cb));
+        *(uint8_t *)pu32 = pVirtio->uISR;
+        pVirtio->uISR = 0;
+        virtioLowerInterrupt( pDevIns,  0);
+        Log((" ISR read and cleared\n"));
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uVirtqSelect,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS(         uVirtqSelect,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uVirtqPfn,                  VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        PVIRTQUEUE pVirtQueue = &pVirtio->aVirtqueues[uVirtq];
+        *pu32 = pVirtQueue->GCPhysVirtqDesc >> PAGE_SHIFT;
+        Log(("%-23s: Guest read  uVirtqPfn .................... %#x\n",   __FUNCTION__, *pu32));
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uQueueSize,                 VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uQueueSize,        uVirtq,  VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio->aVirtqueues);
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uQueueNotify,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS(         uQueueNotify,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
+#if LEGACY_MSIX_SUPPORTED
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixConfig,                VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS(         uMsixConfig,                VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixVector,                VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsixVector,       uVirtq,  VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio->aVirtqueues);
+#endif
+    else if (offPort >= sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T))
+    {
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
+#if IN_RING3
+        /* Access device-specific configuration */
+        PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
+        int rc = pVirtioCC->pfnDevCapRead(pDevIns, offPort - sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T), pv, cb);
+        return rc;
+#else
+        return VINF_IOM_R3_IOPORT_READ;
+#endif
+    }
+    else
+    {
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
+        Log2Func(("Bad guest read access to virtio_legacy_pci_common_cfg: offset=%#x, cb=%x\n",
+                   offPort, cb));
+        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
+                    "virtioLegacyIOPortIn: no valid port at offset offset=%RTiop cb=%#x\n", offPort, cb);
+        return rc;
+    }
+
+    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{ * @callback_method_impl{FNIOMIOPORTNEWOUT}
+ *
+ * This I/O Port interface exists only to handle access from legacy drivers.
+ */
+static DECLCALLBACK(VBOXSTRICTRC) virtioLegacyIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
+{
+    PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
+    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatWrite), a);
+    RT_NOREF(pvUser);
+
+    uint16_t uVirtq = pVirtio->uVirtqSelect;
+    uint32_t u32OnStack = u32;  /* allows us to use this impl's MMIO parsing macros */
+    void *pv = &u32OnStack; /* To use existing macros */
+    int fWrite = 1;         /* To use existing macros */
+
+//    LogFunc(("Write to port offset=%RTiop, cb=%#x, u32=%#x\n",  offPort, cb, u32));
+
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uVirtqSelect,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS(         uVirtqSelect,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
+    else
+#if LEGACY_MSIX_SUPPORTED
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixConfig,         VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS(         uMsixConfig,         VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixVector,         VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsixVector, uVirtq, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio->aVirtqueues);
+    else
+#endif
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDeviceFeatures,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        /* Check to see if guest acknowledged unsupported features */
+        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDeviceFeatures,          VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
+        LogFunc(("... WARNING: Guest attempted to write readonly virtio_pci_common_cfg.device_feature (ignoring)\n"));
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+        return VINF_SUCCESS;
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDriverFeatures,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        memcpy(&pVirtio->uDriverFeatures, pv, cb);
+        if ((pVirtio->uDriverFeatures & ~VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED) == 0)
+        {
+                Log(("Guest asked for features host does not support! (host=%x guest=%x)\n",
+                      VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED, pVirtio->uDriverFeatures));
+                pVirtio->uDriverFeatures &= VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED;
+        }
+        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures,          VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uQueueSize,             VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        VIRTIO_DEV_CONFIG_LOG_ACCESS(uQueueSize,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
+        LogFunc(("... WARNING: Guest attempted to write readonly device_feature (queue size) (ignoring)\n"));
+        return VINF_SUCCESS;
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fDeviceStatus,          VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        bool const fDriverInitiatedReset = (pVirtio->fDeviceStatus = (uint8_t)u32) == 0;
+        bool const fDriverStateImproved = IS_DRIVER_OK(pVirtio) && !WAS_DRIVER_OK(pVirtio);
+
+        if (LogIs7Enabled())
+        {
+            char szOut[80] = { 0 };
+            virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut));
+            Log(("%-23s: Guest wrote fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut));
+        }
+
+        if (fDriverStateImproved  || fDriverInitiatedReset)
+        {
+#ifdef IN_RING0
+            Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__));
+            STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+            return VINF_IOM_R3_IOPORT_WRITE;
+#endif
+        }
+
+#ifdef IN_RING3
+        PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
+        if (fDriverInitiatedReset)
+            virtioGuestR3WasReset(pDevIns, pVirtio, pVirtioCC);
+
+        else if (fDriverStateImproved)
+            pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, 1 /* fDriverOk */);
+
+#endif
+        pVirtio->fPrevDeviceStatus = pVirtio->fDeviceStatus;
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uVirtqPfn, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
+        uint64_t uVirtqPfn = (uint64_t)u32;
+
+        if (uVirtqPfn)
+        {
+            /* Transitional devices calculate ring physical addresses using rigid spec-defined formulae,
+             * instead of guest conveying respective address of each ring, as "modern" VirtIO drivers do,
+             * thus there is no virtq PFN or single base queue address stored in instance data for
+             * this transitional device, but rather it is derived, when read back, from GCPhysVirtqDesc */
+
+            pVirtq->GCPhysVirtqDesc  = uVirtqPfn * VIRTIO_PAGE_SIZE;
+            pVirtq->GCPhysVirtqAvail = pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * pVirtq->uQueueSize;
+            pVirtq->GCPhysVirtqUsed  =
+                RT_ALIGN(pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uQueueSize]), VIRTIO_PAGE_SIZE);
+        }
+        else
+        {
+            /* Don't set ring addresses for queue (to meaningless values), when guest resets the virtq's PFN */
+            pVirtq->GCPhysVirtqDesc  = 0;
+            pVirtq->GCPhysVirtqAvail = 0;
+            pVirtq->GCPhysVirtqUsed  = 0;
+        }
+        Log(("%-23s: Guest wrote uVirtqPfn .................... %#x:\n"
+             "%68s... %p -> GCPhysVirtqDesc\n%68s... %p -> GCPhysVirtqAvail\n%68s... %p -> GCPhysVirtqUsed\n",
+                __FUNCTION__, u32, " ", pVirtq->GCPhysVirtqDesc, " ", pVirtq->GCPhysVirtqAvail, " ", pVirtq->GCPhysVirtqUsed));
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uQueueNotify, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+#ifdef IN_RING3
+        ASSERT_GUEST_MSG(cb == 2, ("cb=%u\n", cb));
+        pVirtio->uQueueNotify =  u32 & 0xFFFF;
+        if (uVirtq < VIRTQ_MAX_COUNT)
+        {
+            RT_UNTRUSTED_VALIDATED_FENCE();
+
+            /* Need to check that queue is configured. Legacy spec didn't have a queue enabled flag */
+            if (pVirtio->aVirtqueues[pVirtio->uQueueNotify].GCPhysVirtqDesc)
+                    virtioCoreVirtqNotified(pDevIns, pVirtio, pVirtio->uQueueNotify, pVirtio->uQueueNotify /* uNotifyIdx */);
+            else
+                Log(("The queue (#%d) being notified has not been initialized.\n", pVirtio->uQueueNotify));
+        }
+        else
+            Log(("Invalid queue number (%d)\n", pVirtio->uQueueNotify));
+#else
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+        return VINF_IOM_R3_IOPORT_WRITE;
+#endif
+    }
+    else
+    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
+    {
+        VIRTIO_DEV_CONFIG_LOG_ACCESS( fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
+        LogFunc(("... WARNING: Guest attempted to write readonly device_feature (ISR status) (ignoring)\n"));
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+        return VINF_SUCCESS;
+    }
+    else if (offPort >= sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T))
+    {
+#if IN_RING3
+
+        /* Access device-specific configuration */
+        PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
+        return pVirtioCC->pfnDevCapWrite(pDevIns, offPort - sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T), pv, cb);
+#else
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+        return VINF_IOM_R3_IOPORT_WRITE;
+#endif
+    }
+    else
+    {
+        Log2Func(("Bad guest write access to virtio_legacy_pci_common_cfg: offset=%#x, cb=0x%x\n",
+                  offPort, cb));
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
+                    "virtioLegacyIOPortOut: no valid port at offset offset=%RTiop cb=0x%#x\n", offPort, cb);
+        return rc;
+    }
+
+    RT_NOREF(uVirtq);
+    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+    return VINF_SUCCESS;
+}
+
 
 /**
@@ -1368,4 +1663,6 @@
     AssertReturn(cb == 1 || cb == 2 || cb == 4, VERR_INVALID_PARAMETER);
     Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser);
+    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatRead), a);
+
 
     uint32_t uOffset;
@@ -1400,6 +1697,8 @@
 
         virtioLowerInterrupt(pDevIns, 0);
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
         return rcStrict;
 #else
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
         return VINF_IOM_R3_MMIO_READ;
 #endif
@@ -1415,10 +1714,13 @@
         pVirtio->uISR = 0; /* VirtIO spec requires reads of ISR to clear it */
         virtioLowerInterrupt(pDevIns, 0);
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
         return VINF_SUCCESS;
     }
 
-    ASSERT_GUEST_MSG_FAILED(("Bad read access to mapped capabilities region: off=%RGp cb=%u\n",
-                              off, cb));
-    return VINF_IOM_MMIO_UNUSED_00;
+    ASSERT_GUEST_MSG_FAILED(("Bad read access to mapped capabilities region: off=%RGp cb=%u\n", off, cb));
+    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
+    int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
+                "virtioMmioRead: Bad MMIO access to capabilities, offset=%RTiop cb=%08x\n", off, cb);
+    return rc;
 }
 
@@ -1435,8 +1737,8 @@
     PVIRTIOCORE   pVirtio   = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
     PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
-
     AssertReturn(cb == 1 || cb == 2 || cb == 4, VERR_INVALID_PARAMETER);
-
     Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser);
+    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatWrite), a);
+
     uint32_t uOffset;
     if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocDeviceCap))
@@ -1446,6 +1748,8 @@
          * Foreward this MMIO write access for client to deal with.
          */
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
         return pVirtioCC->pfnDevCapWrite(pDevIns, uOffset, pv, cb);
 #else
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
         return VINF_IOM_R3_MMIO_WRITE;
 #endif
@@ -1453,5 +1757,8 @@
 
     if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocCommonCfgCap))
+    {
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
         return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, true /* fWrite */, uOffset, cb, (void *)pv);
+    }
 
     if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocIsrCap) && cb == sizeof(uint8_t))
@@ -1462,4 +1769,5 @@
                   pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
                   RT_BOOL(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG)));
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
         return VINF_SUCCESS;
     }
@@ -1469,9 +1777,13 @@
     {
         virtioCoreVirtqNotified(pDevIns, pVirtio, uOffset / VIRTIO_NOTIFY_OFFSET_MULTIPLIER, *(uint16_t *)pv);
+        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
         return VINF_SUCCESS;
     }
 
     ASSERT_GUEST_MSG_FAILED(("Bad write access to mapped capabilities region: off=%RGp pv=%#p{%.*Rhxs} cb=%u\n", off, pv, cb, pv, cb));
-    return VINF_SUCCESS;
+    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
+    int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
+                "virtioMmioRead: Bad MMIO access to capabilities, offset=%RTiop cb=%08x\n", off, cb);
+    return rc;
 }
 
@@ -1494,4 +1806,5 @@
          * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
          * (the virtio_pci_cfg_cap capability), and access data items.
+         * This is used by BIOS to gain early boot access to the the storage device.
          */
         struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap;
@@ -1535,5 +1848,6 @@
         /* VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability
          * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
-         * (the virtio_pci_cfg_cap capability), and access data items. */
+         * (the virtio_pci_cfg_cap capability), and access data items.
+         * This is used by BIOS to gain early boot access to the the storage device.*/
 
         struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap;
@@ -1593,7 +1907,7 @@
         pHlp->pfnSSMPutGCPhys64( pSSM, pVirtq->GCPhysVirtqUsed);
         pHlp->pfnSSMPutU16(      pSSM, pVirtq->uNotifyOffset);
-        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uMsix);
+        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uMsixVector);
         pHlp->pfnSSMPutU16(      pSSM, pVirtq->uEnable);
-        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uSize);
+        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uQueueSize);
         pHlp->pfnSSMPutU16(      pSSM, pVirtq->uAvailIdxShadow);
         pHlp->pfnSSMPutU16(      pSSM, pVirtq->uUsedIdxShadow);
@@ -1653,7 +1967,7 @@
         pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqUsed);
         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uNotifyOffset);
-        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uMsix);
+        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uMsixVector);
         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uEnable);
-        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uSize);
+        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uQueueSize);
         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uAvailIdxShadow);
         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uUsedIdxShadow);
@@ -1695,5 +2009,5 @@
             for (int uVirtq = 0; uVirtq < VIRTQ_MAX_COUNT; uVirtq++)
             {
-                if (pVirtio->aVirtqueues[uVirtq].uEnable)
+                if (!pVirtio->fLegacyDriver || pVirtio->aVirtqueues[uVirtq].uEnable)
                     virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, uVirtq);
             }
@@ -1719,4 +2033,5 @@
         pVirtioCC->pbPrevDevSpecificCfg = NULL;
     }
+
     RT_NOREF(pDevIns, pVirtio);
 }
@@ -1726,4 +2041,6 @@
                      const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg)
 {
+
+
     /*
      * The pVirtio state must be the first member of the shared device instance
@@ -1740,10 +2057,14 @@
     AssertReturn(pVirtioCC->pfnStatusChanged, VERR_INVALID_POINTER);
     AssertReturn(pVirtioCC->pfnVirtqNotified, VERR_INVALID_POINTER);
-
-#if 0 /* Until pdmR3DvHlp_PCISetIrq() impl is fixed and Assert that limits vec to 0 is removed */
+    AssertReturn(VIRTQ_SIZE > 0 && VIRTQ_SIZE <= 32768,  VERR_OUT_OF_RANGE); /* VirtIO specification-defined limit */
+
+#if 0 /* Until pdmR3DvHlp_PCISetIrq() impl is fixed and Assert that limits vec to 0 is removed
+       * The legacy MSI support has not been implemented yet
+       */
 # ifdef VBOX_WITH_MSI_DEVICES
     pVirtio->fMsiSupport = true;
 # endif
 #endif
+
 
     /*
@@ -1756,6 +2077,4 @@
 
     RTStrCopy(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszInstance);
-
-    pVirtio->fDeviceStatus = 0;
     pVirtioCC->cbDevSpecificCfg = cbDevSpecificCfg;
     pVirtioCC->pbDevSpecificCfg = (uint8_t *)pvDevSpecificCfg;
@@ -1769,10 +2088,10 @@
     PDMPciDevSetRevisionId(pPciDev,         DEVICE_PCI_REVISION_ID_VIRTIO);
     PDMPciDevSetVendorId(pPciDev,           DEVICE_PCI_VENDOR_ID_VIRTIO);
+    PDMPciDevSetDeviceId(pPciDev,           pPciParams->uDeviceId);
+    PDMPciDevSetSubSystemId(pPciDev,        DEVICE_PCI_NETWORK_SUBSYSTEM);
     PDMPciDevSetSubSystemVendorId(pPciDev,  DEVICE_PCI_VENDOR_ID_VIRTIO);
-    PDMPciDevSetDeviceId(pPciDev,           pPciParams->uDeviceId);
     PDMPciDevSetClassBase(pPciDev,          pPciParams->uClassBase);
     PDMPciDevSetClassSub(pPciDev,           pPciParams->uClassSub);
     PDMPciDevSetClassProg(pPciDev,          pPciParams->uClassProg);
-    PDMPciDevSetSubSystemId(pPciDev,        pPciParams->uSubsystemId);
     PDMPciDevSetInterruptLine(pPciDev,      pPciParams->uInterruptLine);
     PDMPciDevSetInterruptPin(pPciDev,       pPciParams->uInterruptPin);
@@ -1785,5 +2104,4 @@
     rc = PDMDevHlpPCIInterceptConfigAccesses(pDevIns, pPciDev, virtioR3PciConfigRead, virtioR3PciConfigWrite);
     AssertRCReturn(rc, rc);
-
 
     /* Construct & map PCI vendor-specific capabilities for virtio host negotiation with guest driver */
@@ -1918,13 +2236,28 @@
     PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST);
 
-    size_t cbSize = RTStrPrintf(pVirtioCC->pcszMmioName, sizeof(pVirtioCC->pcszMmioName), "%s MMIO", pcszInstance);
+    size_t cbSize = RTStrPrintf(pVirtioCC->pcszMmioName, sizeof(pVirtioCC->pcszMmioName), "%s (modern)", pcszInstance);
     if (cbSize <= 0)
         return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: out of memory allocating string")); /* can we put params in this error? */
 
-    /* Note: The Linux driver at drivers/virtio/virtio_pci_modern.c tries to map at least a page for the
+    cbSize = RTStrPrintf(pVirtioCC->pcszPortIoName, sizeof(pVirtioCC->pcszPortIoName), "%s (legacy)", pcszInstance);
+    if (cbSize <= 0)
+        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: out of memory allocating string")); /* can we put params in this error? */
+
+    /* As a transitional device that supports legacy VirtIO drivers, this VirtIO device generic implementation presents
+     * legacy driver interface in I/O space at BAR0. The following maps the common (e.g. device independent)
+     * dev config area as well as device-specific dev config area (whose size is passed to init function of this VirtIO
+     * generic device code) for access via Port I/O, since legacy drivers (e.g. pre VirtIO 1.0) don't use MMIO callbacks.
+     * (See VirtIO 1.1, Section 4.1.4.8).
+     */
+    rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, VIRTIO_REGION_LEGACY_IO, sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T) + cbDevSpecificCfg,
+                                      virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/, pVirtioCC->pcszPortIoName,
+                                      NULL /*paExtDescs*/, &pVirtio->hLegacyIoPorts);
+    AssertLogRelRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register legacy config in I/O space at BAR0 */")));
+
+    /*  Note: The Linux driver at drivers/virtio/virtio_pci_modern.c tries to map at least a page for the
      * 'unknown' device-specific capability without querying the capability to figure
      *  out size, so pad with an extra page
      */
-    rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + PAGE_SIZE, PAGE_SIZE),
+    rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + VIRTIO_PAGE_SIZE, VIRTIO_PAGE_SIZE),
                                         PCI_ADDRESS_SPACE_MEM, virtioMmioWrite, virtioMmioRead, pVirtio,
                                         IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
@@ -1935,4 +2268,5 @@
      * Statistics.
      */
+# ifdef VBOX_WITH_STATISTICS
     PDMDevHlpSTAMRegisterF(pDevIns, &pVirtio->StatDescChainsAllocated,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
                            "Total number of allocated descriptor chains",   "DescChainsAllocated");
@@ -1943,4 +2277,13 @@
     PDMDevHlpSTAMRegisterF(pDevIns, &pVirtio->StatDescChainsSegsOut,    STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
                            "Total number of outbound segments",             "DescChainsSegsOut");
+    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatReadR3,    STAMTYPE_PROFILE, "IO/ReadR3",          STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in R3");
+    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatReadR0,    STAMTYPE_PROFILE, "IO/ReadR0",          STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in R0");
+    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatReadRC,    STAMTYPE_PROFILE, "IO/ReadRC",          STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in RC");
+    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatWriteR3,   STAMTYPE_PROFILE, "IO/WriteR3",         STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in R3");
+    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatWriteR0,   STAMTYPE_PROFILE, "IO/WriteR0",         STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in R0");
+    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatWriteRC,   STAMTYPE_PROFILE, "IO/WriteRC",         STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in RC");
+# endif /* VBOX_WITH_STATISTICS */
+
+    virtioResetDevice(pDevIns, pVirtio); /* Reset VirtIO specific state of device */
 
     return VINF_SUCCESS;
@@ -1967,4 +2310,8 @@
     int rc = PDMDevHlpMmioSetUpContext(pDevIns, pVirtio->hMmioPciCap, virtioMmioWrite, virtioMmioRead, pVirtio);
     AssertRCReturn(rc, rc);
+
+    rc = PDMDevHlpIoPortSetUpContext(pDevIns, pVirtio->hLegacyIoPorts, virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/);
+    AssertRCReturn(rc, rc);
+
     return rc;
 }
Index: /trunk/src/VBox/Devices/VirtIO/VirtioCore.h
===================================================================
--- /trunk/src/VBox/Devices/VirtIO/VirtioCore.h	(revision 91702)
+++ /trunk/src/VBox/Devices/VirtIO/VirtioCore.h	(revision 91703)
@@ -25,4 +25,5 @@
 #include <iprt/ctype.h>
 #include <iprt/sg.h>
+#include <iprt/types.h>
 
 #ifdef LOG_ENABLED
@@ -48,9 +49,19 @@
 
 #define VIRTIO_MAX_VIRTQ_NAME_SIZE          32                   /**< Maximum length of a queue name           */
-#define VIRTQ_MAX_ENTRIES                   1024                 /**< Max size (# desc elements) of a virtq    */
+#define VIRTQ_SIZE                        1024                   /**< Max size (# entries) of a virtq          */
 #define VIRTQ_MAX_COUNT                     24                   /**< Max queues we allow guest to create      */
 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
+#define VIRTIO_REGION_LEGACY_IO             0                    /**< BAR for VirtIO legacy drivers MBZ        */
 #define VIRTIO_REGION_PCI_CAP               2                    /**< BAR for VirtIO Cap. MMIO (impl specific) */
 #define VIRTIO_REGION_MSIX_CAP              0                    /**< Bar for MSI-X handling                   */
+#define VIRTIO_PAGE_SIZE                 4096                    /**< Page size used by VirtIO specification   */
+
+
+/* Note: The VirtIO specification, particularly rev. 0.95, and clarified in rev 1.0 for transitional devices,
+         says the page sized used for Queue Size calculations is usually 4096 bytes, but dependent on the
+         the transport. In an appendix of the 0.95 spec, the 'mmio device', which has not been
+         implemented by VBox legacy device in VirtualBox, says guest must report the page size. For now
+         will set page size to a static 4096 based on the original VBox legacy VirtIO implementation which
+         tied it to PAGE_SIZE which appears to work (or at least good enough for most practical purposes)      */
 
 
@@ -107,6 +118,6 @@
     VIRTIOSGBUF         SgBufIn;
     VIRTIOSGBUF         SgBufOut;
-    VIRTIOSGSEG         aSegsIn[VIRTQ_MAX_ENTRIES];
-    VIRTIOSGSEG         aSegsOut[VIRTQ_MAX_ENTRIES];
+    VIRTIOSGSEG         aSegsIn[VIRTQ_SIZE];
+    VIRTIOSGSEG         aSegsOut[VIRTQ_SIZE];
     /** @} */
 } VIRTQBUF_T;
@@ -129,16 +140,29 @@
 } VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS;
 
+/* Virtio Platform Indepdented Reserved Feature Bits (see 1.1 specification section 6) */
+
+#define VIRTIO_F_NOTIFY_ON_EMPTY            RT_BIT_64(24)        /**< Legacy feature: Force intr if no AVAIL    */
+#define VIRTIO_F_ANY_LAYOUT                 RT_BIT_64(27)        /**< Doc bug: Goes under two names in spec     */
+#define VIRTIO_F_INDIRECT_DESC              RT_BIT_64(28)        /**< Allow descs to point to list of descs     */
+#define VIRTIO_F_RING_INDIRECT_DESC         RT_BIT_64(28)        /**< Doc bug: Goes under two names in spec     */
+#define VIRTIO_F_EVENT_IDX                  RT_BIT_64(29)        /**< Allow notification disable for n elems    */
+#define VIRTIO_F_RING_EVENT_IDX             RT_BIT_64(29)        /**< Doc bug: Goes under two names in spec     */
+#define VIRTIO_F_BAD_FEATURE                RT_BIT_64(30)        /**< QEMU kludge.  UNUSED as of >= VirtIO 1.0  */
 #define VIRTIO_F_VERSION_1                  RT_BIT_64(32)        /**< Required feature bit for 1.0 devices      */
-#define VIRTIO_F_INDIRECT_DESC              RT_BIT_64(28)        /**< Allow descs to point to list of descs     */
-#define VIRTIO_F_EVENT_IDX                  RT_BIT_64(29)        /**< Allow notification disable for n elems    */
-#define VIRTIO_F_RING_INDIRECT_DESC         RT_BIT_64(28)        /**< Doc bug: Goes under two names in spec     */
-#define VIRTIO_F_RING_EVENT_IDX             RT_BIT_64(29)        /**< Doc bug: Goes under two names in spec     */
+#define VIRTIO_F_ACCESS_PLATFORM            RT_BIT_64(33)        /**< Funky guest mem access   (VirtIO 1.1 NYI) */
+#define VIRTIO_F_RING_PACKED                RT_BIT_64(34)        /**< Packed Queue Layout      (VirtIO 1.1 NYI) */
+#define VIRTIO_F_IN_ORDER                   RT_BIT_64(35)        /**< Honor guest buf order    (VirtIO 1.1 NYI) */
+#define VIRTIO_F_ORDER_PLATFORM             RT_BIT_64(36)        /**< Host mem access honored  (VirtIO 1.1 NYI) */
+#define VIRTIO_F_SR_IOV                     RT_BIT_64(37)        /**< Dev Single Root I/O virt (VirtIO 1.1 NYI) */
+#define VIRTIO_F_NOTIFICAITON_DATA          RT_BIT_64(38)        /**< Driver passes extra data (VirtIO 1.1 NYI) */
 
 #define VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED ( 0 )            /**< TBD: Add VIRTIO_F_INDIRECT_DESC           */
+#define VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED ( 0 )     /**< Only offered to legacy drivers            */
 
 #define VIRTIO_ISR_VIRTQ_INTERRUPT           RT_BIT_32(0)        /**< Virtq interrupt bit of ISR register       */
 #define VIRTIO_ISR_DEVICE_CONFIG             RT_BIT_32(1)        /**< Device configuration changed bit of ISR   */
+#define DEVICE_PCI_NETWORK_SUBSYSTEM                    1        /**< Network Card, per VirtIO legacy spec.     */
 #define DEVICE_PCI_VENDOR_ID_VIRTIO                0x1AF4        /**< Guest driver locates dev via (mandatory)  */
-#define DEVICE_PCI_REVISION_ID_VIRTIO                   1        /**< VirtIO 1.0 non-transitional drivers >= 1  */
+#define DEVICE_PCI_REVISION_ID_VIRTIO                   0        /**< VirtIO Modern Transitional driver rev MBZ */
 
 /** Reserved (*negotiated*) Feature Bits (e.g. device independent features, VirtIO 1.0 spec,section 6) */
@@ -190,4 +214,24 @@
 
 /**
+ * VirtIO Legacy Capabilities' related MMIO-mapped structs (see virtio-0.9.5 spec)
+ *
+ * Note: virtio_pci_device_cap is dev-specific, implemented by client. Definition unknown here.
+ */
+typedef struct virtio_legacy_pci_common_cfg
+{
+    /* Device-specific fields */
+    uint32_t  uDeviceFeatures;                                   /**< RO (device reports features to driver)    */
+    uint32_t  uDriverFeatures;                                   /**< RW (driver-accepted device features)      */
+    uint32_t  uVirtqPfn;                                         /**< RW (driver writes queue page number)      */
+    uint16_t  uQueueSize;                                        /**< RW (queue size, 0 - 2^n)                  */
+    uint16_t  uVirtqSelect;                                      /**< RW (selects queue focus for these fields) */
+    uint16_t  uQueueNotify;                                      /**< RO (offset into virtqueue; see spec)      */
+    uint8_t   fDeviceStatus;                                     /**< RW (driver writes device status, 0=reset) */
+    uint8_t   fIsrStatus;                                        /**< RW (driver writes ISR status, 0=reset)    */
+//    uint16_t  uMsixConfig;                                       /**< RW (driver sets MSI-X config vector)      */
+//    uint16_t  uMsixVector;                                       /**< RW (driver sets MSI-X config vector)      */
+} VIRTIO_LEGACY_PCI_COMMON_CFG_T, *PVIRTIO_LEGACY_PCI_COMMON_CFG_T;
+
+/**
  * VirtIO 1.0 Capabilities' related MMIO-mapped structs:
  *
@@ -208,6 +252,6 @@
     /* Virtq-specific fields (values reflect (via MMIO) info related to queue indicated by uVirtqSelect. */
     uint16_t  uVirtqSelect;                                      /**< RW (selects queue focus for these fields) */
-    uint16_t  uSize;                                             /**< RW (queue size, 0 - 2^n)                  */
-    uint16_t  uMsix;                                             /**< RW (driver selects MSI-X queue vector)    */
+    uint16_t  uQueueSize;                                        /**< RW (queue size, 0 - 2^n)                  */
+    uint16_t  uMsixVector;                                       /**< RW (driver selects MSI-X queue vector)    */
     uint16_t  uEnable;                                           /**< RW (driver controls usability of queue)   */
     uint16_t  uNotifyOffset;                                     /**< RO (offset into virtqueue; see spec)      */
@@ -245,8 +289,8 @@
     RTGCPHYS                    GCPhysVirtqAvail;                 /**< (MMIO) PhysAdr per-Q avail structs  GUEST */
     RTGCPHYS                    GCPhysVirtqUsed;                  /**< (MMIO) PhysAdr per-Q used structs   GUEST */
-    uint16_t                    uMsix;                            /**< (MMIO) Per-queue vector for MSI-X   GUEST */
+    uint16_t                    uMsixVector;                      /**< (MMIO) Per-queue vector for MSI-X   GUEST */
     uint16_t                    uEnable;                          /**< (MMIO) Per-queue enable             GUEST */
     uint16_t                    uNotifyOffset;                    /**< (MMIO) per-Q notify offset           HOST */
-    uint16_t                    uSize;                            /**< (MMIO) Per-queue size          HOST/GUEST */
+    uint16_t                    uQueueSize;                       /**< (MMIO) Per-queue size          HOST/GUEST */
     uint16_t                    uAvailIdxShadow;                  /**< Consumer's position in avail ring         */
     uint16_t                    uUsedIdxShadow;                   /**< Consumer's position in used ring          */
@@ -272,6 +316,13 @@
     uint32_t                    uMsixConfig;                      /**< (MMIO) MSI-X vector                 GUEST */
     uint8_t                     fDeviceStatus;                    /**< (MMIO) Device Status                GUEST */
-    uint8_t                     uPrevDeviceStatus;                /**< (MMIO) Prev Device Status           GUEST */
+    uint8_t                     fPrevDeviceStatus;                /**< (MMIO) Prev Device Status           GUEST */
     uint8_t                     uConfigGeneration;                /**< (MMIO) Device config sequencer       HOST */
+    uint16_t                    uQueueNotify;                     /**< Caches queue idx in legacy mode     GUEST */
+    bool                        fGenUpdatePending;                /**< If set, update cfg gen after driver reads */
+    uint8_t                     uPciCfgDataOff;                   /**< Offset to PCI configuration data area     */
+    uint8_t                     uISR;                             /**< Interrupt Status Register.                */
+    uint8_t                     fMsiSupport;                      /**< Flag set if using MSI instead of ISR      */
+    uint8_t                     fLegacyDriver;                    /**< Set if guest driver < VirtIO 1.0          */
+    uint16_t                    uVirtqSelect;                     /**< (MMIO) queue selector               GUEST */
 
     /** @name The locations of the capability structures in PCI config space and the BAR.
@@ -284,12 +335,11 @@
     /** @} */
 
-    uint16_t                    uVirtqSelect;                     /**< (MMIO) queue selector               GUEST */
-    bool                        fGenUpdatePending;                /**< If set, update cfg gen after driver reads */
-    uint8_t                     uPciCfgDataOff;                   /**< Offset to PCI configuration data area     */
-    uint8_t                     uISR;                             /**< Interrupt Status Register.                */
-    uint8_t                     fMsiSupport;                      /**< Flag set if using MSI instead of ISR      */
-    /** The MMIO handle for the PCI capability region (\#2). */
-    IOMMMIOHANDLE               hMmioPciCap;
-
+
+
+    IOMMMIOHANDLE               hMmioPciCap;                      /**< MMIO handle of PCI cap. region (\#2)      */
+    IOMIOPORTHANDLE             hLegacyIoPorts;                   /**< Handle of legacy I/O port range.          */
+
+
+#ifdef VBOX_WITH_STATISTICS
     /** @name Statistics
      * @{ */
@@ -298,4 +348,12 @@
     STAMCOUNTER                 StatDescChainsSegsIn;
     STAMCOUNTER                 StatDescChainsSegsOut;
+    STAMPROFILEADV              StatReadR3;                        /** I/O port and MMIO R3 Read profiling       */
+    STAMPROFILEADV              StatReadR0;                        /** I/O port and MMIO R0 Read profiling       */
+    STAMPROFILEADV              StatReadRC;                        /** I/O port and MMIO R3 Read profiling       */
+    STAMPROFILEADV              StatWriteR3;                       /** I/O port and MMIO R3 Write profiling      */
+    STAMPROFILEADV              StatWriteR0;                       /** I/O port and MMIO R3 Write profiling      */
+    STAMPROFILEADV              StatWriteRC;                       /** I/O port and MMIO R3 Write profiling      */
+#endif
+
     /** @} */
 } VIRTIOCORE;
@@ -367,4 +425,5 @@
     bool                                fGenUpdatePending;         /**< If set, update cfg gen after driver reads */
     char                                pcszMmioName[MAX_NAME];    /**< MMIO mapping name                         */
+    char                                pcszPortIoName[MAX_NAME];  /**< PORT mapping name                         */
 } VIRTIOCORER3;
 
@@ -648,4 +707,14 @@
 int virtioCoreR3VirtqAvailBufNext(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
 
+/**
+ * Checks to see if guest has acknowledged device's VIRTIO_F_VERSION_1 feature.
+ * If not, it's presumed to be a VirtIO legacy guest driver. Note that legacy drivers
+ * may start using the device prematurely, as opposed to the rigorously sane protocol
+ * prescribed by the "modern" VirtIO spec. Doing so is suggestive of a legacy driver.
+ * Therefore legacy mode is the assumption un proven otherwise.
+ *
+ * @param   pVirtio      Pointer to the virtio state.
+ */
+int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio);
 
 DECLINLINE(void) virtioCoreGCPhysChainInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs)
@@ -881,4 +950,6 @@
 {
     Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqueues));
+    if (pVirtio->fLegacyDriver)
+        return pVirtio->aVirtqueues[uVirtqNbr].GCPhysVirtqDesc != 0;
     return pVirtio->aVirtqueues[uVirtqNbr].uEnable != 0;
 }
@@ -958,5 +1029,5 @@
  * @param   uBase       base address of per-row address prefixing of hex output
  * @param   pszTitle    Optional title. If present displays title that lists
- *                      provided text with value of cb to indicate size next to it.
+ *                      provided text with value of cb to indicate VIRTQ_SIZE next to it.
  */
 void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle);
@@ -993,4 +1064,29 @@
 }
 
+/**
+ * This VirtIO transitional device supports "modern" (rev 1.0+) as well as "legacy" (e.g. < 1.0) VirtIO drivers.
+ * Some legacy guest drivers are known to mishandle PCI bus mastering wherein the PCI flavor of GC phys
+ * access functions can't be used. The following wrappers select the mem access method based on whether the
+ * device is operating in legacy mode or not.
+ */
+DECLINLINE(int) virtioCoreGCPhysWrite(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbWrite)
+{
+    int rc;
+    if (virtioCoreIsLegacyMode(pVirtio))
+        rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
+    else
+        rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
+    return rc;
+}
+
+DECLINLINE(int) virtioCoreGCPhysRead(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+{
+    int rc;
+    if (virtioCoreIsLegacyMode(pVirtio))
+        rc = PDMDevHlpPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
+    else
+        rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
+    return rc;
+}
 
 /** Misc VM and PDM boilerplate */
@@ -1055,4 +1151,6 @@
                                   RT_UOFFSETOF(tCfgStruct, member),  \
                                   RT_SIZEOFMEMB(tCfgStruct, member), false /* fSubfieldMatch */)
+
+
 
 /**
