VirtualBox

Changeset 91703 in vbox for trunk/src/VBox/Devices


Ignore:
Timestamp:
Oct 13, 2021 2:24:30 AM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
147437
Message:

DevVirtioNet_1_0.cpp: Convert VirtIO to be 'transitional' device, that handles both legacy (0.9) guests and modern (1.0+) guests. Various other small improvements and reduction/improved formatting of logging. See BugRef:8561, Comment #137

Location:
trunk/src/VBox/Devices
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp

    r90931 r91703  
    119119 */
    120120
    121 #define FEATURE_ENABLED(feature)        RT_BOOL(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)
     121#define FEATURE_ENABLED(feature)        RT_BOOL(!!(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature))
    122122#define FEATURE_DISABLED(feature)       (!FEATURE_ENABLED(feature))
    123123#define FEATURE_OFFERED(feature)        VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature
     
    165165            (virtioCoreVirtqAvailBufCount(pDevIns, pVirtio, uVirtqNbr) == 0)
    166166
    167 #define PCI_DEVICE_ID_VIRTIONET_HOST               0x1041      /**< Informs guest driver of type of VirtIO device   */
    168 #define PCI_CLASS_BASE_NETWORK_CONTROLLER          0x02        /**< PCI Network device class                        */
     167
     168#define PCI_DEVICE_ID_VIRTIONET_HOST               0x1000      /**< VirtIO transitional device ID for network card  */
     169#define PCI_CLASS_BASE_NETWORK_CONTROLLER          0x0200      /**< PCI Network device class                        */
    169170#define PCI_CLASS_SUB_NET_ETHERNET_CONTROLLER      0x00        /**< PCI NET Controller subclass                     */
    170171#define PCI_CLASS_PROG_UNSPECIFIED                 0x00        /**< Programming interface. N/A.                     */
    171172#define VIRTIONET_PCI_CLASS                        0x01        /**< Base class Mass Storage?                        */
    172 
    173 
    174 /*********************************************************************************************************************************
    175 *   Structures and Typedefs                                                                                                      *
    176 *********************************************************************************************************************************/
    177173
    178174/**
     
    373369
    374370    /** Number of virtqueues total (which includes each queue of each pair plus one control queue */
    375     uint16_t                cVirtVirtqs;
     371    uint16_t                cVirtqs;
    376372
    377373    /** Number of worker threads (one for the control queue and one for each Tx queue) */
     
    444440    bool                    fCableConnected;
    445441
     442    /** True if guest has not reported modern virtio driver */
     443    bool                    fIsLegacy;
    446444    /** @name Statistic
    447445     * @{ */
     
    553551static int virtioNetR3CreateWorkerThreads(PPDMDEVINS, PVIRTIONET, PVIRTIONETCC);
    554552
     553typedef enum VIRTIONETPKTHDRTYPE
     554{
     555    kVirtioNetModernPktHdr_1_0          = 0,
     556    kVirtioNetLegacyPktHdr              = 1,
     557    kVirtioNetLegacyPktHdrWithoutMrgRx  = 2,
     558    kVirtioNetFor32BitHack              = 0x7fffffff
     559} VIRTIONETPKTHDRTYPE;
     560
     561DECLINLINE(int) virtioNetPktHdrType(PVIRTIOCORE pVirtio, PVIRTIONET pThis)
     562{
     563    if (!virtioCoreIsLegacyMode(pVirtio))
     564        return kVirtioNetModernPktHdr_1_0;
     565    else /* legacy mode */
     566        if (FEATURE_ENABLED(MRG_RXBUF))
     567            return kVirtioNetLegacyPktHdrWithoutMrgRx;
     568    return kVirtioNetLegacyPktHdr;
     569}
     570
     571DECLINLINE(size_t) virtioNetCalcPktHdrSize(PVIRTIOCORE pVirtio, PVIRTIONET pThis)
     572{
     573    size_t cbHdr = sizeof(VIRTIONETPKTHDR);
     574    if (virtioCoreIsLegacyMode(pVirtio) & !FEATURE_ENABLED(MRG_RXBUF))
     575        cbHdr -= RT_SIZEOFMEMB(VIRTIONETPKTHDR, uNumBuffers);
     576    return cbHdr;
     577}
     578
    555579DECLINLINE(const char *) virtioNetThreadStateName(PPDMTHREAD pThread)
    556580{
     
    594618    if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT)
    595619    {
    596         Log10Func(("%s Waking downstream device's Rx buf waiter thread\n", pThis->szInst));
     620        Log10Func(("[%s] Waking downstream device's Rx buf waiter thread\n", pThis->szInst));
    597621        int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEventRxDescAvail);
    598622        AssertRC(rc);
     
    600624}
    601625
    602 
    603 
    604626/**
    605627 * @callback_method_impl{VIRTIOCORER0,pfnVirtqNotified}
     
    614636
    615637#if defined (IN_RING3) && defined (LOG_ENABLED)
    616 
    617      RTLogFlush(NULL);
    618 
     638    RTLogFlush(NULL);
    619639#endif
    620 
    621640    if (IS_RX_VIRTQ(uVirtqNbr))
    622641    {
     
    640659            if (ASMAtomicReadBool(&pWorker->fSleeping))
    641660            {
    642                 Log10Func(("%s %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
     661                Log10Func(("[%s] %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
    643662
    644663                int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
     
    647666            else
    648667            {
    649                 Log10Func(("%s %s has available buffers - worker already awake\n", pThis->szInst, pVirtq->szName));
     668                Log10Func(("[%s] %s has available buffers - worker already awake\n", pThis->szInst, pVirtq->szName));
    650669            }
    651670        }
    652671        else
    653672        {
    654             Log10Func(("%s %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
     673            Log10Func(("[%s] %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
    655674        }
    656675    }
    657676    else
    658         LogRelFunc(("%s unrecognized queue %s (idx=%d) notified\n", pThis->szInst, pVirtq->szName, uVirtqNbr));
     677        LogRelFunc(("[%s] unrecognized queue %s (idx=%d) notified\n", pThis->szInst, pVirtq->szName, uVirtqNbr));
    659678}
    660679
     
    669688    PVIRTIONETWORKER pWorker = (PVIRTIONETWORKER)pThread->pvUser;
    670689
    671     Log10Func(("%s\n", pThis->szInst));
     690    Log10Func(("[%s]\n", pThis->szInst));
    672691    RT_NOREF(pThis);
    673 
    674692    return PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
    675693}
     
    770788    {
    771789        LogFunc(("-------------------------------------------------------------------\n"));
    772         LogFunc(("rxPktHdr\n"
    773                  "    uFlags ......... %2.2x\n"
    774                  "    uGsoType ....... %2.2x\n"
    775                  "    uHdrLen ........ %4.4x\n"
    776                  "    uGsoSize ....... %4.4x\n"
    777                  "    uChksumStart ... %4.4x\n"
    778                  "    uChksumOffset .. %4.4x\n"
    779                  "    uNumBuffers .... %4.4x\n",
    780                         pRxPktHdr->uFlags,
    781                         pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
    782                         pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers));
    783 
     790        if (!virtioCoreIsLegacyMode(&pThis->Virtio) || FEATURE_ENABLED(MRG_RXBUF))
     791                LogFunc(("rxPktHdr\n"
     792                         "    uFlags ......... %2.2x\n    uGsoType ....... %2.2x\n    uHdrLen ........ %4.4x\n"
     793                         "    uGsoSize ....... %4.4x\n    uChksumStart ... %4.4x\n    uChksumOffset .. %4.4x\n"
     794                         "    uNumBuffers .... %4.4x\n",
     795                                pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
     796                                pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers));
     797        else
     798                LogFunc(("rxPktHdr\n"
     799                         "    uFlags ......... %2.2x\n    uGsoType ....... %2.2x\n    uHdrLen ........ %4.4x\n"
     800                         "    uGsoSize ....... %4.4x\n    uChksumStart ... %4.4x\n    uChksumOffset .. %4.4x\n",
     801                                pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
     802                                pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset));
    784803        virtioCoreHexDump((uint8_t *)pRxPktHdr, sizeof(VIRTIONETPKTHDR), 0, "Dump of virtual rPktHdr");
    785804    }
     
    833852    {
    834853        pHlp->pfnPrintf(pHlp, "Virtq information:\n\n");
    835 
    836         for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
     854        for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    837855        {
    838856            PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr];
     
    879897    if (fAll || fPointers)
    880898    {
    881 
    882899        pHlp->pfnPrintf(pHlp, "Internal Pointers:\n\n");
    883 
    884900        pHlp->pfnPrintf(pHlp, "    pDevIns ................... %p\n",   pDevIns);
    885901        pHlp->pfnPrintf(pHlp, "    PVIRTIONET ................ %p\n",   pThis);
     
    889905        pHlp->pfnPrintf(pHlp, "    pDrv ...................... %p\n",   pThisCC->pDrv);
    890906        pHlp->pfnPrintf(pHlp, "\n");
    891 
    892907    }
    893908
     
    908923        pHlp->pfnPrintf(pHlp, "    uDeviceStatus ............. 0x%x\n", pThis->Virtio.fDeviceStatus);
    909924        pHlp->pfnPrintf(pHlp, "    cVirtqPairs .,............. %d\n",   pThis->cVirtqPairs);
    910         pHlp->pfnPrintf(pHlp, "    cVirtVirtqs .,............. %d\n",   pThis->cVirtVirtqs);
     925        pHlp->pfnPrintf(pHlp, "    cVirtqs .,................. %d\n",   pThis->cVirtqs);
    911926        pHlp->pfnPrintf(pHlp, "    cWorkers .................. %d\n",   pThis->cWorkers);
    912927        pHlp->pfnPrintf(pHlp, "    MMIO mapping name ......... %d\n",   pThisCC->Virtio.pcszMmioName);
     
    918933    {
    919934        pHlp->pfnPrintf(pHlp, "Network configuration:\n\n");
    920 
    921935        pHlp->pfnPrintf(pHlp, "    MAC: ...................... %RTmac\n", &pThis->macConfigured);
    922936        pHlp->pfnPrintf(pHlp, "\n");
     
    952966        pHlp->pfnPrintf(pHlp, "    Leaf starved: ............. %s\n",      pThis->fLeafWantsEmptyRxBufs ? "true" : "false");
    953967        pHlp->pfnPrintf(pHlp, "\n");
    954 
    955968    }
    956969    /** @todo implement this
     
    10011014}
    10021015
    1003 static int virtioNetR3CfgAccessed(PVIRTIONET pThis, uint32_t uOffsetOfAccess, void *pv, uint32_t cb, bool fWrite)
     1016static int virtioNetR3DevCfgAccess(PVIRTIONET pThis, uint32_t uOffsetOfAccess, void *pv, uint32_t cb, bool fWrite)
    10041017{
    10051018    AssertReturn(pv && cb <= sizeof(uint32_t), fWrite ? VINF_SUCCESS : VINF_IOM_MMIO_UNUSED_00);
     
    10331046    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    10341047
    1035     LogFunc((" %s uOffset: %d, cb: %d\n",  pThis->szInst, uOffset, cb));
    10361048    RT_NOREF(pThis);
    1037     return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, pv, cb, false /*fRead*/);
     1049    return virtioNetR3DevCfgAccess(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, pv, cb, false /*fRead*/);
    10381050}
    10391051
     
    10451057    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    10461058
    1047     Log10Func(("%s uOffset: %d, cb: %d: %.*Rhxs\n", pThis->szInst, uOffset, cb, RT_MAX(cb, 8) , pv));
     1059    Log10Func(("[%s] uOffset: %d, cb: %d: %.*Rhxs\n", pThis->szInst, uOffset, cb, RT_MAX(cb, 8) , pv));
    10481060    RT_NOREF(pThis);
    1049     return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, (void *)pv, cb, true /*fWrite*/);
     1061    return virtioNetR3DevCfgAccess(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, (void *)pv, cb, true /*fWrite*/);
    10501062}
    10511063
     
    10651077
    10661078    RT_NOREF(pThisCC);
    1067     Log7Func(("%s LOAD EXEC!!\n", pThis->szInst));
     1079    Log7Func(("[%s] LOAD EXEC!!\n", pThis->szInst));
    10681080
    10691081    AssertReturn(uPass == SSM_PASS_FINAL, VERR_SSM_UNEXPECTED_PASS);
     
    10751087    pHlp->pfnSSMGetU64(     pSSM, &pThis->fNegotiatedFeatures);
    10761088
    1077     pHlp->pfnSSMGetU16(     pSSM, &pThis->cVirtVirtqs);
    1078     AssertReturn(pThis->cVirtVirtqs <= (VIRTIONET_MAX_QPAIRS * 2), VERR_OUT_OF_RANGE);
     1089    pHlp->pfnSSMGetU16(     pSSM, &pThis->cVirtqs);
     1090    AssertReturn(pThis->cVirtqs <= (VIRTIONET_MAX_QPAIRS * 2), VERR_OUT_OF_RANGE);
    10791091
    10801092    pHlp->pfnSSMGetU16(     pSSM, &pThis->cWorkers);
     
    10821094
    10831095
    1084     for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
     1096    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    10851097        pHlp->pfnSSMGetBool(pSSM, &pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore);
    10861098
     
    11481160        if (pVirtq->fAttachedToVirtioCore)
    11491161        {
    1150             Log7Func(("%s Waking %s worker.\n", pThis->szInst, pVirtq->szName));
     1162            Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName));
    11511163            rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
    11521164            AssertRCReturn(rc, rc);
     
    11661178
    11671179    RT_NOREF(pThisCC);
    1168     Log7Func(("%s SAVE EXEC!!\n", pThis->szInst));
     1180    Log7Func(("[%s] SAVE EXEC!!\n", pThis->szInst));
    11691181
    11701182    pHlp->pfnSSMPutU64(     pSSM, pThis->fNegotiatedFeatures);
    11711183
    1172     pHlp->pfnSSMPutU16(     pSSM, pThis->cVirtVirtqs);
     1184    pHlp->pfnSSMPutU16(     pSSM, pThis->cVirtqs);
    11731185    pHlp->pfnSSMPutU16(     pSSM, pThis->cWorkers);
    11741186
    1175     for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
     1187    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    11761188        pHlp->pfnSSMPutBool(pSSM, pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore);
    11771189
     
    12491261void virtioNetR3SetReadLed(PVIRTIONETR3 pThisR3, bool fOn)
    12501262{
    1251     Log10Func(("%s\n", fOn ? "on" : "off"));
    12521263    if (fOn)
    12531264        pThisR3->led.Asserted.s.fReading = pThisR3->led.Actual.s.fReading = 1;
     
    13011312
    13021313    if (!virtioNetIsOperational(pThis, pDevIns))
    1303         Log8Func(("%s No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));
     1314        Log8Func(("[%s] No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));
    13041315
    13051316    else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio, pRxVirtq->uIdx))
    1306         Log8Func(("%s No Rx bufs available. (%s not enabled)\n",  pThis->szInst, pRxVirtq->szName));
     1317        Log8Func(("[%s] No Rx bufs available. (%s not enabled)\n",  pThis->szInst, pRxVirtq->szName));
    13071318
    13081319    else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxVirtq->uIdx))
    1309         Log8Func(("%s No Rx bufs available. (%s empty)\n",  pThis->szInst, pRxVirtq->szName));
     1320        Log8Func(("[%s] No Rx bufs available. (%s empty)\n",  pThis->szInst, pRxVirtq->szName));
    13101321
    13111322    else
    13121323    {
    1313         Log8Func(("%s Empty guest buffers available in %s\n",  pThis->szInst,pRxVirtq->szName));
     1324        Log8Func(("[%s] %s has empty guest bufs avail\n",  pThis->szInst, pRxVirtq->szName));
    13141325        rc = VINF_SUCCESS;
    13151326    }
     
    13471358    if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
    13481359    {
    1349         Log10Func(("%s Rx bufs now available, releasing waiter...\n", pThis->szInst));
     1360        Log10Func(("[%s] Rx bufs now available, releasing waiter...\n", pThis->szInst));
    13501361        return VINF_SUCCESS;
    13511362    }
     
    13531364        return VERR_NET_NO_BUFFER_SPACE;
    13541365
    1355     LogFunc(("%s %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : ""));
     1366    LogFunc(("[%s] %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : ""));
    13561367
    13571368
     
    13621373        if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
    13631374        {
    1364             Log10Func(("%s Rx bufs now available, releasing waiter...\n", pThis->szInst));
     1375            Log10Func(("[%s] Rx bufs now available, releasing waiter...\n", pThis->szInst));
    13651376            ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, false);
    13661377            return VINF_SUCCESS;
    13671378        }
    1368         Log9Func(("%s Starved for empty guest Rx bufs. Waiting...\n", pThis->szInst));
     1379        Log9Func(("[%s] Starved for empty guest Rx bufs. Waiting...\n", pThis->szInst));
    13691380
    13701381        int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventRxDescAvail, timeoutMs);
     
    13881399    ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, false);
    13891400
    1390     Log7Func(("%s Wait for Rx buffers available was interrupted\n", pThis->szInst));
     1401    Log7Func(("[%s] Wait for Rx buffers available was interrupted\n", pThis->szInst));
    13911402    return VERR_INTERRUPTED;
    13921403}
     
    14871498        char *pszType;
    14881499        if (virtioNetR3IsMulticast(pvBuf))
    1489             pszType = (char *)"Multicast";
     1500            pszType = (char *)"mcast";
    14901501        else if (virtioNetR3IsBroadcast(pvBuf))
    1491             pszType = (char *)"Broadcast";
     1502            pszType = (char *)"bcast";
    14921503        else
    1493             pszType = (char *)"Unicast";
    1494 
    1495         LogFunc(("%s node(%RTmac %s%s), pkt(%RTmac %s)\n",
    1496                  pThis->szInst, pThis->virtioNetConfig.uMacAddress.au8,
    1497                  pThis->fPromiscuous ? "promiscuous" : "",
    1498                  pThis->fAllMulticast ? " all-multicast" : "",
     1504            pszType = (char *)"ucast";
     1505
     1506        LogFunc(("node(%RTmac%s%s), pkt(%RTmac, %s) ",
     1507                 pThis->virtioNetConfig.uMacAddress.au8,
     1508                 pThis->fPromiscuous ? " promisc" : "",
     1509                 pThis->fAllMulticast ? " all-mcast" : "",
    14991510                 pvBuf,  pszType));
    15001511    }
    15011512
    1502     if (pThis->fPromiscuous)
     1513    if (pThis->fPromiscuous) {
     1514        Log11(("\n"));
    15031515        return true;
     1516    }
    15041517
    15051518    /* Ignore everything outside of our VLANs */
     
    15101523        && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_U16(uPtr[7]) & 0xFFF))
    15111524    {
    1512         Log11Func(("\n%s not our VLAN, returning false\n", pThis->szInst));
     1525        Log11Func(("\n[%s] not our VLAN, returning false\n", pThis->szInst));
    15131526        return false;
    15141527    }
     
    15161529    if (virtioNetR3IsBroadcast(pvBuf))
    15171530    {
    1518         Log11(("... accept (broadcast)\n"));
     1531        Log11(("acpt (bcast)\n"));
    15191532        if (LogIs12Enabled())
    15201533            virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     
    15231536    if (pThis->fAllMulticast && virtioNetR3IsMulticast(pvBuf))
    15241537    {
    1525         Log11(("... accept (all-multicast mode)\n"));
     1538        Log11(("acpt (all-mcast)\n"));
    15261539        if (LogIs12Enabled())
    15271540            virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     
    15311544    if (!memcmp(pThis->virtioNetConfig.uMacAddress.au8, pvBuf, sizeof(RTMAC)))
    15321545    {
    1533         Log11((". . . accept (direct to this node)\n"));
     1546        Log11(("acpt (to-node)\n"));
    15341547        if (LogIs12Enabled())
    15351548            virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     
    15411554        if (!memcmp(&pThis->aMacMulticastFilter[i], pvBuf, sizeof(RTMAC)))
    15421555        {
    1543             Log11(("... accept (in multicast array)\n"));
     1556            Log11(("acpt (mcast whitelist)\n"));
    15441557            if (LogIs12Enabled())
    15451558                virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     
    15511564        if (!memcmp(&pThis->aMacUnicastFilter[i], pvBuf, sizeof(RTMAC)))
    15521565        {
    1553             Log11(("... accept (in unicast array)\n"));
     1566            Log11(("acpt (ucast whitelist)\n"));
    15541567            return true;
    15551568        }
    15561569
    1557     if (LogIs12Enabled())
     1570    if (LogIs11Enabled())
    15581571        Log(("... reject\n"));
    15591572
     
    15701583    uint16_t cVirtqBufs  = 0;
    15711584    uint64_t uOffset = 0;
     1585
     1586    int uPktHdrType = virtioNetPktHdrType(&pThis->Virtio,  pThis);
    15721587
    15731588    while (uOffset < cb)
     
    15841599                            VERR_INTERNAL_ERROR);
    15851600
    1586         /* Length of first seg of guest Rx S/G buf should never be less than sizeof(virtio_net_pkt_hdr).
     1601        /* Length of first seg of guest Rx S/G buf should never be less than sthe packet header.
    15871602         * Otherwise code has to become more complicated, e.g. locate & cache seg idx & offset of
    1588          * virtio_net_header.num_buffers, to facilitate deferring updating GCPhys memory. Re-visit if needed */
    1589 
    1590         AssertMsgReturnStmt(pVirtqBuf->pSgPhysReturn->paSegs[0].cbSeg >= sizeof(VIRTIONETPKTHDR),
    1591                             ("Desc chain's first seg has insufficient space for pkt header!\n"),
    1592                             virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf),
    1593                             VERR_INTERNAL_ERROR);
     1603         * virtio_net_header.num_buffers, to facilitate deferring updating GCPhys memory.
     1604         * Re-visit if needed */
     1605
     1606        size_t cbPktHdr = virtioNetCalcPktHdrSize(&pThis->Virtio, pThis);
     1607
     1608        AssertMsgReturn(pVirtqBuf->pSgPhysReturn->paSegs[0].cbSeg >= cbPktHdr,
     1609                            ("Out of Memory"), VERR_NO_MEMORY);
    15941610
    15951611        size_t cbBufRemaining = pVirtqBuf->cbPhysReturn;
    1596         uint8_t  cbHdr = sizeof(VIRTIONETPKTHDR);
     1612
    15971613
    15981614        /* Fill the Guest Rx buffer with data received from the interface */
     
    16021618            {
    16031619                /* Lead with packet header */
    1604                 paVirtSegsToGuest[0].cbSeg = cbHdr;
    1605                 paVirtSegsToGuest[0].pvSeg = RTMemAlloc(cbHdr);
     1620                paVirtSegsToGuest[0].cbSeg = cbPktHdr;
     1621                paVirtSegsToGuest[0].pvSeg = RTMemAlloc(cbPktHdr);
    16061622                AssertReturn(paVirtSegsToGuest[0].pvSeg, VERR_NO_MEMORY);
    1607                 cbBufRemaining -= cbHdr;
    1608 
    1609                 memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, cbHdr);
    1610 
    1611                 /* Calculate & cache GCPhys addr of field to update after final value is known */
    1612                 GCPhysPktHdrNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys
    1613                                        + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers);
     1623                cbBufRemaining -= cbPktHdr;
     1624
     1625                memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, cbPktHdr);
     1626
     1627                if (uPktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx)
     1628                {
     1629                    /* Calculate & cache GCPhys addr of field to update after final value is known */
     1630                    GCPhysPktHdrNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys
     1631                                           + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers);
     1632                }
    16141633                fAddPktHdr = false;
    16151634                cSegs++;
     
    16481667    if (uOffset < cb)
    16491668    {
    1650         LogFunc(("%s Packet did not fit into RX queue (packet size=%u)!\n", pThis->szInst, cb));
     1669        LogFunc(("[%s] Packet did not fit into RX queue (packet size=%u)!\n", pThis->szInst, cb));
    16511670        return VERR_TOO_MUCH_DATA;
    16521671    }
    16531672
    1654     /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */
    1655 
    1656     int rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhysPktHdrNumBuffers, &cVirtqBufs, sizeof(cVirtqBufs));
    1657     AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc);
     1673
     1674    if (uPktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx)
     1675    {
     1676        /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */
     1677        int rc = virtioCoreGCPhysWrite(&pThis->Virtio, pDevIns, GCPhysPktHdrNumBuffers, &cVirtqBufs, sizeof(cVirtqBufs));
     1678        AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc);
     1679    }
    16581680
    16591681    virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, pRxVirtq->uIdx);
     
    16831705    RT_NOREF(pThisCC);
    16841706
    1685     LogFunc(("%s (%RTmac) pGso %s\n", pThis->szInst, pvBuf, pGso ? "present" : "not present"));
     1707    LogFunc(("[%s] (%RTmac) pGso %s\n", pThis->szInst, pvBuf, pGso ? "present" : "not present"));
    16861708    VIRTIONETPKTHDR rxPktHdr;
    16871709
    16881710    if (pGso)
    16891711    {
    1690         Log2Func(("%s gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
     1712        Log2Func(("[%s] gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
    16911713              pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal,
    16921714              pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
     
    17831805        if (!uFeatures)
    17841806        {
    1785             LogFunc(("%s GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type));
     1807            LogFunc(("[%s] GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type));
    17861808            return VERR_NOT_SUPPORTED;
    17871809        }
    17881810    }
    17891811
    1790     Log10Func(("%s pvBuf=%p cb=%3u pGso=%p ...\n", pThis->szInst, pvBuf, cb, pGso));
     1812    Log10Func(("[%s] pvBuf=%p cb=%3u pGso=%p ...\n", pThis->szInst, pvBuf, cb, pGso));
    17911813
    17921814    /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue
     
    18301852{
    18311853
    1832 #define LOG_VIRTIONET_FLAG(fld) LogFunc(("%s Setting %s=%d\n", pThis->szInst, #fld, pThis->fld))
    1833 
    1834     LogFunc(("%s Processing CTRL Rx command\n", pThis->szInst));
     1854#define LOG_VIRTIONET_FLAG(fld) LogFunc(("[%s] Setting %s=%d\n", pThis->szInst, #fld, pThis->fld))
     1855
     1856    LogFunc(("[%s] Processing CTRL Rx command\n", pThis->szInst));
    18351857    switch(pCtrlPktHdr->uCmd)
    18361858    {
     
    18931915static uint8_t virtioNetR3CtrlMac(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
    18941916{
    1895     LogFunc(("%s Processing CTRL MAC command\n", pThis->szInst));
     1917    LogFunc(("[%s] Processing CTRL MAC command\n", pThis->szInst));
     1918
    18961919
    18971920    AssertMsgReturn(pVirtqBuf->cbPhysSend >= sizeof(*pCtrlPktHdr),
     
    19251948            cbRemaining -= sizeof(cMacs);
    19261949
    1927             Log7Func(("%s Guest provided %d unicast MAC Table entries\n", pThis->szInst, cMacs));
     1950            Log7Func(("[%s] Guest provided %d unicast MAC Table entries\n", pThis->szInst, cMacs));
    19281951
    19291952            if (cMacs)
     
    19501973            cbRemaining -= sizeof(cMacs);
    19511974
    1952             Log10Func(("%s Guest provided %d multicast MAC Table entries\n", pThis->szInst, cMacs));
     1975            Log10Func(("[%s] Guest provided %d multicast MAC Table entries\n", pThis->szInst, cMacs));
    19531976
    19541977
     
    19681991
    19691992#ifdef LOG_ENABLED
    1970             LogFunc(("%s unicast MACs:\n", pThis->szInst));
     1993            LogFunc(("[%s] unicast MACs:\n", pThis->szInst));
    19711994            for(unsigned i = 0; i < cMacs; i++)
    19721995                LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
    19731996
    1974             LogFunc(("%s multicast MACs:\n", pThis->szInst));
     1997            LogFunc(("[%s] multicast MACs:\n", pThis->szInst));
    19751998            for(unsigned i = 0; i < cMacs; i++)
    19761999                LogFunc(("         %RTmac\n", &pThis->aMacMulticastFilter[i]));
     
    19872010static uint8_t virtioNetR3CtrlMultiQueue(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMDEVINS pDevIns, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
    19882011{
    1989     LogFunc(("%s Processing CTRL MQ command\n", pThis->szInst));
     2012    LogFunc(("[%s] Processing CTRL MQ command\n", pThis->szInst));
    19902013
    19912014    uint16_t cVirtqPairs;
     
    20032026
    20042027            AssertMsgReturn(cVirtqPairs > VIRTIONET_MAX_QPAIRS,
    2005                 ("%s Guest CTRL MQ virtq pair count out of range)\n", pThis->szInst, cVirtqPairs), VIRTIONET_ERROR);
    2006 
    2007             LogFunc(("%s Guest specifies %d VQ pairs in use\n", pThis->szInst, cVirtqPairs));
     2028                ("[%s] Guest CTRL MQ virtq pair count out of range)\n", pThis->szInst, cVirtqPairs), VIRTIONET_ERROR);
     2029
     2030            LogFunc(("[%s] Guest specifies %d VQ pairs in use\n", pThis->szInst, cVirtqPairs));
    20082031            pThis->cVirtqPairs = cVirtqPairs;
    20092032            break;
     
    20352058static uint8_t virtioNetR3CtrlVlan(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
    20362059{
    2037     LogFunc(("%s Processing CTRL VLAN command\n", pThis->szInst));
     2060    LogFunc(("[%s] Processing CTRL VLAN command\n", pThis->szInst));
    20382061
    20392062    uint16_t uVlanId;
     
    20492072        ("%s VLAN ID out of range (VLAN ID=%u)\n", pThis->szInst, uVlanId), VIRTIONET_ERROR);
    20502073
    2051     LogFunc(("%s uCommand=%u VLAN ID=%u\n", pThis->szInst, pCtrlPktHdr->uCmd, uVlanId));
     2074    LogFunc(("[%s] uCommand=%u VLAN ID=%u\n", pThis->szInst, pCtrlPktHdr->uCmd, uVlanId));
    20522075
    20532076    switch (pCtrlPktHdr->uCmd)
     
    20692092                            PVIRTQBUF pVirtqBuf)
    20702093{
    2071     LogFunc(("%s Received CTRL packet from guest\n", pThis->szInst));
     2094    LogFunc(("[%s] Received CTRL packet from guest\n", pThis->szInst));
    20722095
    20732096    if (pVirtqBuf->cbPhysSend < 2)
    20742097    {
    2075         LogFunc(("%s CTRL packet from guest driver incomplete. Skipping ctrl cmd\n", pThis->szInst));
     2098        LogFunc(("[%s] CTRL packet from guest driver incomplete. Skipping ctrl cmd\n", pThis->szInst));
    20762099        return;
    20772100    }
    20782101    else if (pVirtqBuf->cbPhysReturn < sizeof(VIRTIONET_CTRL_HDR_T_ACK))
    20792102    {
    2080         LogFunc(("%s Guest driver didn't allocate memory to receive ctrl pkt ACK. Skipping ctrl cmd\n", pThis->szInst));
     2103        LogFunc(("[%s] Guest driver didn't allocate memory to receive ctrl pkt ACK. Skipping ctrl cmd\n", pThis->szInst));
    20812104        return;
    20822105    }
     
    20952118                         RT_MIN(pVirtqBuf->cbPhysSend, sizeof(VIRTIONET_CTRL_HDR_T)));
    20962119
    2097     Log7Func(("%s CTRL COMMAND: class=%d command=%d\n", pThis->szInst, pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd));
     2120    Log7Func(("[%s] CTRL COMMAND: class=%d command=%d\n", pThis->szInst, pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd));
    20982121
    20992122    uint8_t uAck;
     
    21222145            if (pCtrlPktHdr->uCmd != VIRTIONET_CTRL_ANNOUNCE_ACK)
    21232146            {
    2124                 LogFunc(("%s Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE. Unrecognized uCmd\n", pThis->szInst));
     2147                LogFunc(("[%s] Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE. Unrecognized uCmd\n", pThis->szInst));
    21252148                break;
    21262149            }
    21272150            pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_ANNOUNCE;
    2128             Log7Func(("%s Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst));
     2151            Log7Func(("[%s] Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst));
    21292152            break;
    21302153        default:
     
    21712194}
    21722195
    2173 static int virtioNetR3ReadHeader(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame)
    2174 {
    2175     int rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pPktHdr, sizeof(*pPktHdr));
     2196static int virtioNetR3ReadHeader(PVIRTIOCORE pVirtio, PVIRTIONET pThis, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame)
     2197{
     2198    size_t cbPktHdr = virtioNetCalcPktHdrSize(pVirtio, pThis);
     2199    int rc = virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys, pPktHdr, cbPktHdr);
    21762200    if (RT_FAILURE(rc))
    21772201        return rc;
     
    22732297}
    22742298
    2275 static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
     2299static int virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    22762300                                         PVIRTIONETVIRTQ pTxVirtq, bool fOnWorkerThread)
    22772301{
     
    22822306    if (!pThis->fVirtioReady)
    22832307    {
    2284         LogFunc(("%s Ignoring Tx requests. VirtIO not ready (status=0x%x).\n",
     2308        LogFunc(("%s Ignoring Tx requests. VirtIO not ready (status=0x%x)\n",
    22852309                pThis->szInst, pThis->virtioNetConfig.uStatus));
    2286         return;
     2310        return VERR_IGNORED;
    22872311    }
    22882312
    22892313    if (!pThis->fCableConnected)
    22902314    {
    2291         Log(("%s Ignoring transmit requests while cable is disconnected.\n", pThis->szInst));
    2292         return;
     2315        Log(("[%s] Ignoring transmit requests while cable is disconnected.\n", pThis->szInst));
     2316        return VERR_IGNORED;
    22932317    }
    22942318
     
    22992323     */
    23002324    if (!ASMAtomicCmpXchgU32(&pThis->uIsTransmitting, 1, 0))
    2301         return;
     2325        return VERR_IGNORED;
    23022326
    23032327
     
    23112335        {
    23122336            ASMAtomicWriteU32(&pThis->uIsTransmitting, 0);
    2313             return;
     2337            return VERR_TRY_AGAIN;
    23142338        }
    23152339    }
     
    23182342    if (!cPkts)
    23192343    {
    2320         LogFunc(("%s No packets to send found on %s\n", pThis->szInst, pTxVirtq->szName));
     2344        LogFunc(("[%s] No packets to send found on %s\n", pThis->szInst, pTxVirtq->szName));
    23212345
    23222346        if (pDrv)
     
    23242348
    23252349        ASMAtomicWriteU32(&pThis->uIsTransmitting, 0);
    2326         return;
    2327     }
    2328     LogFunc(("%s About to transmit %d pending packet%c\n", pThis->szInst, cPkts, cPkts == 1 ? ' ' : 's'));
     2350        return VERR_MISSING;
     2351    }
     2352    LogFunc(("[%s] About to transmit %d pending packet%c\n", pThis->szInst, cPkts, cPkts == 1 ? ' ' : 's'));
    23292353
    23302354    virtioNetR3SetWriteLed(pThisCC, true);
     
    23342358    while ((rc = virtioCoreR3VirtqAvailBufPeek(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx, &pVirtqBuf)) == VINF_SUCCESS)
    23352359    {
    2336         Log10Func(("%s fetched descriptor chain from %s\n", pThis->szInst, pTxVirtq->szName));
     2360        Log10Func(("[%s] fetched descriptor chain from %s\n", pThis->szInst, pTxVirtq->szName));
    23372361
    23382362        PVIRTIOSGBUF pSgPhysSend = pVirtqBuf->pSgPhysSend;
    23392363        PVIRTIOSGSEG paSegsFromGuest = pSgPhysSend->paSegs;
    23402364        uint32_t cSegsFromGuest = pSgPhysSend->cSegs;
    2341 
    2342         VIRTIONETPKTHDR PktHdr;
    23432365        size_t uSize = 0;
    23442366
    2345         Assert(paSegsFromGuest[0].cbSeg >= sizeof(PktHdr));
     2367        size_t cbPktHdr = virtioNetCalcPktHdrSize(pVirtio, pThis);
     2368
     2369        AssertMsgReturn(paSegsFromGuest[0].cbSeg >= cbPktHdr,
     2370                        ("Desc chain's first seg has insufficient space for pkt header!\n"),
     2371                        VERR_INTERNAL_ERROR);
     2372
     2373        PVIRTIONETPKTHDR pPktHdr = (PVIRTIONETPKTHDR)RTMemAllocZ(cbPktHdr);
     2374        AssertMsgReturn(pPktHdr, ("Out of Memory\n"), VERR_NO_MEMORY);
    23462375
    23472376        /* Compute total frame size. */
     
    23492378            uSize +=  paSegsFromGuest[i].cbSeg;
    23502379
    2351         Log5Func(("%s complete frame is %u bytes.\n", pThis->szInst, uSize));
     2380        Log5Func(("[%s] complete frame is %u bytes.\n", pThis->szInst, uSize));
    23522381        Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE);
    23532382
     
    23602389            uint64_t uOffset;
    23612390
    2362             uSize -= sizeof(PktHdr);
    2363             rc = virtioNetR3ReadHeader(pDevIns, paSegsFromGuest[0].GCPhys, &PktHdr, uSize);
     2391            uSize -= cbPktHdr;
     2392            rc = virtioNetR3ReadHeader(pVirtio, pThis, pDevIns, paSegsFromGuest[0].GCPhys, pPktHdr, uSize);
    23642393            if (RT_FAILURE(rc))
    2365                 return;
    2366             virtioCoreGCPhysChainAdvance(pSgPhysSend, sizeof(PktHdr));
    2367 
    2368             PDMNETWORKGSO  Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr);
     2394                return rc;
     2395            virtioCoreGCPhysChainAdvance(pSgPhysSend, cbPktHdr);
     2396
     2397            PDMNETWORKGSO  Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, pPktHdr);
    23692398
    23702399            PPDMSCATTERGATHER pSgBufToPdmLeafDevice;
     
    23862415                    uint64_t srcSgCur   = (uint64_t)pSgPhysSend->GCPhysCur;
    23872416                    cbCopied = RT_MIN((uint64_t)cbRemain, srcSgLen - (srcSgCur - srcSgStart));
    2388                     PDMDevHlpPCIPhysRead(pDevIns,
     2417                    virtioCoreGCPhysRead(pVirtio, pDevIns,
    23892418                                         (RTGCPHYS)pSgPhysSend->GCPhysCur,
    23902419                                         ((uint8_t *)pSgBufToPdmLeafDevice->aSegs[0].pvSeg) + uOffset, cbCopied);
     
    23982427                     cbTotal, pVirtqBuf->cbPhysSend, pVirtqBuf->cbPhysSend - cbTotal));
    23992428
    2400                 rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, &PktHdr);
     2429                rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, pPktHdr);
    24012430                if (RT_FAILURE(rc))
    24022431                {
    2403                     LogFunc(("%s Failed to transmit frame, rc = %Rrc\n", pThis->szInst, rc));
     2432                    LogFunc(("[%s] Failed to transmit frame, rc = %Rrc\n", pThis->szInst, rc));
    24042433                    STAM_PROFILE_STOP(&pThis->StatTransmitSend, a);
    24052434                    STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
     
    24362465
    24372466    ASMAtomicWriteU32(&pThis->uIsTransmitting, 0);
     2467    return VINF_SUCCESS;
    24382468}
    24392469
     
    24502480    STAM_COUNTER_INC(&pThis->StatTransmitByNetwork);
    24512481
    2452     virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/);
     2482    (void)virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/);
    24532483}
    24542484
     
    24662496    virtioNetWakeupRxBufWaiter(pDevIns);
    24672497
    2468     LogFunc(("%s Link is up\n", pThis->szInst));
     2498    LogFunc(("[%s] Link is up\n", pThis->szInst));
    24692499
    24702500    if (pThisCC->pDrv)
     
    24962526        AssertRC(rc);
    24972527
    2498         LogFunc(("%s Link is down temporarily\n", pThis->szInst));
     2528        LogFunc(("[%s] Link is down temporarily\n", pThis->szInst));
    24992529    }
    25002530}
     
    25132543    if (LogIs7Enabled())
    25142544    {
    2515         LogFunc(("%s", pThis->szInst));
     2545        LogFunc(("[%s]", pThis->szInst));
    25162546        switch(enmState)
    25172547        {
     
    25482578        if (fRequestedLinkStateIsUp)
    25492579        {
    2550             Log(("%s Link is up\n", pThis->szInst));
     2580            Log(("[%s] Link is up\n", pThis->szInst));
    25512581            pThis->fCableConnected = true;
    25522582            SET_LINK_UP(pThis);
     
    25572587            /* The link was brought down explicitly, make sure it won't come up by timer.  */
    25582588            PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer);
    2559             Log(("%s Link is down\n", pThis->szInst));
     2589            Log(("[%s] Link is down\n", pThis->szInst));
    25602590            pThis->fCableConnected = false;
    25612591            SET_LINK_DOWN(pThis);
     
    25802610static int virtioNetR3DestroyWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    25812611{
    2582     Log10Func(("%s\n", pThis->szInst));
     2612    Log10Func(("[%s]\n", pThis->szInst));
    25832613    int rc = VINF_SUCCESS;
    25842614    for (unsigned uIdxWorker = 0; uIdxWorker < pThis->cWorkers; uIdxWorker++)
     
    26082638                                            PVIRTIONETVIRTQ pVirtq)
    26092639{
    2610     Log10Func(("%s\n", pThis->szInst));
     2640    Log10Func(("[%s]\n", pThis->szInst));
    26112641    RT_NOREF(pThis);
    26122642
     
    26372667static int virtioNetR3CreateWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    26382668{
    2639 
    2640 
    2641     Log10Func(("%s\n", pThis->szInst));
     2669    Log10Func(("[%s]\n", pThis->szInst));
     2670    int rc;
     2671
     2672
     2673    /* Create the Control Queue worker anyway whether or not it is feature-negotiated or utilized by the guest,
     2674     * as it's relatively low overhead resource-wise.  This is for two reasons: First, at the time of this comment
     2675     * queues and workers are configured pre-feature negotiation; secondly, legacy guest drivers are allowed to start
     2676     * using the device prior to feature negotiation, and we can only know we are dealing with a modern guest driver
     2677     * after feature negotiation. */
    26422678
    26432679    PVIRTIONETVIRTQ pCtlVirtq = &pThis->aVirtqs[CTRLQIDX];
    2644     int rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis,
    2645                                               &pThis->aWorkers[CTRLQIDX], &pThisCC->aWorkers[CTRLQIDX], pCtlVirtq);
     2680    rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis,
     2681                                          &pThis->aWorkers[CTRLQIDX], &pThisCC->aWorkers[CTRLQIDX], pCtlVirtq);
    26462682    AssertRCReturn(rc, rc);
    26472683
     
    26542690
    26552691        rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, &pThis->aWorkers[TXQIDX(uVirtqPair)],
    2656                                                               &pThisCC->aWorkers[TXQIDX(uVirtqPair)], pTxVirtq);
     2692                                              &pThisCC->aWorkers[TXQIDX(uVirtqPair)], pTxVirtq);
    26572693        AssertRCReturn(rc, rc);
    26582694
     
    26652701
    26662702    pThis->cWorkers = pThis->cVirtqPairs + 1 /* One control virtq */;
     2703
    26672704    return rc;
    26682705}
     
    26862723        return VINF_SUCCESS;
    26872724
    2688     LogFunc(("%s worker thread idx=%d started for %s (virtq idx=%d)\n", pThis->szInst,  pWorker->uIdx, pVirtq->szName, pVirtq->uIdx));
     2725    LogFunc(("[%s] worker thread idx=%d started for %s (virtq idx=%d)\n", pThis->szInst,  pWorker->uIdx, pVirtq->szName, pVirtq->uIdx));
    26892726
    26902727    /** @todo Race w/guest enabling/disabling guest notifications cyclically.
     
    27032740            if (!fNotificationSent)
    27042741            {
    2705                 Log10Func(("%s %s worker sleeping...\n\n", pThis->szInst, pVirtq->szName));
     2742                Log10Func(("[%s] %s worker sleeping...\n\n", pThis->szInst, pVirtq->szName));
    27062743                Assert(ASMAtomicReadBool(&pWorker->fSleeping));
    27072744
     
    27232760         if (pVirtq->fCtlVirtq)
    27242761         {
    2725              Log10Func(("%s %s worker woken. Fetching desc chain\n", pThis->szInst, pVirtq->szName));
     2762             Log10Func(("[%s] %s worker woken. Fetching desc chain\n", pThis->szInst, pVirtq->szName));
    27262763             PVIRTQBUF pVirtqBuf = NULL;
    27272764             int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pVirtq->uIdx, &pVirtqBuf, true);
    27282765             if (rc == VERR_NOT_AVAILABLE)
    27292766             {
    2730                 Log10Func(("%s %s worker woken. Nothing found in queue/n", pThis->szInst, pVirtq->szName));
     2767                Log10Func(("[%s] %s worker woken. Nothing found in queue/n", pThis->szInst, pVirtq->szName));
    27312768                continue;
    27322769             }
     
    27362773         else /* Must be Tx queue */
    27372774         {
    2738              Log10Func(("%s %s worker woken. Virtq has data to transmit\n",  pThis->szInst, pVirtq->szName));
     2775             Log10Func(("[%s] %s worker woken. Virtq has data to transmit\n",  pThis->szInst, pVirtq->szName));
    27392776             virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */);
    27402777         }
     
    27462783          */
    27472784    }
    2748     Log10(("%s %s worker thread exiting\n", pThis->szInst, pVirtq->szName));
     2785    Log10(("[%s] %s worker thread exiting\n", pThis->szInst, pVirtq->szName));
    27492786    return VINF_SUCCESS;
    27502787}
     
    27532790 * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged}
    27542791 */
    2755 static DECLCALLBACK(void) virtioNetR3StatusChanged(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady)
     2792static DECLCALLBACK(void) virtioNetR3StatusChg(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady)
    27562793{
    27572794    PVIRTIONET     pThis     = RT_FROM_MEMBER(pVirtio,  VIRTIONET, Virtio);
     
    27622799    if (fVirtioReady)
    27632800    {
    2764         LogFunc(("%s VirtIO ready\n-----------------------------------------------------------------------------------------\n",
    2765                  pThis->szInst));
     2801        Log(("-----------------------------------------------------------------------------------------\n"));
     2802        Log(("%-23s: %s *** VirtIO Ready ***\n-----------------------------------------------------------------------------------------\n",
     2803                 __FUNCTION__, pThis->szInst));
    27662804
    27672805        pThis->fNegotiatedFeatures = virtioCoreGetNegotiatedFeatures(pVirtio);
     
    27762814        pThis->fResetting = false;
    27772815
    2778         for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
     2816        for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    27792817        {
    27802818            PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr];
     
    27942832    else
    27952833    {
    2796         LogFunc(("%s VirtIO is resetting\n", pThis->szInst));
     2834        Log(("%-23s: %s VirtIO is resetting\n", __FUNCTION__, pThis->szInst));
    27972835
    27982836        pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0;
    2799         Log7Func(("%s Link is %s\n", pThis->szInst, pThis->fCableConnected ? "up" : "down"));
     2837        Log7(("%-23s: %s Link is %s\n", __FUNCTION__, pThis->szInst, pThis->fCableConnected ? "up" : "down"));
    28002838
    28012839        pThis->fPromiscuous         = true;
     
    28152853        pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, true);
    28162854
    2817         for (uint16_t uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
     2855        for (uint16_t uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    28182856            pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore = false;
    28192857    }
     
    28342872    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    28352873
    2836     Log7Func(("%s\n", pThis->szInst));
     2874    Log7Func(("[%s]\n", pThis->szInst));
     2875    RT_NOREF(pThis);
     2876
    28372877    AssertLogRelReturnVoid(iLUN == 0);
    28382878
    2839     RT_NOREF(pThis);
    2840 
    2841     /*
    2842      * Zero important members.
    2843      */
    28442879    pThisCC->pDrvBase = NULL;
    28452880    pThisCC->pDrv     = NULL;
     
    28582893    RT_NOREF(fFlags);
    28592894
    2860     Log7Func(("%s", pThis->szInst));
     2895    Log7Func(("[%s]", pThis->szInst));
    28612896
    28622897    AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
     
    28732908    else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
    28742909             || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
    2875                     Log(("%s No attached driver!\n", pThis->szInst));
     2910                    Log(("[%s] No attached driver!\n", pThis->szInst));
    28762911
    28772912    return rc;
     
    28972932{
    28982933    PVIRTIONETR3 pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, IBase);
    2899 LogFunc(("pInterface=%p %s\n", pInterface, pszIID));
    29002934    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN,   &pThisCC->INetworkDown);
    29012935    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig);
     
    29152949    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    29162950
    2917     Log(("%s Destroying instance\n", pThis->szInst));
     2951    Log(("[%s] Destroying instance\n", pThis->szInst));
    29182952
    29192953    if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT)
     
    29452979     */
    29462980    Log7Func(("PDM device instance: %d\n", iInstance));
    2947 
    2948     RTStrPrintf(pThis->szInst, sizeof(pThis->szInst), "VNET%d", iInstance);
    2949 
    2950     /** @todo Remove next line (temporary hack used for less logging clutter for single-instance debugging) */
    2951     *pThis->szInst = '\0';
     2981    RTStrPrintf(pThis->szInst, sizeof(pThis->szInst), "virtio-net #%d", iInstance);
    29522982
    29532983    pThisCC->pDevIns     = pDevIns;
    2954 
    29552984    pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface;
    29562985    pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed;
     
    29973026                pThis->szInst, pThis->cMsLinkUpDelay / 1000));
    29983027
    2999     Log(("%s Link up delay is set to %u seconds\n", pThis->szInst, pThis->cMsLinkUpDelay / 1000));
     3028    Log(("[%s] Link up delay is set to %u seconds\n", pThis->szInst, pThis->cMsLinkUpDelay / 1000));
    30003029
    30013030    /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */
    30023031    memcpy(pThis->virtioNetConfig.uMacAddress.au8, pThis->macConfigured.au8, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */
    30033032
     3033    Log(("Using MAC address for %s: %2x:%2x:%2x:%2x:%2x:%2x\n", pThis->szInst,
     3034            pThis->macConfigured.au8[0], pThis->macConfigured.au8[1], pThis->macConfigured.au8[2],
     3035            pThis->macConfigured.au8[3], pThis->macConfigured.au8[4], pThis->macConfigured.au8[5]));
    30043036
    30053037    LogFunc(("RC=%RTbool R0=%RTbool\n", pDevIns->fRCEnabled, pDevIns->fR0Enabled));
     
    30153047
    30163048    pThisCC->Virtio.pfnVirtqNotified        = virtioNetVirtqNotified;
    3017     pThisCC->Virtio.pfnStatusChanged        = virtioNetR3StatusChanged;
     3049    pThisCC->Virtio.pfnStatusChanged        = virtioNetR3StatusChg;
    30183050    pThisCC->Virtio.pfnDevCapRead           = virtioNetR3DevCapRead;
    30193051    pThisCC->Virtio.pfnDevCapWrite          = virtioNetR3DevCapWrite;
     
    30333065        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create event semaphore"));
    30343066
     3067
    30353068    /* Initialize VirtIO core. (pfnStatusChanged callback when both host VirtIO core & guest driver are ready) */
    30363069    rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInst,
     
    30443077        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated."));
    30453078
     3079
     3080    /*
     3081     * Initialize queues.  Due to this being a transitional device (e.g. accommodating both modern
     3082     * and legacy drivers), the control queue must be created whether or not the VIRTIO_NET_F_CTRL_VQ
     3083     * is negotiated, because legacy drivers are not bound to begin configuration and I/O until
     3084     * feature negotiation is complete.  In the final analysis, there may be no good reason to
     3085     * enforce VIRTIO_NET_F_CTRL_VQ as a prerequisite to handling guest control queue transactions,
     3086     * but merely to log violations (e.g. control transactions without feature explicitly enabled),
     3087     * once, thus not being strict with regard to misbehaving modern drivers.
     3088     */
     3089
    30463090    pThis->cVirtqPairs = 1;  /* default, VirtIO 1.0, 5.1.6.5.5 */
    3047 
    3048     pThis->cVirtVirtqs += pThis->cVirtqPairs * 2 + 1;
    3049 
    3050     /* Create Link Up Timer */
    3051     rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, virtioNetR3LinkUpTimer, NULL,
    3052                               TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
    3053                               "VirtioNet Link Up", &pThisCC->hLinkUpTimer);
    3054 
    3055     /*
    3056      * Initialize queues.
    3057      */
     3091    pThis->cVirtqs += pThis->cVirtqPairs * 2 + 1;
     3092    pThis->aVirtqs[CTRLQIDX].fCtlVirtq = true;
     3093
    30583094    virtioNetR3SetVirtqNames(pThis);
    3059     pThis->aVirtqs[CTRLQIDX].fCtlVirtq = true;
    3060     for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++)
     3095    for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    30613096    {
    30623097        PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr];
     
    30673102        pWorkerR3->uIdx = uVirtqNbr;
    30683103    }
    3069 
    30703104    /*
    30713105     * Create queue workers for life of instance. (I.e. they persist through VirtIO bounces)
     
    30753109        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create worker threads"));
    30763110
    3077 
     3111    /* Create Link Up Timer */
     3112    rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, virtioNetR3LinkUpTimer, NULL,
     3113                              TMTIMER_FLAGS_NO_CRIT_SECT | TMTIMER_FLAGS_NO_RING0,
     3114                              "VirtioNet Link Up", &pThisCC->hLinkUpTimer);
    30783115    /*
    30793116     * Attach network driver instance
     
    30883125    else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
    30893126             || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
    3090                     Log(("%s No attached driver!\n", pThis->szInst));
    3091 
     3127                    Log(("[%s] No attached driver!\n", pThis->szInst));
    30923128    /*
    30933129     * Status driver
     
    31113147     * The /Public/ bits are official and used by session info in the GUI.
    31123148     */
     3149# ifdef VBOX_WITH_STATISTICS
    31133150    PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatReceiveBytes,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
    31143151                           "Amount of data received",    "/Public/NetAdapter/%u/BytesReceived", uStatNo);
     
    31243161    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTransmitGSO,         STAMTYPE_COUNTER, "Packets/Transmit-Gso",   STAMUNIT_COUNT,          "Number of sent GSO packets");
    31253162    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTransmitCSum,        STAMTYPE_COUNTER, "Packets/Transmit-Csum",  STAMUNIT_COUNT,          "Number of completed TX checksums");
    3126 # ifdef VBOX_WITH_STATISTICS
    31273163    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatReceive,             STAMTYPE_PROFILE, "Receive/Total",          STAMUNIT_TICKS_PER_CALL, "Profiling receive");
    31283164    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatReceiveStore,        STAMTYPE_PROFILE, "Receive/Store",          STAMUNIT_TICKS_PER_CALL, "Profiling receive storing");
  • trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp

    r90791 r91703  
    358358{
    359359    R3PTRTYPE(PPDMTHREAD)           pThread;                    /**< pointer to worker thread's handle                 */
    360     uint16_t                        auRedoDescs[VIRTQ_MAX_ENTRIES];/**< List of previously suspended reqs to re-submit    */
     360    uint16_t                        auRedoDescs[VIRTQ_SIZE];/**< List of previously suspended reqs to re-submit    */
    361361    uint16_t                        cRedoDescs;                 /**< Number of redo desc chain head desc idxes in list */
    362362} VIRTIOSCSIWORKERR3;
     
    457457    uint32_t                        fHasT10pi;
    458458
    459     /** True if VIRTIO_SCSI_F_T10_PI was negotiated */
     459    /** True if VIRTIO_SCSI_F_HOTPLUG was negotiated */
    460460    uint32_t                        fHasHotplug;
    461461
    462     /** True if VIRTIO_SCSI_F_T10_PI was negotiated */
     462    /** True if VIRTIO_SCSI_F_INOUT was negotiated */
    463463    uint32_t                        fHasInOutBufs;
    464464
    465     /** True if VIRTIO_SCSI_F_T10_PI was negotiated */
     465    /** True if VIRTIO_SCSI_F_CHANGE was negotiated */
    466466    uint32_t                        fHasLunChange;
    467467
     
    559559    uint16_t                       uVirtqNbr;                   /**< Index of queue this request arrived on            */
    560560    PVIRTQBUF                      pVirtqBuf;                   /**< Prepared desc chain pulled from virtq avail ring  */
    561     size_t                         cbDataIn;                    /**< size of dataout buffer                            */
     561    size_t                         cbDataIn;                    /**< size of datain buffer                             */
    562562    size_t                         cbDataOut;                   /**< size of dataout buffer                            */
    563563    uint16_t                       uDataInOff;                  /**< Fixed size of respHdr + sense (precede datain)    */
    564     uint16_t                       uDataOutOff;                 /**< Fixed size of respHdr + sense (precede datain)    */
     564    uint16_t                       uDataOutOff;                 /**< Fixed size of reqhdr + cdb (precede dataout)      */
    565565    uint32_t                       cbSenseAlloc;                /**< Size of sense buffer                              */
    566566    size_t                         cbSenseLen;                  /**< Receives \# bytes written into sense buffer       */
     
    828828    RTSGSEG aReqSegs[2];
    829829
    830     /* Segment #1: Request header*/
     830    /* Segment #1: Response header*/
    831831    aReqSegs[0].pvSeg = pRespHdr;
    832832    aReqSegs[0].cbSeg = sizeof(*pRespHdr);
     
    11641164     */
    11651165    size_t const cbReqHdr = sizeof(REQ_CMD_HDR_T) + cbCdb;
    1166     AssertReturn(pVirtqBuf->cbPhysSend >= cbReqHdr, VERR_INVALID_PARAMETER);
     1166    AssertReturn(pVirtqBuf && pVirtqBuf->cbPhysSend >= cbReqHdr, VERR_INVALID_PARAMETER);
    11671167
    11681168    AssertCompile(VIRTIOSCSI_CDB_SIZE_MAX < 4096);
     
    17141714        /*
    17151715         * BIOS may change these values. When the OS comes up, and KVM driver accessed
    1716          * through the Windows, assumes they are the default size. So as per the VirtIO 1.0 spec,
     1716         * through Windows, it assumes they are the default size. So as per the VirtIO 1.0 spec,
    17171717         * 5.6.4, these device configuration values must be set to default upon device reset.
    17181718         */
     
    19581958        rc = pHlp->pfnSSMGetU16(pSSM, &cReqsRedo);
    19591959        AssertRCReturn(rc, rc);
    1960         AssertReturn(cReqsRedo < VIRTQ_MAX_ENTRIES,
     1960        AssertReturn(cReqsRedo < VIRTQ_SIZE,
    19611961                     pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    19621962                                              N_("Bad count of I/O transactions to re-do in saved state (%#x, max %#x - 1)"),
    1963                                               cReqsRedo, VIRTQ_MAX_ENTRIES));
     1963                                              cReqsRedo, VIRTQ_SIZE));
    19641964
    19651965        for (uint16_t uVirtqNbr = VIRTQ_REQ_BASE; uVirtqNbr < VIRTIOSCSI_VIRTQ_CNT; uVirtqNbr++)
     
    19821982            rc = pHlp->pfnSSMGetU16(pSSM, &idxHead);
    19831983            AssertRCReturn(rc, rc);
    1984             AssertReturn(idxHead < VIRTQ_MAX_ENTRIES,
     1984            AssertReturn(idxHead < VIRTQ_SIZE,
    19851985                         pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    19861986                                                  N_("Bad queue element index for re-do in saved state (%#x, max %#x)"),
    1987                                                   idxHead, VIRTQ_MAX_ENTRIES - 1));
     1987                                                  idxHead, VIRTQ_SIZE - 1));
    19881988
    19891989            PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[uVirtqNbr];
    19901990            pWorkerR3->auRedoDescs[pWorkerR3->cRedoDescs++] = idxHead;
    1991             pWorkerR3->cRedoDescs %= VIRTQ_MAX_ENTRIES;
     1991            pWorkerR3->cRedoDescs %= VIRTQ_SIZE;
    19921992        }
    19931993    }
  • trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp

    r88828 r91703  
    4545#define VIRTQNAME(a_pVirtio, a_uVirtq)      ((a_pVirtio)->aVirtqueues[(a_uVirtq)].szName)
    4646
     47
     48#define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq) \
     49            (virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq) == 0)
     50
     51
    4752#define IS_DRIVER_OK(a_pVirtio)             ((a_pVirtio)->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
    48 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq) \
    49             (virtioCoreVirtqAvailBufCount_inline(pDevIns, pVirtio, pVirtq) == 0)
     53#define WAS_DRIVER_OK(a_pVirtio)            ((a_pVirtio)->fPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
    5054
    5155/**
     
    149153                                uint32_t idxDesc, PVIRTQ_DESC_T pDesc)
    150154{
    151     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    152     RT_NOREF(pVirtio);
    153     uint16_t const cVirtqItems = RT_MAX(pVirtq->uSize, 1); /* Make sure to avoid div-by-zero. */
    154     PDMDevHlpPCIPhysRead(pDevIns,
    155                       pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
    156                       pDesc, sizeof(VIRTQ_DESC_T));
     155    AssertMsg(IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     156    uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */
     157
     158        virtioCoreGCPhysRead(pVirtio, pDevIns,
     159                          pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
     160                          pDesc, sizeof(VIRTQ_DESC_T));
    157161}
    158162#endif
     
    165169{
    166170    uint16_t uDescIdx;
    167     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    168     RT_NOREF(pVirtio);
    169     uint16_t const cVirtqItems = RT_MAX(pVirtq->uSize, 1); /* Make sure to avoid div-by-zero. */
    170     PDMDevHlpPCIPhysRead(pDevIns,
     171
     172    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     173    uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */
     174    virtioCoreGCPhysRead(pVirtio, pDevIns,
    171175                         pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[availIdx % cVirtqItems]),
    172176                         &uDescIdx, sizeof(uDescIdx));
     
    178182    uint16_t uUsedEventIdx;
    179183    /* VirtIO 1.0 uUsedEventIdx (used_event) immediately follows ring */
    180     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    181     RT_NOREF(pVirtio);
    182     PDMDevHlpPCIPhysRead(pDevIns,
    183                          pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uSize]),
     184    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     185    virtioCoreGCPhysRead(pVirtio, pDevIns,
     186                         pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uQueueSize]),
    184187                         &uUsedEventIdx, sizeof(uUsedEventIdx));
    185188    return uUsedEventIdx;
     
    190193{
    191194    uint16_t uIdx = 0;
    192     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    193     RT_NOREF(pVirtio);
    194     PDMDevHlpPCIPhysRead(pDevIns,
     195    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     196    virtioCoreGCPhysRead(pVirtio, pDevIns,
    195197                         pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, uIdx),
    196198                         &uIdx, sizeof(uIdx));
     
    201203{
    202204    uint16_t fFlags = 0;
    203     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    204     RT_NOREF(pVirtio);
    205     PDMDevHlpPCIPhysRead(pDevIns,
     205    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     206    virtioCoreGCPhysRead(pVirtio, pDevIns,
    206207                         pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
    207208                         &fFlags, sizeof(fFlags));
     209
    208210    return fFlags;
    209211}
     
    220222{
    221223    VIRTQ_USED_ELEM_T elem = { uDescIdx,  uLen };
    222     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    223     RT_NOREF(pVirtio);
    224     uint16_t const cVirtqItems = RT_MAX(pVirtq->uSize, 1); /* Make sure to avoid div-by-zero. */
    225     PDMDevHlpPCIPhysWrite(pDevIns,
     224    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     225    uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */
     226    virtioCoreGCPhysWrite(pVirtio, pDevIns,
    226227                          pVirtq->GCPhysVirtqUsed
    227228                        + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[usedIdx % cVirtqItems]),
     
    231232DECLINLINE(void) virtioWriteUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq, uint16_t fFlags)
    232233{
    233     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    234     RT_NOREF(pVirtio);
     234    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
    235235    RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
    236     PDMDevHlpPCIPhysWrite(pDevIns,
     236    virtioCoreGCPhysWrite(pVirtio, pDevIns,
    237237                          pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
    238238                          &fFlags, sizeof(fFlags));
     
    242242DECLINLINE(void) virtioWriteUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq, uint16_t uIdx)
    243243{
    244     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    245     RT_NOREF(pVirtio);
    246     PDMDevHlpPCIPhysWrite(pDevIns,
     244    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     245    RT_UNTRUSTED_VALIDATED_FENCE(); /* VirtIO 1.0, Section 3.2.1.4.1 */
     246    virtioCoreGCPhysWrite(pVirtio, pDevIns,
    247247                          pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    248248                          &uIdx, sizeof(uIdx));
     
    254254{
    255255    uint16_t uIdx = 0;
    256     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    257     RT_NOREF(pVirtio);
    258     PDMDevHlpPCIPhysRead(pDevIns,
     256    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     257    virtioCoreGCPhysRead(pVirtio, pDevIns,
    259258                         pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, uIdx),
    260259                         &uIdx, sizeof(uIdx));
     
    265264{
    266265    uint16_t fFlags = 0;
    267     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    268     RT_NOREF(pVirtio);
    269     PDMDevHlpPCIPhysRead(pDevIns,
     266    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     267    virtioCoreGCPhysRead(pVirtio, pDevIns,
    270268                         pVirtq->GCPhysVirtqUsed + RT_UOFFSETOF(VIRTQ_USED_T, fFlags),
    271269                         &fFlags, sizeof(fFlags));
     
    276274{
    277275    /** VirtIO 1.0 uAvailEventIdx (avail_event) immediately follows ring */
    278     AssertMsg(pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK, ("Called with guest driver not ready\n"));
    279     RT_NOREF(pVirtio);
    280     PDMDevHlpPCIPhysWrite(pDevIns,
     276    AssertMsg(pVirtio->fLegacyDriver || IS_DRIVER_OK(pVirtio), ("Called with guest driver not ready\n"));
     277    virtioCoreGCPhysWrite(pVirtio, pDevIns,
    281278                          pVirtq->GCPhysVirtqUsed
    282                         + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtq->uSize]),
     279                        + RT_UOFFSETOF_DYN(VIRTQ_USED_T, aRing[pVirtq->uQueueSize]),
    283280                          &uAvailEventIdx, sizeof(uAvailEventIdx));
    284281}
    285282#endif
    286283
    287 DECLINLINE(uint16_t) virtioCoreVirtqAvailBufCount_inline(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq)
     284DECLINLINE(uint16_t) virtioCoreVirtqAvailCnt(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq)
    288285{
    289286    uint16_t uIdxActual = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtq);
     
    292289
    293290    if (uIdxActual < uIdxShadow)
    294         uIdxDelta = (uIdxActual + VIRTQ_MAX_ENTRIES) - uIdxShadow;
     291        uIdxDelta = (uIdxActual + VIRTQ_SIZE) - uIdxShadow;
    295292    else
    296293        uIdxDelta = uIdxActual - uIdxShadow;
    297294
    298     LogFunc(("%s has %u %s (idx=%u shadow=%u)\n",
    299         pVirtq->szName, uIdxDelta, uIdxDelta == 1 ? "entry" : "entries",
    300         uIdxActual, uIdxShadow));
     295    LogFunc(("%s, %u %s\n",
     296        pVirtq->szName, uIdxDelta, uIdxDelta == 1 ? "entry" : "entries"));
    301297
    302298    return uIdxDelta;
     
    316312    AssertMsgReturn(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues), ("uVirtq out of range"), 0);
    317313    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    318     if (!IS_DRIVER_OK(pVirtio) || !pVirtq->uEnable)
    319     {
    320         LogRelFunc(("Driver not ready or queue not enabled\n"));
     314
     315    if (!IS_DRIVER_OK(pVirtio))
     316    {
     317        LogRelFunc(("Driver not ready\n"));
    321318        return 0;
    322319    }
    323 
    324     return virtioCoreVirtqAvailBufCount_inline(pDevIns, pVirtio, pVirtq);
     320    if (!pVirtio->fLegacyDriver && !pVirtq->uEnable)
     321    {
     322        LogRelFunc(("virtq: %d (%s) not enabled\n", uVirtq, VIRTQNAME(pVirtio, uVirtq)));
     323        return 0;
     324    }
     325
     326    return virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq);
    325327}
    326328
     
    414416void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle)
    415417{
     418    PVIRTIOCORE pVirtio = PDMDEVINS_2_DATA(pDevIns, PVIRTIOCORE);
    416419#define ADJCURSOR(cb) pszOut += cb; cbRemain -= cb;
    417420    size_t cbPrint = 0, cbRemain = ((cb / 16) + 1) * 80;
     
    431434        {
    432435           uint32_t idx = row * 16 + col;
    433            PDMDevHlpPCIPhysRead(pDevIns, GCPhys + idx, &c, 1);
     436           virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys + idx, &c, 1);
    434437           if (idx >= cb)
    435438               cbPrint = RTStrPrintf(pszOut, cbRemain, "-- %s", (col + 1) % 8 ? "" : "  ");
     
    440443        for (uint16_t idx = row * 16; idx < row * 16 + 16; idx++)
    441444        {
    442            PDMDevHlpPCIPhysRead(pDevIns, GCPhys + idx, &c, 1);
     445           virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys + idx, &c, 1);
    443446           cbPrint = RTStrPrintf(pszOut, cbRemain, "%c", (idx >= cb) ? ' ' : (c >= 0x20 && c <= 0x7e ? c : '.'));
    444447           ADJCURSOR(cbPrint);
     
    455458
    456459/** API function: See header file */
     460int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio)
     461{
     462    Log12Func(("%s", pVirtio->fLegacyDriver ? "Legacy Guest Driver handling mode\n" : ""));
     463    return pVirtio->fLegacyDriver;
     464}
     465
     466/** API function: See header file */
    457467void virtioCoreLogMappedIoValue(const char *pszFunc, const char *pszMember, uint32_t uMemberSize,
    458468                                const void *pv, uint32_t cb, uint32_t uOffset, int fWrite,
     
    553563int virtioCoreR3VirtqAttach(PVIRTIOCORE pVirtio, uint16_t uVirtq, const char *pcszName)
    554564{
    555     LogFunc(("%s\n", pcszName));
     565    LogFunc(("Attaching %s to VirtIO core\n", pcszName));
    556566    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    557567    pVirtq->uVirtq = uVirtq;
     
    596606    bool fUsedNoNotify       = virtioReadUsedRingFlags(pDevIns, pVirtio, pVirtq) & VIRTQ_USED_F_NO_NOTIFY;
    597607
    598 
    599608    pHlp->pfnPrintf(pHlp, "       queue enabled: ........... %s\n", pVirtq->uEnable ? "true" : "false");
    600     pHlp->pfnPrintf(pHlp, "       size: .................... %d\n", pVirtq->uSize);
     609    pHlp->pfnPrintf(pHlp, "       size: .................... %d\n", pVirtq->uQueueSize);
    601610    pHlp->pfnPrintf(pHlp, "       notify offset: ........... %d\n", pVirtq->uNotifyOffset);
    602611    if (pVirtio->fMsiSupport)
    603         pHlp->pfnPrintf(pHlp, "       MSIX vector: ....... %4.4x\n", pVirtq->uMsix);
     612        pHlp->pfnPrintf(pHlp, "       MSIX vector: ....... %4.4x\n", pVirtq->uMsixVector);
    604613    pHlp->pfnPrintf(pHlp, "\n");
    605614    pHlp->pfnPrintf(pHlp, "       avail ring (%d entries):\n", uAvailIdx - uAvailIdxShadow);
     
    684693    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    685694
    686     if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
     695    if (IS_DRIVER_OK(pVirtio))
    687696    {
    688697        uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, pVirtq);
     
    702711    LogFunc(("\n"));
    703712    pVirtio->fDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
    704     if (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
    705     {
    706         pVirtio->fGenUpdatePending = true;
     713    if (IS_DRIVER_OK(pVirtio))
     714    {
     715        if (!pVirtio->fLegacyDriver)
     716            pVirtio->fGenUpdatePending = true;
    707717        virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
    708718    }
     
    722732    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    723733
    724     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
    725                     ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
     734    if (!pVirtio->fLegacyDriver)
     735        AssertMsgReturn((pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) && pVirtq->uEnable,
     736            ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    726737
    727738    if (IS_VIRTQ_EMPTY(pVirtio->pDevInsR3, pVirtio, pVirtq))
     
    747758    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    748759
    749     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
    750                     ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
     760    if (!pVirtio->fLegacyDriver)
     761        AssertMsgReturn((pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) && pVirtq->uEnable,
     762            ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    751763
    752764    uint16_t uDescIdx = uHeadIdx;
    753765
    754     Log6Func(("%s DESC CHAIN: (head) desc_idx=%u\n", pVirtio->aVirtqueues[uVirtq].szName, uHeadIdx));
     766    Log6Func(("%s DESC CHAIN: (head idx = %u)\n", pVirtio->aVirtqueues[uVirtq].szName, uHeadIdx));
    755767
    756768    /*
     
    788800         * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
    789801         */
    790         if (cSegsIn + cSegsOut >= VIRTQ_MAX_ENTRIES)
     802        if (cSegsIn + cSegsOut >= VIRTQ_SIZE)
    791803        {
    792804            static volatile uint32_t s_cMessages  = 0;
     
    807819        if (desc.fFlags & VIRTQ_DESC_F_WRITE)
    808820        {
    809             Log6Func(("%s IN  desc_idx=%u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
     821            Log6Func(("%s IN  idx=%u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
    810822            cbIn += desc.cb;
    811823            pSeg = &paSegsIn[cSegsIn++];
     
    893905    AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    894906
    895     Log6Func(("Copying client data to %s, desc chain (head desc_idx %d)\n",
    896               VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
     907    Log6Func(("    Copying device data to %s (%s guest), desc chain idx %d\n",
     908              VIRTQNAME(pVirtio, uVirtq), pVirtio->fLegacyDriver ? "legacy" : "modern", virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
    897909
    898910    /* Copy s/g buf (virtual memory) to guest phys mem (IN direction). */
     
    910922            cbCopy = RT_MIN(pSgVirtReturn->cbSegLeft,  pSgPhysReturn->cbSegLeft);
    911923            Assert(cbCopy > 0);
    912             PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->GCPhysCur, pSgVirtReturn->pvSegCur, cbCopy);
     924            virtioCoreGCPhysWrite(pVirtio, pDevIns, (RTGCPHYS)pSgPhysReturn->GCPhysCur, pSgVirtReturn->pvSegCur, cbCopy);
    913925            RTSgBufAdvance(pSgVirtReturn, cbCopy);
    914926            virtioCoreGCPhysChainAdvance(pSgPhysReturn, cbCopy);
     
    922934    }
    923935
    924     /* If this write-ahead crosses threshold where the driver wants to get an event flag it */
     936    /* If this write-ahead crosses threshold where the driver wants to get an event, flag it */
    925937    if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
    926938        if (pVirtq->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq))
     
    933945
    934946    if (pSgVirtReturn)
    935         Log6Func((".... Copied %zu bytes in %d segs to %u byte buffer, residual=%zu\n",
    936                   cbTotal - cbRemain, pSgVirtReturn->cSegs, pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal));
    937 
    938     Log6Func(("Write ahead used_idx=%u, %s used_idx=%u\n",
    939               pVirtq->uUsedIdxShadow, VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
     947        Log6Func(("     ... %d segs, %zu bytes, copied to %u byte buf. residual: %zu bytes\n",
     948                  pSgVirtReturn->cSegs, cbTotal - cbRemain,  pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal));
     949
     950    Log6Func(("    %s used_idx=%u\n", VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
    940951
    941952    return VINF_SUCCESS;
     
    951962    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    952963
    953     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtq->uEnable,
    954                     ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    955 
    956     Log6Func(("Updating %s used_idx to %u\n", pVirtq->szName, pVirtq->uUsedIdxShadow));
     964    if (!pVirtio->fLegacyDriver)
     965        AssertMsgReturn((pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) && pVirtq->uEnable,
     966            ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
     967
     968    Log6Func(("    %s ++used_idx=%u\n", pVirtq->szName, pVirtq->uUsedIdxShadow));
    957969
    958970    virtioWriteUsedRingIdx(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow);
     
    976988    PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
    977989
    978 
    979990    /* See VirtIO 1.0, section 4.1.5.2 It implies that uVirtq and uNotifyIdx should match.
    980991     * Disregarding this notification may cause throughput to stop, however there's no way to know
     
    9901001
    9911002    Log6Func(("%s (desc chains: %u)\n", pVirtq->szName,
    992         virtioCoreVirtqAvailBufCount_inline(pDevIns, pVirtio, pVirtq)));
     1003        virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq)));
    9931004
    9941005    /* Inform client */
     
    10271038                   pVirtq->szName, (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq)));
    10281039#endif
    1029             virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsix);
     1040            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
    10301041            pVirtq->fUsedRingEvent = false;
    10311042            return;
     
    10411052        if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, pVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT))
    10421053        {
    1043             virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsix);
     1054            virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
    10441055            return;
    10451056        }
     
    10561067 * @param   uVec        MSI-X vector, if enabled
    10571068 */
    1058 static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixtor)
     1069static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixVector)
    10591070{
    10601071    if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
     
    10691080        PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_HIGH);
    10701081    }
    1071     else if (uMsixtor != VIRTIO_MSI_NO_VECTOR)
    1072         PDMDevHlpPCISetIrq(pDevIns, uMsixtor, 1);
     1082    else if (uMsixVector != VIRTIO_MSI_NO_VECTOR)
     1083        PDMDevHlpPCISetIrq(pDevIns, uMsixVector, 1);
    10731084    return VINF_SUCCESS;
    10741085}
     
    10791090 * @param   pDevIns     The device instance.
    10801091 */
    1081 static void virtioLowerInterrupt(PPDMDEVINS pDevIns, uint16_t uMsixtor)
     1092static void virtioLowerInterrupt(PPDMDEVINS pDevIns, uint16_t uMsixVector)
    10821093{
    10831094    PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
    10841095    if (!pVirtio->fMsiSupport)
    10851096        PDMDevHlpPCISetIrq(pDevIns, 0, PDM_IRQ_LEVEL_LOW);
    1086     else if (uMsixtor != VIRTIO_MSI_NO_VECTOR)
     1097    else if (uMsixVector != VIRTIO_MSI_NO_VECTOR)
    10871098        PDMDevHlpPCISetIrq(pDevIns, pVirtio->uMsixConfig, PDM_IRQ_LEVEL_LOW);
    10881099}
     
    10941105    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    10951106
     1107    pVirtq->uQueueSize       = VIRTQ_SIZE;
     1108    pVirtq->uEnable          = false;
     1109    pVirtq->uNotifyOffset    = uVirtq;
     1110    pVirtq->fUsedRingEvent   = false;
    10961111    pVirtq->uAvailIdxShadow  = 0;
    10971112    pVirtq->uUsedIdxShadow   = 0;
    1098     pVirtq->uEnable          = false;
    1099     pVirtq->uSize            = VIRTQ_MAX_ENTRIES;
    1100     pVirtq->uNotifyOffset    = uVirtq;
    1101     pVirtq->uMsix            = uVirtq + 2;
    1102     pVirtq->fUsedRingEvent   = false;
     1113    pVirtq->uMsixVector      = uVirtq + 2;
    11031114
    11041115    if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */
    1105         pVirtq->uMsix = VIRTIO_MSI_NO_VECTOR;
    1106 
    1107     virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtq->uMsix);
     1116        pVirtq->uMsixVector = VIRTIO_MSI_NO_VECTOR;
     1117
     1118    virtioLowerInterrupt(pVirtio->pDevInsR3, pVirtq->uMsixVector);
    11081119}
    11091120
    11101121static void virtioResetDevice(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio)
    11111122{
    1112     Log2Func(("\n"));
     1123    LogFunc(("Resetting device VirtIO state\n"));
     1124    pVirtio->fLegacyDriver          = 1;   /* Assume this. Cleared if VIRTIO_F_VERSION_1 feature ack'd */
    11131125    pVirtio->uDeviceFeaturesSelect  = 0;
    11141126    pVirtio->uDriverFeaturesSelect  = 0;
     
    11231135        virtioLowerInterrupt(pDevIns, pVirtio->uMsixConfig);
    11241136        for (int i = 0; i < VIRTQ_MAX_COUNT; i++)
    1125             virtioLowerInterrupt(pDevIns, pVirtio->aVirtqueues[i].uMsix);
     1137            virtioLowerInterrupt(pDevIns, pVirtio->aVirtqueues[i].uMsixVector);
    11261138    }
    11271139
     
    11391151static void virtioGuestR3WasReset(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC)
    11401152{
    1141     LogFunc(("Guest reset the device\n"));
     1153    Log(("%-23s: Guest reset the device\n", __FUNCTION__));
    11421154
    11431155    /* Let the client know */
    1144     pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, 0);
     1156    pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, 0 /* fDriverOk */);
    11451157    virtioResetDevice(pDevIns, pVirtio);
    11461158}
     
    12101222                case 1:
    12111223                    memcpy((char *)&pVirtio->uDriverFeatures + sizeof(uint32_t), pv, cb);
     1224                    if (pVirtio->uDriverFeatures & VIRTIO_F_VERSION_1)
     1225                        pVirtio->fLegacyDriver = 0;
    12121226                    VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess + sizeof(uint32_t));
    12131227                    break;
     
    12181232            }
    12191233        }
    1220         /* Guest READ pCommonCfg->udriverFeatures */
     1234        else /* Guest READ pCommonCfg->udriverFeatures */
    12211235        {
    12221236            switch (pVirtio->uDriverFeaturesSelect)
     
    12621276                char szOut[80] = { 0 };
    12631277                virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut));
    1264                 LogFunc(("Guest wrote fDeviceStatus ................ (%s)\n", szOut));
     1278                Log(("%-23s: Guest wrote fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut));
    12651279            }
    1266             bool const fStatusChanged =
    1267                 (pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK) != (pVirtio->uPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
     1280            bool const fStatusChanged = IS_DRIVER_OK(pVirtio) != WAS_DRIVER_OK(pVirtio);
    12681281
    12691282            if (fDeviceReset || fStatusChanged)
     
    12721285                /* Since VirtIO status changes are cumbersome by nature, e.g. not a benchmark priority,
    12731286                 * handle the rest in R3 to facilitate logging or whatever dev-specific client needs to do */
    1274                 Log6Func(("RING0 => RING3 (demote)\n"));
     1287                Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__));
    12751288                return VINF_IOM_R3_MMIO_WRITE;
    12761289#endif
     
    12851298
    12861299            if (fStatusChanged)
    1287                 pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, pVirtio->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK);
     1300                pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, IS_DRIVER_OK(pVirtio));
    12881301#endif
    12891302            /*
    12901303             * Save the current status for the next write so we can see what changed.
    12911304             */
    1292             pVirtio->uPrevDeviceStatus = pVirtio->fDeviceStatus;
     1305            pVirtio->fPrevDeviceStatus = pVirtio->fDeviceStatus;
    12931306        }
    12941307        else /* Guest READ pCommonCfg->fDeviceStatus */
     
    13291342        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( GCPhysVirtqUsed,   uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
    13301343    else
    1331     if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uSize,                      VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
    1332         VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uSize,             uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
     1344    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uQueueSize,                 VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
     1345        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uQueueSize,        uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
    13331346    else
    13341347    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uEnable,                    VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
     
    13381351        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uNotifyOffset,     uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
    13391352    else
    1340     if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsix,                      VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
    1341         VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsix,             uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
     1353    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixVector,                VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess))
     1354        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsixVector,       uVirtq,  VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess, pVirtio->aVirtqueues);
    13421355    else
    13431356    {
     
    13521365    return rc;
    13531366}
     1367
     1368/**
     1369 * @callback_method_impl{FNIOMIOPORTNEWIN)
     1370 *
     1371 * This I/O handler exists only to handle access from legacy drivers.
     1372 */
     1373
     1374static DECLCALLBACK(VBOXSTRICTRC) virtioLegacyIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
     1375{
     1376
     1377    PVIRTIOCORE   pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
     1378    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatRead), a);
     1379
     1380    RT_NOREF(pvUser);
     1381//    LogFunc((" Read from port offset=%RTiop cb=%#x\n",  offPort, cb));
     1382
     1383    void *pv = pu32; /* To use existing macros */
     1384    int fWrite = 0;  /* To use existing macros */
     1385
     1386    uint16_t uVirtq = pVirtio->uVirtqSelect;
     1387
     1388    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDeviceFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1389    {
     1390        uint32_t val = pVirtio->uDeviceFeatures & UINT32_C(0xffffffff);
     1391        memcpy(pu32, &val, cb);
     1392        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDeviceFeatures,   VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
     1393    }
     1394    else
     1395    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1396    {
     1397        uint32_t val = pVirtio->uDriverFeatures & 0xffffffff;
     1398        memcpy(pu32, &val, cb);
     1399        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
     1400    }
     1401    else
     1402    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fDeviceStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1403    {
     1404        *(uint8_t *)pu32 = pVirtio->fDeviceStatus;
     1405
     1406        if (LogIs7Enabled())
     1407        {
     1408            char szOut[80] = { 0 };
     1409            virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut));
     1410            Log(("%-23s: Guest read  fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut));
     1411        }
     1412    }
     1413    else
     1414    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1415    {
     1416        ASSERT_GUEST_MSG(cb == 1, ("%d\n", cb));
     1417        *(uint8_t *)pu32 = pVirtio->uISR;
     1418        pVirtio->uISR = 0;
     1419        virtioLowerInterrupt( pDevIns,  0);
     1420        Log((" ISR read and cleared\n"));
     1421    }
     1422    else
     1423    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uVirtqSelect,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1424        VIRTIO_DEV_CONFIG_ACCESS(         uVirtqSelect,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
     1425    else
     1426    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uVirtqPfn,                  VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1427    {
     1428        PVIRTQUEUE pVirtQueue = &pVirtio->aVirtqueues[uVirtq];
     1429        *pu32 = pVirtQueue->GCPhysVirtqDesc >> PAGE_SHIFT;
     1430        Log(("%-23s: Guest read  uVirtqPfn .................... %#x\n",   __FUNCTION__, *pu32));
     1431    }
     1432    else
     1433    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uQueueSize,                 VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1434        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uQueueSize,        uVirtq,  VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio->aVirtqueues);
     1435    else
     1436    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uQueueNotify,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1437        VIRTIO_DEV_CONFIG_ACCESS(         uQueueNotify,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
     1438#if LEGACY_MSIX_SUPPORTED
     1439    else
     1440    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixConfig,                VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1441        VIRTIO_DEV_CONFIG_ACCESS(         uMsixConfig,                VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
     1442    else
     1443    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixVector,                VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1444        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsixVector,       uVirtq,  VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio->aVirtqueues);
     1445#endif
     1446    else if (offPort >= sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T))
     1447    {
     1448        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
     1449#if IN_RING3
     1450        /* Access device-specific configuration */
     1451        PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
     1452        int rc = pVirtioCC->pfnDevCapRead(pDevIns, offPort - sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T), pv, cb);
     1453        return rc;
     1454#else
     1455        return VINF_IOM_R3_IOPORT_READ;
     1456#endif
     1457    }
     1458    else
     1459    {
     1460        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
     1461        Log2Func(("Bad guest read access to virtio_legacy_pci_common_cfg: offset=%#x, cb=%x\n",
     1462                   offPort, cb));
     1463        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
     1464                    "virtioLegacyIOPortIn: no valid port at offset offset=%RTiop cb=%#x\n", offPort, cb);
     1465        return rc;
     1466    }
     1467
     1468    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
     1469    return VINF_SUCCESS;
     1470}
     1471
     1472
     1473/**
     1474 * @callback_method_impl{ * @callback_method_impl{FNIOMIOPORTNEWOUT}
     1475 *
     1476 * This I/O Port interface exists only to handle access from legacy drivers.
     1477 */
     1478static DECLCALLBACK(VBOXSTRICTRC) virtioLegacyIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
     1479{
     1480    PVIRTIOCORE pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
     1481    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatWrite), a);
     1482    RT_NOREF(pvUser);
     1483
     1484    uint16_t uVirtq = pVirtio->uVirtqSelect;
     1485    uint32_t u32OnStack = u32;  /* allows us to use this impl's MMIO parsing macros */
     1486    void *pv = &u32OnStack; /* To use existing macros */
     1487    int fWrite = 1;         /* To use existing macros */
     1488
     1489//    LogFunc(("Write to port offset=%RTiop, cb=%#x, u32=%#x\n",  offPort, cb, u32));
     1490
     1491    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uVirtqSelect,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1492        VIRTIO_DEV_CONFIG_ACCESS(         uVirtqSelect,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
     1493    else
     1494#if LEGACY_MSIX_SUPPORTED
     1495    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixConfig,         VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1496        VIRTIO_DEV_CONFIG_ACCESS(         uMsixConfig,         VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio);
     1497    else
     1498    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uMsixVector,         VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1499        VIRTIO_DEV_CONFIG_ACCESS_INDEXED( uMsixVector, uVirtq, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort, pVirtio->aVirtqueues);
     1500    else
     1501#endif
     1502    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDeviceFeatures,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1503    {
     1504        /* Check to see if guest acknowledged unsupported features */
     1505        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDeviceFeatures,          VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
     1506        LogFunc(("... WARNING: Guest attempted to write readonly virtio_pci_common_cfg.device_feature (ignoring)\n"));
     1507        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1508        return VINF_SUCCESS;
     1509    }
     1510    else
     1511    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDriverFeatures,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1512    {
     1513        memcpy(&pVirtio->uDriverFeatures, pv, cb);
     1514        if ((pVirtio->uDriverFeatures & ~VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED) == 0)
     1515        {
     1516                Log(("Guest asked for features host does not support! (host=%x guest=%x)\n",
     1517                      VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED, pVirtio->uDriverFeatures));
     1518                pVirtio->uDriverFeatures &= VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED;
     1519        }
     1520        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures,          VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
     1521    }
     1522    else
     1523    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uQueueSize,             VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1524    {
     1525        VIRTIO_DEV_CONFIG_LOG_ACCESS(uQueueSize,               VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
     1526        LogFunc(("... WARNING: Guest attempted to write readonly device_feature (queue size) (ignoring)\n"));
     1527        return VINF_SUCCESS;
     1528    }
     1529    else
     1530    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fDeviceStatus,          VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1531    {
     1532        bool const fDriverInitiatedReset = (pVirtio->fDeviceStatus = (uint8_t)u32) == 0;
     1533        bool const fDriverStateImproved = IS_DRIVER_OK(pVirtio) && !WAS_DRIVER_OK(pVirtio);
     1534
     1535        if (LogIs7Enabled())
     1536        {
     1537            char szOut[80] = { 0 };
     1538            virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut));
     1539            Log(("%-23s: Guest wrote fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut));
     1540        }
     1541
     1542        if (fDriverStateImproved  || fDriverInitiatedReset)
     1543        {
     1544#ifdef IN_RING0
     1545            Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__));
     1546            STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1547            return VINF_IOM_R3_IOPORT_WRITE;
     1548#endif
     1549        }
     1550
     1551#ifdef IN_RING3
     1552        PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
     1553        if (fDriverInitiatedReset)
     1554            virtioGuestR3WasReset(pDevIns, pVirtio, pVirtioCC);
     1555
     1556        else if (fDriverStateImproved)
     1557            pVirtioCC->pfnStatusChanged(pVirtio, pVirtioCC, 1 /* fDriverOk */);
     1558
     1559#endif
     1560        pVirtio->fPrevDeviceStatus = pVirtio->fDeviceStatus;
     1561    }
     1562    else
     1563    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uVirtqPfn, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1564    {
     1565        PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
     1566        uint64_t uVirtqPfn = (uint64_t)u32;
     1567
     1568        if (uVirtqPfn)
     1569        {
     1570            /* Transitional devices calculate ring physical addresses using rigid spec-defined formulae,
     1571             * instead of guest conveying respective address of each ring, as "modern" VirtIO drivers do,
     1572             * thus there is no virtq PFN or single base queue address stored in instance data for
     1573             * this transitional device, but rather it is derived, when read back, from GCPhysVirtqDesc */
     1574
     1575            pVirtq->GCPhysVirtqDesc  = uVirtqPfn * VIRTIO_PAGE_SIZE;
     1576            pVirtq->GCPhysVirtqAvail = pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * pVirtq->uQueueSize;
     1577            pVirtq->GCPhysVirtqUsed  =
     1578                RT_ALIGN(pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uQueueSize]), VIRTIO_PAGE_SIZE);
     1579        }
     1580        else
     1581        {
     1582            /* Don't set ring addresses for queue (to meaningless values), when guest resets the virtq's PFN */
     1583            pVirtq->GCPhysVirtqDesc  = 0;
     1584            pVirtq->GCPhysVirtqAvail = 0;
     1585            pVirtq->GCPhysVirtqUsed  = 0;
     1586        }
     1587        Log(("%-23s: Guest wrote uVirtqPfn .................... %#x:\n"
     1588             "%68s... %p -> GCPhysVirtqDesc\n%68s... %p -> GCPhysVirtqAvail\n%68s... %p -> GCPhysVirtqUsed\n",
     1589                __FUNCTION__, u32, " ", pVirtq->GCPhysVirtqDesc, " ", pVirtq->GCPhysVirtqAvail, " ", pVirtq->GCPhysVirtqUsed));
     1590    }
     1591    else
     1592    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uQueueNotify, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1593    {
     1594#ifdef IN_RING3
     1595        ASSERT_GUEST_MSG(cb == 2, ("cb=%u\n", cb));
     1596        pVirtio->uQueueNotify =  u32 & 0xFFFF;
     1597        if (uVirtq < VIRTQ_MAX_COUNT)
     1598        {
     1599            RT_UNTRUSTED_VALIDATED_FENCE();
     1600
     1601            /* Need to check that queue is configured. Legacy spec didn't have a queue enabled flag */
     1602            if (pVirtio->aVirtqueues[pVirtio->uQueueNotify].GCPhysVirtqDesc)
     1603                    virtioCoreVirtqNotified(pDevIns, pVirtio, pVirtio->uQueueNotify, pVirtio->uQueueNotify /* uNotifyIdx */);
     1604            else
     1605                Log(("The queue (#%d) being notified has not been initialized.\n", pVirtio->uQueueNotify));
     1606        }
     1607        else
     1608            Log(("Invalid queue number (%d)\n", pVirtio->uQueueNotify));
     1609#else
     1610        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1611        return VINF_IOM_R3_IOPORT_WRITE;
     1612#endif
     1613    }
     1614    else
     1615    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     1616    {
     1617        VIRTIO_DEV_CONFIG_LOG_ACCESS( fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
     1618        LogFunc(("... WARNING: Guest attempted to write readonly device_feature (ISR status) (ignoring)\n"));
     1619        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1620        return VINF_SUCCESS;
     1621    }
     1622    else if (offPort >= sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T))
     1623    {
     1624#if IN_RING3
     1625
     1626        /* Access device-specific configuration */
     1627        PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
     1628        return pVirtioCC->pfnDevCapWrite(pDevIns, offPort - sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T), pv, cb);
     1629#else
     1630        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1631        return VINF_IOM_R3_IOPORT_WRITE;
     1632#endif
     1633    }
     1634    else
     1635    {
     1636        Log2Func(("Bad guest write access to virtio_legacy_pci_common_cfg: offset=%#x, cb=0x%x\n",
     1637                  offPort, cb));
     1638        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1639        int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
     1640                    "virtioLegacyIOPortOut: no valid port at offset offset=%RTiop cb=0x%#x\n", offPort, cb);
     1641        return rc;
     1642    }
     1643
     1644    RT_NOREF(uVirtq);
     1645    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1646    return VINF_SUCCESS;
     1647}
     1648
    13541649
    13551650/**
     
    13681663    AssertReturn(cb == 1 || cb == 2 || cb == 4, VERR_INVALID_PARAMETER);
    13691664    Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser);
     1665    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatRead), a);
     1666
    13701667
    13711668    uint32_t uOffset;
     
    14001697
    14011698        virtioLowerInterrupt(pDevIns, 0);
     1699        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
    14021700        return rcStrict;
    14031701#else
     1702        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
    14041703        return VINF_IOM_R3_MMIO_READ;
    14051704#endif
     
    14151714        pVirtio->uISR = 0; /* VirtIO spec requires reads of ISR to clear it */
    14161715        virtioLowerInterrupt(pDevIns, 0);
     1716        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
    14171717        return VINF_SUCCESS;
    14181718    }
    14191719
    1420     ASSERT_GUEST_MSG_FAILED(("Bad read access to mapped capabilities region: off=%RGp cb=%u\n",
    1421                               off, cb));
    1422     return VINF_IOM_MMIO_UNUSED_00;
     1720    ASSERT_GUEST_MSG_FAILED(("Bad read access to mapped capabilities region: off=%RGp cb=%u\n", off, cb));
     1721    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
     1722    int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
     1723                "virtioMmioRead: Bad MMIO access to capabilities, offset=%RTiop cb=%08x\n", off, cb);
     1724    return rc;
    14231725}
    14241726
     
    14351737    PVIRTIOCORE   pVirtio   = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
    14361738    PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
    1437 
    14381739    AssertReturn(cb == 1 || cb == 2 || cb == 4, VERR_INVALID_PARAMETER);
    1439 
    14401740    Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser);
     1741    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatWrite), a);
     1742
    14411743    uint32_t uOffset;
    14421744    if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocDeviceCap))
     
    14461748         * Foreward this MMIO write access for client to deal with.
    14471749         */
     1750        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
    14481751        return pVirtioCC->pfnDevCapWrite(pDevIns, uOffset, pv, cb);
    14491752#else
     1753        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
    14501754        return VINF_IOM_R3_MMIO_WRITE;
    14511755#endif
     
    14531757
    14541758    if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocCommonCfgCap))
     1759    {
     1760        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
    14551761        return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, true /* fWrite */, uOffset, cb, (void *)pv);
     1762    }
    14561763
    14571764    if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocIsrCap) && cb == sizeof(uint8_t))
     
    14621769                  pVirtio->uISR & VIRTIO_ISR_VIRTQ_INTERRUPT,
    14631770                  RT_BOOL(pVirtio->uISR & VIRTIO_ISR_DEVICE_CONFIG)));
     1771        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
    14641772        return VINF_SUCCESS;
    14651773    }
     
    14691777    {
    14701778        virtioCoreVirtqNotified(pDevIns, pVirtio, uOffset / VIRTIO_NOTIFY_OFFSET_MULTIPLIER, *(uint16_t *)pv);
     1779        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
    14711780        return VINF_SUCCESS;
    14721781    }
    14731782
    14741783    ASSERT_GUEST_MSG_FAILED(("Bad write access to mapped capabilities region: off=%RGp pv=%#p{%.*Rhxs} cb=%u\n", off, pv, cb, pv, cb));
    1475     return VINF_SUCCESS;
     1784    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1785    int rc = PDMDevHlpDBGFStop(pDevIns, RT_SRC_POS,
     1786                "virtioMmioRead: Bad MMIO access to capabilities, offset=%RTiop cb=%08x\n", off, cb);
     1787    return rc;
    14761788}
    14771789
     
    14941806         * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
    14951807         * (the virtio_pci_cfg_cap capability), and access data items.
     1808         * This is used by BIOS to gain early boot access to the the storage device.
    14961809         */
    14971810        struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap;
     
    15351848        /* VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability
    15361849         * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
    1537          * (the virtio_pci_cfg_cap capability), and access data items. */
     1850         * (the virtio_pci_cfg_cap capability), and access data items.
     1851         * This is used by BIOS to gain early boot access to the the storage device.*/
    15381852
    15391853        struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap;
     
    15931907        pHlp->pfnSSMPutGCPhys64( pSSM, pVirtq->GCPhysVirtqUsed);
    15941908        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uNotifyOffset);
    1595         pHlp->pfnSSMPutU16(      pSSM, pVirtq->uMsix);
     1909        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uMsixVector);
    15961910        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uEnable);
    1597         pHlp->pfnSSMPutU16(      pSSM, pVirtq->uSize);
     1911        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uQueueSize);
    15981912        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uAvailIdxShadow);
    15991913        pHlp->pfnSSMPutU16(      pSSM, pVirtq->uUsedIdxShadow);
     
    16531967        pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqUsed);
    16541968        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uNotifyOffset);
    1655         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uMsix);
     1969        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uMsixVector);
    16561970        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uEnable);
    1657         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uSize);
     1971        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uQueueSize);
    16581972        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uAvailIdxShadow);
    16591973        pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uUsedIdxShadow);
     
    16952009            for (int uVirtq = 0; uVirtq < VIRTQ_MAX_COUNT; uVirtq++)
    16962010            {
    1697                 if (pVirtio->aVirtqueues[uVirtq].uEnable)
     2011                if (!pVirtio->fLegacyDriver || pVirtio->aVirtqueues[uVirtq].uEnable)
    16982012                    virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, uVirtq);
    16992013            }
     
    17192033        pVirtioCC->pbPrevDevSpecificCfg = NULL;
    17202034    }
     2035
    17212036    RT_NOREF(pDevIns, pVirtio);
    17222037}
     
    17262041                     const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg)
    17272042{
     2043
     2044
    17282045    /*
    17292046     * The pVirtio state must be the first member of the shared device instance
     
    17402057    AssertReturn(pVirtioCC->pfnStatusChanged, VERR_INVALID_POINTER);
    17412058    AssertReturn(pVirtioCC->pfnVirtqNotified, VERR_INVALID_POINTER);
    1742 
    1743 #if 0 /* Until pdmR3DvHlp_PCISetIrq() impl is fixed and Assert that limits vec to 0 is removed */
     2059    AssertReturn(VIRTQ_SIZE > 0 && VIRTQ_SIZE <= 32768,  VERR_OUT_OF_RANGE); /* VirtIO specification-defined limit */
     2060
     2061#if 0 /* Until pdmR3DvHlp_PCISetIrq() impl is fixed and Assert that limits vec to 0 is removed
     2062       * The legacy MSI support has not been implemented yet
     2063       */
    17442064# ifdef VBOX_WITH_MSI_DEVICES
    17452065    pVirtio->fMsiSupport = true;
    17462066# endif
    17472067#endif
     2068
    17482069
    17492070    /*
     
    17562077
    17572078    RTStrCopy(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszInstance);
    1758 
    1759     pVirtio->fDeviceStatus = 0;
    17602079    pVirtioCC->cbDevSpecificCfg = cbDevSpecificCfg;
    17612080    pVirtioCC->pbDevSpecificCfg = (uint8_t *)pvDevSpecificCfg;
     
    17692088    PDMPciDevSetRevisionId(pPciDev,         DEVICE_PCI_REVISION_ID_VIRTIO);
    17702089    PDMPciDevSetVendorId(pPciDev,           DEVICE_PCI_VENDOR_ID_VIRTIO);
     2090    PDMPciDevSetDeviceId(pPciDev,           pPciParams->uDeviceId);
     2091    PDMPciDevSetSubSystemId(pPciDev,        DEVICE_PCI_NETWORK_SUBSYSTEM);
    17712092    PDMPciDevSetSubSystemVendorId(pPciDev,  DEVICE_PCI_VENDOR_ID_VIRTIO);
    1772     PDMPciDevSetDeviceId(pPciDev,           pPciParams->uDeviceId);
    17732093    PDMPciDevSetClassBase(pPciDev,          pPciParams->uClassBase);
    17742094    PDMPciDevSetClassSub(pPciDev,           pPciParams->uClassSub);
    17752095    PDMPciDevSetClassProg(pPciDev,          pPciParams->uClassProg);
    1776     PDMPciDevSetSubSystemId(pPciDev,        pPciParams->uSubsystemId);
    17772096    PDMPciDevSetInterruptLine(pPciDev,      pPciParams->uInterruptLine);
    17782097    PDMPciDevSetInterruptPin(pPciDev,       pPciParams->uInterruptPin);
     
    17852104    rc = PDMDevHlpPCIInterceptConfigAccesses(pDevIns, pPciDev, virtioR3PciConfigRead, virtioR3PciConfigWrite);
    17862105    AssertRCReturn(rc, rc);
    1787 
    17882106
    17892107    /* Construct & map PCI vendor-specific capabilities for virtio host negotiation with guest driver */
     
    19182236    PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST);
    19192237
    1920     size_t cbSize = RTStrPrintf(pVirtioCC->pcszMmioName, sizeof(pVirtioCC->pcszMmioName), "%s MMIO", pcszInstance);
     2238    size_t cbSize = RTStrPrintf(pVirtioCC->pcszMmioName, sizeof(pVirtioCC->pcszMmioName), "%s (modern)", pcszInstance);
    19212239    if (cbSize <= 0)
    19222240        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: out of memory allocating string")); /* can we put params in this error? */
    19232241
    1924     /* Note: The Linux driver at drivers/virtio/virtio_pci_modern.c tries to map at least a page for the
     2242    cbSize = RTStrPrintf(pVirtioCC->pcszPortIoName, sizeof(pVirtioCC->pcszPortIoName), "%s (legacy)", pcszInstance);
     2243    if (cbSize <= 0)
     2244        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: out of memory allocating string")); /* can we put params in this error? */
     2245
     2246    /* As a transitional device that supports legacy VirtIO drivers, this VirtIO device generic implementation presents
     2247     * legacy driver interface in I/O space at BAR0. The following maps the common (e.g. device independent)
     2248     * dev config area as well as device-specific dev config area (whose size is passed to init function of this VirtIO
     2249     * generic device code) for access via Port I/O, since legacy drivers (e.g. pre VirtIO 1.0) don't use MMIO callbacks.
     2250     * (See VirtIO 1.1, Section 4.1.4.8).
     2251     */
     2252    rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, VIRTIO_REGION_LEGACY_IO, sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T) + cbDevSpecificCfg,
     2253                                      virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/, pVirtioCC->pcszPortIoName,
     2254                                      NULL /*paExtDescs*/, &pVirtio->hLegacyIoPorts);
     2255    AssertLogRelRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register legacy config in I/O space at BAR0 */")));
     2256
     2257    /*  Note: The Linux driver at drivers/virtio/virtio_pci_modern.c tries to map at least a page for the
    19252258     * 'unknown' device-specific capability without querying the capability to figure
    19262259     *  out size, so pad with an extra page
    19272260     */
    1928     rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + PAGE_SIZE, PAGE_SIZE),
     2261    rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + VIRTIO_PAGE_SIZE, VIRTIO_PAGE_SIZE),
    19292262                                        PCI_ADDRESS_SPACE_MEM, virtioMmioWrite, virtioMmioRead, pVirtio,
    19302263                                        IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
     
    19352268     * Statistics.
    19362269     */
     2270# ifdef VBOX_WITH_STATISTICS
    19372271    PDMDevHlpSTAMRegisterF(pDevIns, &pVirtio->StatDescChainsAllocated,  STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    19382272                           "Total number of allocated descriptor chains",   "DescChainsAllocated");
     
    19432277    PDMDevHlpSTAMRegisterF(pDevIns, &pVirtio->StatDescChainsSegsOut,    STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    19442278                           "Total number of outbound segments",             "DescChainsSegsOut");
     2279    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatReadR3,    STAMTYPE_PROFILE, "IO/ReadR3",          STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in R3");
     2280    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatReadR0,    STAMTYPE_PROFILE, "IO/ReadR0",          STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in R0");
     2281    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatReadRC,    STAMTYPE_PROFILE, "IO/ReadRC",          STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in RC");
     2282    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatWriteR3,   STAMTYPE_PROFILE, "IO/WriteR3",         STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in R3");
     2283    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatWriteR0,   STAMTYPE_PROFILE, "IO/WriteR0",         STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in R0");
     2284    PDMDevHlpSTAMRegister(pDevIns, &pVirtio->StatWriteRC,   STAMTYPE_PROFILE, "IO/WriteRC",         STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in RC");
     2285# endif /* VBOX_WITH_STATISTICS */
     2286
     2287    virtioResetDevice(pDevIns, pVirtio); /* Reset VirtIO specific state of device */
    19452288
    19462289    return VINF_SUCCESS;
     
    19672310    int rc = PDMDevHlpMmioSetUpContext(pDevIns, pVirtio->hMmioPciCap, virtioMmioWrite, virtioMmioRead, pVirtio);
    19682311    AssertRCReturn(rc, rc);
     2312
     2313    rc = PDMDevHlpIoPortSetUpContext(pDevIns, pVirtio->hLegacyIoPorts, virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/);
     2314    AssertRCReturn(rc, rc);
     2315
    19692316    return rc;
    19702317}
  • trunk/src/VBox/Devices/VirtIO/VirtioCore.h

    r90791 r91703  
    2525#include <iprt/ctype.h>
    2626#include <iprt/sg.h>
     27#include <iprt/types.h>
    2728
    2829#ifdef LOG_ENABLED
     
    4849
    4950#define VIRTIO_MAX_VIRTQ_NAME_SIZE          32                   /**< Maximum length of a queue name           */
    50 #define VIRTQ_MAX_ENTRIES                   1024                 /**< Max size (# desc elements) of a virtq    */
     51#define VIRTQ_SIZE                        1024                   /**< Max size (# entries) of a virtq          */
    5152#define VIRTQ_MAX_COUNT                     24                   /**< Max queues we allow guest to create      */
    5253#define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
     54#define VIRTIO_REGION_LEGACY_IO             0                    /**< BAR for VirtIO legacy drivers MBZ        */
    5355#define VIRTIO_REGION_PCI_CAP               2                    /**< BAR for VirtIO Cap. MMIO (impl specific) */
    5456#define VIRTIO_REGION_MSIX_CAP              0                    /**< Bar for MSI-X handling                   */
     57#define VIRTIO_PAGE_SIZE                 4096                    /**< Page size used by VirtIO specification   */
     58
     59
     60/* Note: The VirtIO specification, particularly rev. 0.95, and clarified in rev 1.0 for transitional devices,
     61         says the page sized used for Queue Size calculations is usually 4096 bytes, but dependent on the
     62         the transport. In an appendix of the 0.95 spec, the 'mmio device', which has not been
     63         implemented by VBox legacy device in VirtualBox, says guest must report the page size. For now
     64         will set page size to a static 4096 based on the original VBox legacy VirtIO implementation which
     65         tied it to PAGE_SIZE which appears to work (or at least good enough for most practical purposes)      */
    5566
    5667
     
    107118    VIRTIOSGBUF         SgBufIn;
    108119    VIRTIOSGBUF         SgBufOut;
    109     VIRTIOSGSEG         aSegsIn[VIRTQ_MAX_ENTRIES];
    110     VIRTIOSGSEG         aSegsOut[VIRTQ_MAX_ENTRIES];
     120    VIRTIOSGSEG         aSegsIn[VIRTQ_SIZE];
     121    VIRTIOSGSEG         aSegsOut[VIRTQ_SIZE];
    111122    /** @} */
    112123} VIRTQBUF_T;
     
    129140} VIRTIOPCIPARAMS, *PVIRTIOPCIPARAMS;
    130141
     142/* Virtio Platform Indepdented Reserved Feature Bits (see 1.1 specification section 6) */
     143
     144#define VIRTIO_F_NOTIFY_ON_EMPTY            RT_BIT_64(24)        /**< Legacy feature: Force intr if no AVAIL    */
     145#define VIRTIO_F_ANY_LAYOUT                 RT_BIT_64(27)        /**< Doc bug: Goes under two names in spec     */
     146#define VIRTIO_F_INDIRECT_DESC              RT_BIT_64(28)        /**< Allow descs to point to list of descs     */
     147#define VIRTIO_F_RING_INDIRECT_DESC         RT_BIT_64(28)        /**< Doc bug: Goes under two names in spec     */
     148#define VIRTIO_F_EVENT_IDX                  RT_BIT_64(29)        /**< Allow notification disable for n elems    */
     149#define VIRTIO_F_RING_EVENT_IDX             RT_BIT_64(29)        /**< Doc bug: Goes under two names in spec     */
     150#define VIRTIO_F_BAD_FEATURE                RT_BIT_64(30)        /**< QEMU kludge.  UNUSED as of >= VirtIO 1.0  */
    131151#define VIRTIO_F_VERSION_1                  RT_BIT_64(32)        /**< Required feature bit for 1.0 devices      */
    132 #define VIRTIO_F_INDIRECT_DESC              RT_BIT_64(28)        /**< Allow descs to point to list of descs     */
    133 #define VIRTIO_F_EVENT_IDX                  RT_BIT_64(29)        /**< Allow notification disable for n elems    */
    134 #define VIRTIO_F_RING_INDIRECT_DESC         RT_BIT_64(28)        /**< Doc bug: Goes under two names in spec     */
    135 #define VIRTIO_F_RING_EVENT_IDX             RT_BIT_64(29)        /**< Doc bug: Goes under two names in spec     */
     152#define VIRTIO_F_ACCESS_PLATFORM            RT_BIT_64(33)        /**< Funky guest mem access   (VirtIO 1.1 NYI) */
     153#define VIRTIO_F_RING_PACKED                RT_BIT_64(34)        /**< Packed Queue Layout      (VirtIO 1.1 NYI) */
     154#define VIRTIO_F_IN_ORDER                   RT_BIT_64(35)        /**< Honor guest buf order    (VirtIO 1.1 NYI) */
     155#define VIRTIO_F_ORDER_PLATFORM             RT_BIT_64(36)        /**< Host mem access honored  (VirtIO 1.1 NYI) */
     156#define VIRTIO_F_SR_IOV                     RT_BIT_64(37)        /**< Dev Single Root I/O virt (VirtIO 1.1 NYI) */
     157#define VIRTIO_F_NOTIFICAITON_DATA          RT_BIT_64(38)        /**< Driver passes extra data (VirtIO 1.1 NYI) */
    136158
    137159#define VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED ( 0 )            /**< TBD: Add VIRTIO_F_INDIRECT_DESC           */
     160#define VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED ( 0 )     /**< Only offered to legacy drivers            */
    138161
    139162#define VIRTIO_ISR_VIRTQ_INTERRUPT           RT_BIT_32(0)        /**< Virtq interrupt bit of ISR register       */
    140163#define VIRTIO_ISR_DEVICE_CONFIG             RT_BIT_32(1)        /**< Device configuration changed bit of ISR   */
     164#define DEVICE_PCI_NETWORK_SUBSYSTEM                    1        /**< Network Card, per VirtIO legacy spec.     */
    141165#define DEVICE_PCI_VENDOR_ID_VIRTIO                0x1AF4        /**< Guest driver locates dev via (mandatory)  */
    142 #define DEVICE_PCI_REVISION_ID_VIRTIO                   1        /**< VirtIO 1.0 non-transitional drivers >= 1 */
     166#define DEVICE_PCI_REVISION_ID_VIRTIO                   0        /**< VirtIO Modern Transitional driver rev MBZ */
    143167
    144168/** Reserved (*negotiated*) Feature Bits (e.g. device independent features, VirtIO 1.0 spec,section 6) */
     
    190214
    191215/**
     216 * VirtIO Legacy Capabilities' related MMIO-mapped structs (see virtio-0.9.5 spec)
     217 *
     218 * Note: virtio_pci_device_cap is dev-specific, implemented by client. Definition unknown here.
     219 */
     220typedef struct virtio_legacy_pci_common_cfg
     221{
     222    /* Device-specific fields */
     223    uint32_t  uDeviceFeatures;                                   /**< RO (device reports features to driver)    */
     224    uint32_t  uDriverFeatures;                                   /**< RW (driver-accepted device features)      */
     225    uint32_t  uVirtqPfn;                                         /**< RW (driver writes queue page number)      */
     226    uint16_t  uQueueSize;                                        /**< RW (queue size, 0 - 2^n)                  */
     227    uint16_t  uVirtqSelect;                                      /**< RW (selects queue focus for these fields) */
     228    uint16_t  uQueueNotify;                                      /**< RO (offset into virtqueue; see spec)      */
     229    uint8_t   fDeviceStatus;                                     /**< RW (driver writes device status, 0=reset) */
     230    uint8_t   fIsrStatus;                                        /**< RW (driver writes ISR status, 0=reset)    */
     231//    uint16_t  uMsixConfig;                                       /**< RW (driver sets MSI-X config vector)      */
     232//    uint16_t  uMsixVector;                                       /**< RW (driver sets MSI-X config vector)      */
     233} VIRTIO_LEGACY_PCI_COMMON_CFG_T, *PVIRTIO_LEGACY_PCI_COMMON_CFG_T;
     234
     235/**
    192236 * VirtIO 1.0 Capabilities' related MMIO-mapped structs:
    193237 *
     
    208252    /* Virtq-specific fields (values reflect (via MMIO) info related to queue indicated by uVirtqSelect. */
    209253    uint16_t  uVirtqSelect;                                      /**< RW (selects queue focus for these fields) */
    210     uint16_t  uSize;                                             /**< RW (queue size, 0 - 2^n)                  */
    211     uint16_t  uMsix;                                             /**< RW (driver selects MSI-X queue vector)    */
     254    uint16_t  uQueueSize;                                        /**< RW (queue size, 0 - 2^n)                  */
     255    uint16_t  uMsixVector;                                       /**< RW (driver selects MSI-X queue vector)    */
    212256    uint16_t  uEnable;                                           /**< RW (driver controls usability of queue)   */
    213257    uint16_t  uNotifyOffset;                                     /**< RO (offset into virtqueue; see spec)      */
     
    245289    RTGCPHYS                    GCPhysVirtqAvail;                 /**< (MMIO) PhysAdr per-Q avail structs  GUEST */
    246290    RTGCPHYS                    GCPhysVirtqUsed;                  /**< (MMIO) PhysAdr per-Q used structs   GUEST */
    247     uint16_t                    uMsix;                            /**< (MMIO) Per-queue vector for MSI-X   GUEST */
     291    uint16_t                    uMsixVector;                      /**< (MMIO) Per-queue vector for MSI-X   GUEST */
    248292    uint16_t                    uEnable;                          /**< (MMIO) Per-queue enable             GUEST */
    249293    uint16_t                    uNotifyOffset;                    /**< (MMIO) per-Q notify offset           HOST */
    250     uint16_t                    uSize;                            /**< (MMIO) Per-queue size          HOST/GUEST */
     294    uint16_t                    uQueueSize;                       /**< (MMIO) Per-queue size          HOST/GUEST */
    251295    uint16_t                    uAvailIdxShadow;                  /**< Consumer's position in avail ring         */
    252296    uint16_t                    uUsedIdxShadow;                   /**< Consumer's position in used ring          */
     
    272316    uint32_t                    uMsixConfig;                      /**< (MMIO) MSI-X vector                 GUEST */
    273317    uint8_t                     fDeviceStatus;                    /**< (MMIO) Device Status                GUEST */
    274     uint8_t                     uPrevDeviceStatus;                /**< (MMIO) Prev Device Status           GUEST */
     318    uint8_t                     fPrevDeviceStatus;                /**< (MMIO) Prev Device Status           GUEST */
    275319    uint8_t                     uConfigGeneration;                /**< (MMIO) Device config sequencer       HOST */
     320    uint16_t                    uQueueNotify;                     /**< Caches queue idx in legacy mode     GUEST */
     321    bool                        fGenUpdatePending;                /**< If set, update cfg gen after driver reads */
     322    uint8_t                     uPciCfgDataOff;                   /**< Offset to PCI configuration data area     */
     323    uint8_t                     uISR;                             /**< Interrupt Status Register.                */
     324    uint8_t                     fMsiSupport;                      /**< Flag set if using MSI instead of ISR      */
     325    uint8_t                     fLegacyDriver;                    /**< Set if guest driver < VirtIO 1.0          */
     326    uint16_t                    uVirtqSelect;                     /**< (MMIO) queue selector               GUEST */
    276327
    277328    /** @name The locations of the capability structures in PCI config space and the BAR.
     
    284335    /** @} */
    285336
    286     uint16_t                    uVirtqSelect;                     /**< (MMIO) queue selector               GUEST */
    287     bool                        fGenUpdatePending;                /**< If set, update cfg gen after driver reads */
    288     uint8_t                     uPciCfgDataOff;                   /**< Offset to PCI configuration data area     */
    289     uint8_t                     uISR;                             /**< Interrupt Status Register.                */
    290     uint8_t                     fMsiSupport;                      /**< Flag set if using MSI instead of ISR      */
    291     /** The MMIO handle for the PCI capability region (\#2). */
    292     IOMMMIOHANDLE               hMmioPciCap;
    293 
     337
     338
     339    IOMMMIOHANDLE               hMmioPciCap;                      /**< MMIO handle of PCI cap. region (\#2)      */
     340    IOMIOPORTHANDLE             hLegacyIoPorts;                   /**< Handle of legacy I/O port range.          */
     341
     342
     343#ifdef VBOX_WITH_STATISTICS
    294344    /** @name Statistics
    295345     * @{ */
     
    298348    STAMCOUNTER                 StatDescChainsSegsIn;
    299349    STAMCOUNTER                 StatDescChainsSegsOut;
     350    STAMPROFILEADV              StatReadR3;                        /** I/O port and MMIO R3 Read profiling       */
     351    STAMPROFILEADV              StatReadR0;                        /** I/O port and MMIO R0 Read profiling       */
     352    STAMPROFILEADV              StatReadRC;                        /** I/O port and MMIO R3 Read profiling       */
     353    STAMPROFILEADV              StatWriteR3;                       /** I/O port and MMIO R3 Write profiling      */
     354    STAMPROFILEADV              StatWriteR0;                       /** I/O port and MMIO R3 Write profiling      */
     355    STAMPROFILEADV              StatWriteRC;                       /** I/O port and MMIO R3 Write profiling      */
     356#endif
     357
    300358    /** @} */
    301359} VIRTIOCORE;
     
    367425    bool                                fGenUpdatePending;         /**< If set, update cfg gen after driver reads */
    368426    char                                pcszMmioName[MAX_NAME];    /**< MMIO mapping name                         */
     427    char                                pcszPortIoName[MAX_NAME];  /**< PORT mapping name                         */
    369428} VIRTIOCORER3;
    370429
     
    648707int virtioCoreR3VirtqAvailBufNext(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
    649708
     709/**
     710 * Checks to see if guest has acknowledged device's VIRTIO_F_VERSION_1 feature.
     711 * If not, it's presumed to be a VirtIO legacy guest driver. Note that legacy drivers
     712 * may start using the device prematurely, as opposed to the rigorously sane protocol
     713 * prescribed by the "modern" VirtIO spec. Doing so is suggestive of a legacy driver.
     714 * Therefore legacy mode is the assumption un proven otherwise.
     715 *
     716 * @param   pVirtio      Pointer to the virtio state.
     717 */
     718int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio);
    650719
    651720DECLINLINE(void) virtioCoreGCPhysChainInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs)
     
    881950{
    882951    Assert(uVirtqNbr < RT_ELEMENTS(pVirtio->aVirtqueues));
     952    if (pVirtio->fLegacyDriver)
     953        return pVirtio->aVirtqueues[uVirtqNbr].GCPhysVirtqDesc != 0;
    883954    return pVirtio->aVirtqueues[uVirtqNbr].uEnable != 0;
    884955}
     
    9581029 * @param   uBase       base address of per-row address prefixing of hex output
    9591030 * @param   pszTitle    Optional title. If present displays title that lists
    960  *                      provided text with value of cb to indicate size next to it.
     1031 *                      provided text with value of cb to indicate VIRTQ_SIZE next to it.
    9611032 */
    9621033void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle);
     
    9931064}
    9941065
     1066/**
     1067 * This VirtIO transitional device supports "modern" (rev 1.0+) as well as "legacy" (e.g. < 1.0) VirtIO drivers.
     1068 * Some legacy guest drivers are known to mishandle PCI bus mastering wherein the PCI flavor of GC phys
     1069 * access functions can't be used. The following wrappers select the mem access method based on whether the
     1070 * device is operating in legacy mode or not.
     1071 */
     1072DECLINLINE(int) virtioCoreGCPhysWrite(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbWrite)
     1073{
     1074    int rc;
     1075    if (virtioCoreIsLegacyMode(pVirtio))
     1076        rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
     1077    else
     1078        rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
     1079    return rc;
     1080}
     1081
     1082DECLINLINE(int) virtioCoreGCPhysRead(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
     1083{
     1084    int rc;
     1085    if (virtioCoreIsLegacyMode(pVirtio))
     1086        rc = PDMDevHlpPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
     1087    else
     1088        rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
     1089    return rc;
     1090}
    9951091
    9961092/** Misc VM and PDM boilerplate */
     
    10551151                                  RT_UOFFSETOF(tCfgStruct, member),  \
    10561152                                  RT_SIZEOFMEMB(tCfgStruct, member), false /* fSubfieldMatch */)
     1153
     1154
    10571155
    10581156/**
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette