VirtualBox

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


Ignore:
Timestamp:
Dec 15, 2021 3:51:28 PM (3 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
148914
Message:

Improve transitional behavior, and save/load exec code. Some Rx buffer handling code optimization for speed, and make it easier to understand and maintain. Add missing function comments and improve others. Try to make debug logging even clearer and more succinct. And any other miscellaneous small improvements I could find. See BugRef(8651) Comment #171

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

Legend:

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

    r92091 r92939  
    2424 */
    2525
    26 
    27 /*********************************************************************************************************************************
    28 *   Header Files                                                                                                                 *
    29 *********************************************************************************************************************************/
     26/*******************************************************************************************************************************
     27*   Header Files                                                                                                               *
     28***************************************************************************************************************************** **/
    3029//#define LOG_GROUP LOG_GROUP_DRV_NET
    3130#define LOG_GROUP LOG_GROUP_DEV_VIRTIO
     
    4544#include <VBox/version.h>
    4645#include <VBox/log.h>
     46
    4747
    4848#ifdef IN_RING3
     
    5959#include "VBoxDD.h"
    6060
    61 #define LUN0                            0
     61#define VIRTIONET_TRANSITIONAL_ENABLE_FLAG             1       /** < If set behave as VirtIO "transitional" device  */
     62
     63/** The current saved state version for the virtio core. */
     64#define VIRTIONET_SAVEDSTATE_VERSION                   UINT32_C(1)
     65#define VIRTIONET_SAVEDSTATE_VERSION_3_1_BETA1_LEGACY  UINT32_C(1) /**< Grandfathered in from DevVirtioNet.cpp      */
     66#define VIRTIONET_SAVEDSTATE_VERSION_LEGACY            UINT32_C(2) /**< Grandfathered in from DevVirtioNet.cpp      */
     67#define VIRTIONET_VERSION_MARKER_MAC_ADDR { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } /**  SSM handling                  */
     68
     69/*
     70 * Glossary of networking acronyms used in feature names below:
     71 *
     72 * GSO = Generic Segmentation Offload
     73 * TSO = TCP Segmentation Offload
     74 * UFO = UDP Fragmentation Offload
     75 * ECN = Explicit Congestion Notification
     76 */
    6277
    6378/** @name VirtIO 1.0 NET Host feature bits (See VirtIO 1.0 specification, Section 5.6.3)
     
    88103static const VIRTIO_FEATURES_LIST s_aDevSpecificFeatures[] =
    89104{
    90     { VIRTIONET_F_CSUM,                "   CSUM                 Host handles packets with partial checksum.\n" },
     105    { VIRTIONET_F_STATUS,              "   STATUS               Configuration status field is available.\n" },
     106    { VIRTIONET_F_MAC,                 "   MAC                  Host has given MAC address.\n" },
     107    { VIRTIONET_F_CTRL_VQ,             "   CTRL_VQ              Control channel is available.\n" },
     108    { VIRTIONET_F_CTRL_MAC_ADDR,       "   CTRL_MAC_ADDR        Set MAC address through control channel.\n" },
     109    { VIRTIONET_F_CTRL_RX,             "   CTRL_RX              Control channel RX mode support.\n" },
     110    { VIRTIONET_F_CTRL_VLAN,           "   CTRL_VLAN            Control channel VLAN filtering.\n" },
     111    { VIRTIONET_F_CTRL_GUEST_OFFLOADS, "   CTRL_GUEST_OFFLOADS  Control channel offloads reconfiguration support.\n" },
    91112    { VIRTIONET_F_GUEST_CSUM,          "   GUEST_CSUM           Guest handles packets with partial checksum.\n" },
    92     { VIRTIONET_F_CTRL_GUEST_OFFLOADS, "   CTRL_GUEST_OFFLOADS  Control channel offloads reconfiguration support.\n" },
    93     { VIRTIONET_F_MAC,                 "   MAC                  Host has given MAC address.\n" },
     113    { VIRTIONET_F_GUEST_ANNOUNCE,      "   GUEST_ANNOUNCE       Guest can send gratuitous packets.\n" },
    94114    { VIRTIONET_F_GUEST_TSO4,          "   GUEST_TSO4           Guest can receive TSOv4.\n" },
    95115    { VIRTIONET_F_GUEST_TSO6,          "   GUEST_TSO6           Guest can receive TSOv6.\n" },
     
    100120    { VIRTIONET_F_HOST_ECN,            "   HOST_ECN             Host can receive TSO with ECN.\n" },
    101121    { VIRTIONET_F_HOST_UFO,            "   HOST_UFO             Host can receive UFO.\n" },
     122    { VIRTIONET_F_MQ,                  "   MQ                   Host supports multiqueue with automatic receive steering.\n" },
     123    { VIRTIONET_F_CSUM,                "   CSUM                 Host handles packets with partial checksum.\n" },
    102124    { VIRTIONET_F_MRG_RXBUF,           "   MRG_RXBUF            Guest can merge receive buffers.\n" },
    103     { VIRTIONET_F_STATUS,              "   STATUS               Configuration status field is available.\n" },
    104     { VIRTIONET_F_CTRL_VQ,             "   CTRL_VQ              Control channel is available.\n" },
    105     { VIRTIONET_F_CTRL_RX,             "   CTRL_RX              Control channel RX mode support.\n" },
    106     { VIRTIONET_F_CTRL_VLAN,           "   CTRL_VLAN            Control channel VLAN filtering.\n" },
    107     { VIRTIONET_F_GUEST_ANNOUNCE,      "   GUEST_ANNOUNCE       Guest can send gratuitous packets.\n" },
    108     { VIRTIONET_F_MQ,                  "   MQ                   Host supports multiqueue with automatic receive steering.\n" },
    109     { VIRTIONET_F_CTRL_MAC_ADDR,       "   CTRL_MAC_ADDR        Set MAC address through control channel.\n" },
    110125};
    111 
    112126
    113127#ifdef VIRTIONET_WITH_GSO
     
    135149    | VIRTIONET_F_MRG_RXBUF
    136150
    137 /*
    138  * Glossary of networking acronyms used in the previous bit definitions:
    139  *
    140  * GSO = Generic Segmentation Offload
    141  * TSO = TCP Segmentation Offload
    142  * UFO = UDP Fragmentation Offload
    143  * ECN = Explicit Congestion Notification
    144  */
    145 
    146151#define FEATURE_ENABLED(feature)        RT_BOOL(!!(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature))
    147152#define FEATURE_DISABLED(feature)       (!FEATURE_ENABLED(feature))
    148153#define FEATURE_OFFERED(feature)        VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature
    149154
    150 #define VIRTIONET_SAVED_STATE_VERSION   UINT32_C(1)
    151 
    152155#if FEATURE_OFFERED(MQ)
    153 #   define VIRTIONET_MAX_QPAIRS         1000 /* Instance data doesn't allow an array with VIRTIONET_CTRL_MQ_VQ_PAIRS_MAX entries */
     156/* Instance data doesn't allow an array large enough to contain VIRTIONET_CTRL_MQ_VQ_PAIRS_MAX entries */
     157#   define VIRTIONET_MAX_QPAIRS         1  /* This should be increased at some point and made to work */
    154158#else
    155 #   define VIRTIONET_MAX_QPAIRS         VIRTIONET_CTRL_MQ_VQ_PAIRS_MIN
     159#   define VIRTIONET_MAX_QPAIRS         VIRTIONET_CTRL_MQ_VQ_PAIRS_MIN /* default, VirtIO 1.0, 5.1.6.5.5 */
    156160#endif
    157161
    158 #define VIRTIONET_MAX_WORKERS           VIRTIONET_MAX_QPAIRS
     162#define VIRTIONET_CTRL_MQ_VQ_PAIRS      64
     163#define VIRTIONET_MAX_WORKERS           VIRTIONET_MAX_QPAIRS + 1
    159164#define VIRTIONET_MAX_VIRTQS            (VIRTIONET_MAX_QPAIRS * 2 + 1)
    160165#define VIRTIONET_MAX_FRAME_SIZE        65535 + 18  /**< Max IP pkt size + Eth. header w/VLAN tag  */
    161 #define VIRTIONET_MAC_FILTER_LEN        32
    162 #define VIRTIONET_MAX_VLAN_ID           (1 << 12)
     166#define VIRTIONET_MAC_FILTER_LEN        64
     167#define VIRTIONET_MAX_VLAN_ID           4096
    163168#define VIRTIONET_RX_SEG_COUNT          32
    164169
     
    166171#define CBVIRTQNAME(uVirtqNbr)          RTStrNLen(VIRTQNAME(uVirtqNbr), sizeof(VIRTQNAME(uVirtqNbr)))
    167172
    168 /* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */
    169173#define IS_TX_VIRTQ(n)                  ((n) != CTRLQIDX && ((n) & 1))
    170174#define IS_RX_VIRTQ(n)                  ((n) != CTRLQIDX && !IS_TX_VIRTQ(n))
    171175#define IS_CTRL_VIRTQ(n)                ((n) == CTRLQIDX)
     176
     177/*
     178 * Macros to calculate queue type-pecific index number regardless of scale. VirtIO 1.0, 5.1.2
     179 */
    172180#define RXQIDX(qPairIdx)                (qPairIdx * 2)
    173181#define TXQIDX(qPairIdx)                (RXQIDX(qPairIdx) + 1)
     
    189197#define IS_VIRTQ_EMPTY(pDevIns, pVirtio, uVirtqNbr) \
    190198            (virtioCoreVirtqAvailBufCount(pDevIns, pVirtio, uVirtqNbr) == 0)
    191 
    192199
    193200#define PCI_DEVICE_ID_VIRTIONET_HOST               0x1000      /**< VirtIO transitional device ID for network card  */
     
    198205
    199206/**
    200  * Virtio Net Host Device device-specific configuration (VirtIO 1.0, 5.1.4)
    201  * VBox VirtIO core issues callback to this VirtIO device-specific implementation to handle
    202  * MMIO accesses to device-specific configuration parameters.
     207 * VirtIO Network (virtio-net) device-specific configuration subregion (VirtIO 1.0, 5.1.4)
     208 * Guest MMIO is processed through callback to VirtIO core which forwards references to network configuration
     209 * fields to this device-specific code through a callback.
    203210 */
    204211#pragma pack(1)
     
    260267
    261268/* Command entry fAck values */
    262 #define VIRTIONET_OK                               0
    263 #define VIRTIONET_ERROR                            1
     269#define VIRTIONET_OK                               0            /**< Internal success status                        */
     270#define VIRTIONET_ERROR                            1            /**< Internal failure status                        */
    264271
    265272/** @name Control virtq: Receive filtering flags (VirtIO 1.0, 5.1.6.5.1)
     
    315322 * @{  */
    316323#define VIRTIONET_CTRL_GUEST_OFFLOADS             5            /**< Control class: Offloads state configuration    */
    317 #define VIRTIONET_CTRL_GUEST_OFFLOADS_SET         0            /** Apply new offloads configuration                */
     324#define VIRTIONET_CTRL_GUEST_OFFLOADS_SET         0            /**< Apply new offloads configuration               */
    318325/** @} */
    319326
    320327typedef enum VIRTIONETPKTHDRTYPE
    321328{
    322     kVirtioNetModernPktHdr_1_0          = 0,
    323     kVirtioNetLegacyPktHdr              = 1,
    324     kVirtioNetLegacyPktHdrWithoutMrgRx  = 2,
     329    kVirtioNetUninitializedPktHdrType   = 0,                   /**< Uninitialized (default) packet header type      */
     330    kVirtioNetModernPktHdrWithoutMrgRx  = 1,                   /**< Packets should not be merged (modern driver)    */
     331    kVirtioNetModernPktHdrWithMrgRx     = 2,                   /**< Packets should be merged (modern driver)        */
     332    kVirtioNetLegacyPktHdrWithoutMrgRx  = 3,                   /**< Packets should not be merged (legacy driver)    */
     333    kVirtioNetLegacyPktHdrWithMrgRx     = 4,                   /**< Packets should be merged (legacy driver)        */
    325334    kVirtioNetFor32BitHack              = 0x7fffffff
    326335} VIRTIONETPKTHDRTYPE;
     
    336345    uint16_t                       uIdx;                        /**< Index of this queue                            */
    337346    uint16_t                       align;
    338     char                           szName[VIRTIO_MAX_VIRTQ_NAME_SIZE]; /**< Virtq name                              */
    339347    bool                           fCtlVirtq;                   /**< If set this queue is the control queue         */
    340348    bool                           fHasWorker;                  /**< If set this queue has an associated worker     */
    341349    bool                           fAttachedToVirtioCore;       /**< Set if queue attached to virtio core           */
    342     uint8_t                        pad;
     350    char                           szName[VIRTIO_MAX_VIRTQ_NAME_SIZE]; /**< Virtq name                              */
    343351} VIRTIONETVIRTQ, *PVIRTIONETVIRTQ;
    344352
     
    407415    uint16_t                cWorkers;
    408416
    409     /** Alighnment */
     417    /** Alignment */
    410418    uint16_t                alignment;
    411419
     
    413421    uint32_t                uIsTransmitting;
    414422
    415     /** virtio-net-1-dot-0 (in milliseconds). */
     423    /** Link up delay (in milliseconds). */
    416424    uint32_t                cMsLinkUpDelay;
    417425
     
    479487    bool                    fCableConnected;
    480488
    481     /** True if guest has not reported modern virtio driver */
    482     bool                    fIsLegacy;
     489    /** True if this device should offer legacy virtio support to the guest */
     490    bool                    fOfferLegacy;
     491
    483492    /** @name Statistic
    484493     * @{ */
     
    550559} VIRTIONETR3;
    551560
    552 
    553561/** Pointer to the ring-3 state of the VirtIO Host NET device. */
    554562typedef VIRTIONETR3 *PVIRTIONETR3;
     
    565573typedef VIRTIONETR0 *PVIRTIONETR0;
    566574
    567 
    568575/**
    569576 * VirtIO Host NET device state, raw-mode edition.
     
    577584typedef VIRTIONETRC *PVIRTIONETRC;
    578585
    579 
    580586/** @typedef VIRTIONETCC
    581587 * The instance data for the current context. */
     
    590596static int virtioNetR3CreateWorkerThreads(PPDMDEVINS, PVIRTIONET, PVIRTIONETCC);
    591597
     598/**
     599 * Helper function used when logging state of a VM thread.
     600 *
     601 * @param   Thread
     602 *
     603 * @return  Associated name of thread as a pointer to a zero-terminated string.
     604 */
    592605DECLINLINE(const char *) virtioNetThreadStateName(PPDMTHREAD pThread)
    593606{
     
    620633
    621634/**
    622  * Wakeup the RX thread.
     635 * Wakeup PDM managed downstream (e.g. hierarchically inferior device's) RX thread
    623636 */
    624637static void virtioNetWakeupRxBufWaiter(PPDMDEVINS pDevIns)
     
    638651
    639652/**
     653 * Guest notifying us of its activity with a queue. Figure out which queue and respond accordingly.
     654 *
    640655 * @callback_method_impl{VIRTIOCORER0,pfnVirtqNotified}
    641656 */
     
    662677        }
    663678        else
    664             Log10Func(("%s \n\n***WARNING: %s notified but no empty bufs added by guest! (skip notifying of leaf device)\n\n",
     679            Log10Func(("%s \n\n***WARNING: %s notified but no empty bufs added by guest! (skip leaf dev. notification)\n\n",
    665680                    pThis->szInst, pVirtq->szName));
    666681    }
     
    678693            }
    679694            else
    680             {
    681695                Log10Func(("[%s] %s has available buffers - worker already awake\n", pThis->szInst, pVirtq->szName));
    682             }
    683696        }
    684697        else
    685         {
    686698            Log10Func(("[%s] %s has available buffers - waking worker.\n", pThis->szInst, pVirtq->szName));
    687         }
    688699    }
    689700    else
     
    706717}
    707718
    708 
    709 DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis)
    710 {
    711     RTStrCopy(pThis->aVirtqs[CTRLQIDX].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "controlq");
    712     for (uint16_t qPairIdx = pThis->cInitializedVirtqPairs; qPairIdx < pThis->cVirtqPairs; qPairIdx++)
    713     {
    714         RTStrPrintf(pThis->aVirtqs[RXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "receiveq<%d>",  qPairIdx);
    715         RTStrPrintf(pThis->aVirtqs[TXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "transmitq<%d>", qPairIdx);
     719/**
     720 * Set queue names, distinguishing between modern or legacy mode.
     721 *
     722 * @note This makes it obvious during logging which mode this transitional device is
     723 *       operating in, legacy or modern.
     724 *
     725 * @param  pThis        Device specific device state
     726 * @param  fLegacy      (input) true if running in legacy mode
     727 *                              false if running in modern mode
     728 */
     729DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis, uint32_t fLegacy)
     730{
     731    RTStrCopy(pThis->aVirtqs[CTRLQIDX].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, fLegacy ? "legacy-ctrlq" : " modern-ctrlq");
     732    for (uint16_t qPairIdx = 0; qPairIdx < pThis->cVirtqPairs; qPairIdx++)
     733    {
     734        RTStrPrintf(pThis->aVirtqs[RXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "%s-recvq<%d>", fLegacy ? "legacy" : "modern", qPairIdx);
     735        RTStrPrintf(pThis->aVirtqs[TXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "%s-xmitq<%d>", fLegacy ? "legacy" : "modern", qPairIdx);
    716736    }
    717737}
     
    727747DECLINLINE(void) virtioNetR3PacketDump(PVIRTIONET pThis, const uint8_t *pbPacket, size_t cb, const char *pszText)
    728748{
     749#ifdef LOG_ENABLED
    729750    if (!LogIs12Enabled())
    730751        return;
    731 
     752#endif
    732753    vboxEthPacketDump(pThis->szInst, pszText, pbPacket, (uint32_t)cb);
    733754}
    734 
    735755
    736756#ifdef LOG_ENABLED
     
    742762    if (pRxPktHdr)
    743763    {
    744         LogFunc(("-------------------------------------------------------------------\n"));
     764        LogFunc(("%*c\nrxPktHdr\n"
     765                 "    uFlags ......... %2.2x\n    uGsoType ....... %2.2x\n    uHdrLen ........ %4.4x\n"
     766                 "    uGsoSize ....... %4.4x\n    uChksumStart ... %4.4x\n    uChksumOffset .. %4.4x\n",
     767                        60, ' ', pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
     768                        pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset));
    745769        if (!virtioCoreIsLegacyMode(&pThis->Virtio) || FEATURE_ENABLED(MRG_RXBUF))
    746                 LogFunc(("rxPktHdr\n"
    747                          "    uFlags ......... %2.2x\n    uGsoType ....... %2.2x\n    uHdrLen ........ %4.4x\n"
    748                          "    uGsoSize ....... %4.4x\n    uChksumStart ... %4.4x\n    uChksumOffset .. %4.4x\n"
    749                          "    uNumBuffers .... %4.4x\n",
    750                                 pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
    751                                 pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers));
    752         else
    753                 LogFunc(("rxPktHdr\n"
    754                          "    uFlags ......... %2.2x\n    uGsoType ....... %2.2x\n    uHdrLen ........ %4.4x\n"
    755                          "    uGsoSize ....... %4.4x\n    uChksumStart ... %4.4x\n    uChksumOffset .. %4.4x\n",
    756                                 pRxPktHdr->uFlags, pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
    757                                 pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset));
     770            LogFunc(("    uNumBuffers .... %4.4x\n", pRxPktHdr->uNumBuffers));
    758771        virtioCoreHexDump((uint8_t *)pRxPktHdr, sizeof(VIRTIONETPKTHDR), 0, "Dump of virtual rPktHdr");
    759772    }
    760773    virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
    761774    LogFunc((". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n"));
    762 
    763775    virtioCoreGCPhysHexDump(pDevIns, GCPhysRxBuf, cbRxBuf, 0, "Phys Mem Dump of Rx pkt");
    764     LogFunc(("-------------------------------------------------------------------\n"));
     776    LogFunc(("%*c", 60, '-'));
    765777}
    766778
     
    852864    if (fAll || fPointers)
    853865    {
    854         pHlp->pfnPrintf(pHlp, "Internal Pointers:\n\n");
     866        pHlp->pfnPrintf(pHlp, "Internal Pointers (for instance \"%s\"):\n\n", pThis->szInst);
    855867        pHlp->pfnPrintf(pHlp, "    pDevIns ................... %p\n",   pDevIns);
     868        pHlp->pfnPrintf(pHlp, "    PVIRTIOCORE ............... %p\n",   &pThis->Virtio);
    856869        pHlp->pfnPrintf(pHlp, "    PVIRTIONET ................ %p\n",   pThis);
    857870        pHlp->pfnPrintf(pHlp, "    PVIRTIONETCC .............. %p\n",   pThisCC);
     871        pHlp->pfnPrintf(pHlp, "    VIRTIONETVIRTQ[] .......... %p\n",   pThis->aVirtqs);
    858872        pHlp->pfnPrintf(pHlp, "    pDrvBase .................. %p\n",   pThisCC->pDrvBase);
    859873        pHlp->pfnPrintf(pHlp, "    pDrv ...................... %p\n",   pThisCC->pDrv);
     
    872886        pHlp->pfnPrintf(pHlp, "Misc state\n");
    873887        pHlp->pfnPrintf(pHlp, "\n");
     888        pHlp->pfnPrintf(pHlp, "    fOfferLegacy .............. %d\n",   pThis->fOfferLegacy);
    874889        pHlp->pfnPrintf(pHlp, "    fVirtioReady .............. %d\n",   pThis->fVirtioReady);
     890        pHlp->pfnPrintf(pHlp, "    fResetting ................ %d\n",   pThis->fResetting);
    875891        pHlp->pfnPrintf(pHlp, "    fGenUpdatePending ......... %d\n",   pThis->Virtio.fGenUpdatePending);
    876892        pHlp->pfnPrintf(pHlp, "    fMsiSupport ............... %d\n",   pThis->Virtio.fMsiSupport);
     
    929945}
    930946
    931 /*
    932  * Checks whether negotiated features have required flag combinations.
    933  * See VirtIO 1.0 specification, Section 5.1.3.1 */
     947/**
     948 * Checks whether certain mutually dependent negotiated features are clustered in required combinations.
     949 *
     950 * @note See VirtIO 1.0 spec, Section 5.1.3.1
     951 *
     952 * @param fFeatures     Bitmask of negotiated features to evaluate
     953 *
     954 * @returns             true if valid feature combination(s) found.
     955 *                      false if non-valid feature set.
     956 */
    934957DECLINLINE(bool) virtioNetValidateRequiredFeatures(uint32_t fFeatures)
    935958{
     
    969992}
    970993
     994/**
     995 * Read or write device-specific configuration parameters.
     996 * This is called by VirtIO core code a guest-initiated MMIO access is made to access device-specific
     997 * configuration
     998 *
     999 * @note  See VirtIO 1.0 spec, 2.3 Device Configuration Space
     1000 *
     1001 * @param pThis             Pointer to device-specific state
     1002 * @param uOffsetOfAccess   Offset (within VIRTIONET_CONFIG_T)
     1003 * @param pv                Pointer to data to read or write
     1004 * @param cb                Number of bytes to read or write
     1005 * @param fWrite            True if writing, false if reading
     1006 *
     1007 * @returns VINF_SUCCESS if successful, or VINF_IOM_MMIO_UNUSED if fails (bad offset or size)
     1008 */
    9711009static int virtioNetR3DevCfgAccess(PVIRTIONET pThis, uint32_t uOffsetOfAccess, void *pv, uint32_t cb, bool fWrite)
    9721010{
     
    10171055}
    10181056
     1057static int virtioNetR3VirtqDestroy(PVIRTIOCORE pVirtio, PVIRTIONETVIRTQ pVirtq)
     1058{
     1059    PVIRTIONET         pThis     = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio);
     1060    PVIRTIONETCC       pThisCC   = PDMDEVINS_2_DATA_CC(pVirtio->pDevInsR3, PVIRTIONETCC);
     1061    PVIRTIONETWORKER   pWorker   = &pThis->aWorkers[pVirtq->uIdx];
     1062    PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[pVirtq->uIdx];
     1063
     1064    int rc, rcThread;
     1065    Log10Func(("[%s] Destroying \"%s\"", pThis->szInst, pVirtq->szName));
     1066    if (pVirtq->fHasWorker)
     1067    {
     1068        Log10((" and its worker"));
     1069        rc = PDMDevHlpSUPSemEventClose(pVirtio->pDevInsR3, pWorker->hEvtProcess);
     1070        AssertRCReturn(rc, rc);
     1071        pWorker->hEvtProcess = 0;
     1072        rc = PDMDevHlpThreadDestroy(pVirtio->pDevInsR3,  pWorkerR3->pThread, &rcThread);
     1073        AssertRCReturn(rc, rc);
     1074        pWorkerR3->pThread = 0;
     1075        pVirtq->fHasWorker = false;
     1076    }
     1077    pWorker->fAssigned = false;
     1078    pVirtq->fCtlVirtq  = false;
     1079    Log10(("\n"));
     1080    return rc;
     1081}
     1082
    10191083
    10201084/*********************************************************************************************************************************
     
    10241088/**
    10251089 * @callback_method_impl{FNSSMDEVLOADEXEC}
    1026  */
    1027 static DECLCALLBACK(int) virtioNetR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     1090 *
     1091 * @note: This is included to accept and migrate VMs that had used the original VirtualBox legacy-only virtio-net (network card)
     1092 *        controller device emulator ("DevVirtioNet.cpp") to work with this superset of VirtIO compatibility known
     1093 *        as a transitional device (see PDM-invoked device constructor comments for more information)
     1094 */
     1095static DECLCALLBACK(int) virtioNetR3LegacyDeviceLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass,
     1096                                                    RTMAC uMacLoaded)
    10281097{
    10291098    PVIRTIONET     pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    10301099    PVIRTIONETCC   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    10311100    PCPDMDEVHLPR3  pHlp    = pDevIns->pHlpR3;
     1101    int rc;
     1102
     1103    Log7Func(("[%s] LOAD EXEC (LEGACY)!!\n", pThis->szInst));
     1104
     1105    if (memcmp(&uMacLoaded.au8, &pThis->macConfigured.au8, sizeof(uMacLoaded))
     1106        && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)))
     1107        LogRelFunc(("[%s]: The mac address differs: config=%RTmac saved=%RTmac\n",
     1108            pThis->szInst, &pThis->macConfigured, &uMacLoaded));
     1109
     1110        if (uPass == SSM_PASS_FINAL)
     1111        {
     1112            /* Call the virtio core to have it load legacy device state */
     1113            rc = virtioCoreR3LegacyDeviceLoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, uVersion, VIRTIONET_SAVEDSTATE_VERSION_3_1_BETA1_LEGACY);
     1114            AssertRCReturn(rc, rc);
     1115            /*
     1116             * Scan constructor-determined virtqs to determine if they are all valid-as-restored.
     1117             * If so, nudge them with a signal, otherwise destroy the unusable queue(s)
     1118             * to avoid tripping up the other queue processing logic.
     1119             */
     1120            int cVirtqsToRemove = 0;
     1121            for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
     1122            {
     1123                PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr];
     1124                if (pVirtq->fHasWorker)
     1125                {
     1126                    if (!virtioCoreR3VirtqIsEnabled(&pThis->Virtio, uVirtqNbr))
     1127                    {
     1128                        virtioNetR3VirtqDestroy(&pThis->Virtio, pVirtq);
     1129                        ++cVirtqsToRemove;
     1130                    }
     1131                    else
     1132                    {
     1133                        if (virtioCoreR3VirtqIsAttached(&pThis->Virtio, uVirtqNbr))
     1134                        {
     1135                            Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName));
     1136                            rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[pVirtq->uIdx].hEvtProcess);
     1137                            AssertRCReturn(rc, rc);
     1138                        }
     1139                    }
     1140                }
     1141            }
     1142            AssertMsg(cVirtqsToRemove < 2, ("Multiple unusable queues in saved state unexpected\n"));
     1143            pThis->cVirtqs -= cVirtqsToRemove;
     1144
     1145            pThis->virtioNetConfig.uStatus = pThis->Virtio.fDeviceStatus;
     1146            pThis->fVirtioReady = pThis->Virtio.fDeviceStatus & VIRTIO_STATUS_DRIVER_OK;
     1147
     1148            rc = pHlp->pfnSSMGetMem(pSSM, pThis->virtioNetConfig.uMacAddress.au8, sizeof(pThis->virtioNetConfig.uMacAddress));
     1149            AssertRCReturn(rc, rc);
     1150
     1151            if (uVersion > VIRTIONET_SAVEDSTATE_VERSION_3_1_BETA1_LEGACY)
     1152            {
     1153                rc = pHlp->pfnSSMGetU8( pSSM, &pThis->fPromiscuous);
     1154                AssertRCReturn(rc, rc);
     1155                rc = pHlp->pfnSSMGetU8( pSSM, &pThis->fAllMulticast);
     1156                AssertRCReturn(rc, rc);
     1157                /*
     1158                 * The 0.95 legacy virtio spec defines a control queue command VIRTIO_NET_CTRL_MAC_TABLE_SET,
     1159                 * wherein guest driver configures two variable length mac filter tables: A unicast filter,
     1160                 * and a multicast filter. However original VBox virtio-net saved both sets of filter entries
     1161                 * in a single table, abandoning the distinction between unicast and multicast filters. It preserved
     1162                 * only *one* filter's table length, leaving no way to separate table back out into respective unicast
     1163                 * and multicast tables this device implementation preserves. Deduced from legacy code, the original
     1164                 * assumption was that the both MAC filters are whitelists that can be processed identically
     1165                 * (from the standpoint of a *single* host receiver), such that the distinction between unicast and
     1166                 * multicast doesn't matter in any one VM's context. Little choice here but to save the undifferentiated
     1167                 * unicast & multicast MACs to the unicast filter table and leave multicast table empty/unused.
     1168                 */
     1169                uint32_t cCombinedUnicastMulticastEntries;
     1170                rc = pHlp->pfnSSMGetU32(pSSM, &cCombinedUnicastMulticastEntries);
     1171                AssertRCReturn(rc, rc);
     1172                AssertReturn(cCombinedUnicastMulticastEntries <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE);
     1173                pThis->cUnicastFilterMacs = cCombinedUnicastMulticastEntries;
     1174                rc = pHlp->pfnSSMGetMem(pSSM, pThis->aMacUnicastFilter, cCombinedUnicastMulticastEntries * sizeof(RTMAC));
     1175                AssertRCReturn(rc, rc);
     1176                /* Zero-out the remainder of the Unicast/Multicast filter table */
     1177                memset(&pThis->aMacUnicastFilter[pThis->cUnicastFilterMacs], 0, VIRTIONET_MAC_FILTER_LEN * sizeof(RTMAC));
     1178                rc = pHlp->pfnSSMGetMem(pSSM, pThis->aVlanFilter, sizeof(pThis->aVlanFilter));
     1179                AssertRCReturn(rc, rc);
     1180        }
     1181        else
     1182        {
     1183            pThis->fAllMulticast = false;
     1184            pThis->cUnicastFilterMacs = 0;
     1185            memset(&pThis->aMacUnicastFilter, 0, VIRTIONET_MAC_FILTER_LEN * sizeof(RTMAC));
     1186
     1187            memset(pThis->aVlanFilter, 0, sizeof(pThis->aVlanFilter));
     1188
     1189            pThis->fPromiscuous = true;
     1190            if (pThisCC->pDrv)
     1191                pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, true);
     1192        }
     1193
     1194        /*
     1195         * Log the restored VirtIO feature selection.
     1196         */
     1197        pThis->fNegotiatedFeatures = virtioCoreGetNegotiatedFeatures(&pThis->Virtio);
     1198        virtioCorePrintDeviceFeatures(&pThis->Virtio, NULL, s_aDevSpecificFeatures, RT_ELEMENTS(s_aDevSpecificFeatures));
     1199
     1200        /*
     1201         * Configure remaining transitional device parameters presumably or deductively
     1202         * as these weren't part of the legacy device code thus it didn't save them to SSM
     1203         */
     1204        pThis->fCableConnected = 1;
     1205        pThis->fAllUnicast     = 0;
     1206        pThis->fNoMulticast    = 0;
     1207        pThis->fNoUnicast      = 0;
     1208        pThis->fNoBroadcast    = 0;
     1209
     1210        /* Zero out the multicast table and count, all MAC filters, if any, are in the unicast filter table */
     1211        pThis->cMulticastFilterMacs = 0;
     1212        memset(&pThis->aMacMulticastFilter, 0, VIRTIONET_MAC_FILTER_LEN * sizeof(RTMAC));
     1213
     1214    }
     1215    return VINF_SUCCESS;
     1216}
     1217
     1218/**
     1219 * @callback_method_impl{FNSSMDEVLOADEXEC}
     1220 *
     1221 * @note: This loads state saved by a Modern (VirtIO 1.0+) device, of which this transitional device is one,
     1222 *        and thus supports both legacy and modern guest virtio drivers.
     1223 */
     1224static DECLCALLBACK(int) virtioNetR3ModernDeviceLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
     1225{
     1226    PVIRTIONET     pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     1227    PVIRTIONETCC   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
     1228    PCPDMDEVHLPR3  pHlp    = pDevIns->pHlpR3;
     1229    int rc;
    10321230
    10331231    RT_NOREF(pThisCC);
     1232
     1233    RTMAC uMacLoaded, uVersionMarkerMac = VIRTIONET_VERSION_MARKER_MAC_ADDR;
     1234    rc = pHlp->pfnSSMGetMem(pSSM, &uMacLoaded.au8, sizeof(uMacLoaded.au8));
     1235    AssertRCReturn(rc, rc);
     1236    if (memcmp(&uMacLoaded.au8, uVersionMarkerMac.au8, sizeof(uVersionMarkerMac.au8)))
     1237    {
     1238        rc = virtioNetR3LegacyDeviceLoadExec(pDevIns, pSSM, uVersion, uPass, uMacLoaded);
     1239        return rc;
     1240    }
     1241
    10341242    Log7Func(("[%s] LOAD EXEC!!\n", pThis->szInst));
    10351243
    10361244    AssertReturn(uPass == SSM_PASS_FINAL, VERR_SSM_UNEXPECTED_PASS);
    1037     AssertLogRelMsgReturn(uVersion == VIRTIONET_SAVED_STATE_VERSION,
     1245    AssertLogRelMsgReturn(uVersion == VIRTIONET_SAVEDSTATE_VERSION,
    10381246                          ("uVersion=%u\n", uVersion), VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION);
    10391247
    1040     virtioNetR3SetVirtqNames(pThis);
     1248    virtioNetR3SetVirtqNames(pThis, false /* fLegacy */);
    10411249
    10421250    pHlp->pfnSSMGetU64(     pSSM, &pThis->fNegotiatedFeatures);
    10431251
    10441252    pHlp->pfnSSMGetU16(     pSSM, &pThis->cVirtqs);
    1045     AssertReturn(pThis->cVirtqs <= (VIRTIONET_MAX_QPAIRS * 2), VERR_OUT_OF_RANGE);
    1046 
     1253    AssertReturn(pThis->cVirtqs <= (VIRTIONET_MAX_QPAIRS * 2) + 1, VERR_OUT_OF_RANGE);
    10471254    pHlp->pfnSSMGetU16(     pSSM, &pThis->cWorkers);
    1048     AssertReturn(pThis->cWorkers <= VIRTIONET_MAX_WORKERS, VERR_OUT_OF_RANGE);
    1049 
     1255    AssertReturn(pThis->cWorkers <= VIRTIONET_MAX_WORKERS , VERR_OUT_OF_RANGE);
    10501256
    10511257    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    1052         pHlp->pfnSSMGetBool(pSSM, &pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore);
    1053 
    1054     int rc;
    1055 
    1056     if (uPass == SSM_PASS_FINAL)
    1057     {
    1058 
    1059     /* Load config area */
    1060 #if FEATURE_OFFERED(STATUS)
    1061     /* config checks */
     1258            pHlp->pfnSSMGetBool(pSSM, &pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore);
     1259
     1260    /* Config checks */
    10621261    RTMAC macConfigured;
    10631262    rc = pHlp->pfnSSMGetMem(pSSM, &macConfigured.au8, sizeof(macConfigured.au8));
     
    10651264    if (memcmp(&macConfigured.au8, &pThis->macConfigured.au8, sizeof(macConfigured.au8))
    10661265        && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)))
    1067         LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n",
    1068             pThis->szInst, &pThis->macConfigured, &macConfigured));
     1266            LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n",
     1267                    pThis->szInst, &pThis->macConfigured, &macConfigured));
     1268    memcpy(pThis->virtioNetConfig.uMacAddress.au8, macConfigured.au8, sizeof(macConfigured.au8));
     1269
     1270#if FEATURE_OFFERED(STATUS)
     1271    uint16_t fChkStatus;
     1272    pHlp->pfnSSMGetU16(     pSSM, &fChkStatus);
     1273    if (fChkStatus == 0xffff)
     1274    {
     1275        /* Dummy value in saved state because status feature wasn't enabled at the time */
     1276        pThis->virtioNetConfig.uStatus = 0; /* VIRTIO_NET_S_ANNOUNCE disabled */
     1277        pThis->virtioNetConfig.uStatus = !!IS_LINK_UP(pThis); /* VIRTIO_NET_IS_LINK_UP (bit 0) */
     1278    }
     1279    else
     1280        pThis->virtioNetConfig.uStatus = fChkStatus;
     1281#else
     1282    uint16_t fDiscard;
     1283    pHlp->pfnSSMGetU16(     pSSM, &fDiscard);
    10691284#endif
    10701285
    10711286#if FEATURE_OFFERED(MQ)
    1072         pHlp->pfnSSMGetU16( pSSM, &pThis->virtioNetConfig.uMaxVirtqPairs);
     1287    uint16_t uCheckMaxVirtqPairs;
     1288    pHlp->pfnSSMGetU16(     pSSM, &uCheckMaxVirtqPairs);
     1289    if (uCheckMaxVirtqPairs)
     1290        pThis->virtioNetConfig.uMaxVirtqPairs = uCheckMaxVirtqPairs;
     1291    else
     1292        pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_CTRL_MQ_VQ_PAIRS;
     1293#else
     1294    uint16_t fDiscard;
     1295    pHlp->pfnSSMGetU16(     pSSM, &fDiscard);
    10731296#endif
    1074         /* Save device-specific part */
    1075         pHlp->pfnSSMGetBool(    pSSM, &pThis->fCableConnected);
    1076         pHlp->pfnSSMGetU8(      pSSM, &pThis->fPromiscuous);
    1077         pHlp->pfnSSMGetU8(      pSSM, &pThis->fAllMulticast);
    1078         pHlp->pfnSSMGetU8(      pSSM, &pThis->fAllUnicast);
    1079         pHlp->pfnSSMGetU8(      pSSM, &pThis->fNoMulticast);
    1080         pHlp->pfnSSMGetU8(      pSSM, &pThis->fNoUnicast);
    1081         pHlp->pfnSSMGetU8(      pSSM, &pThis->fNoBroadcast);
    1082 
    1083         pHlp->pfnSSMGetU32(     pSSM, &pThis->cMulticastFilterMacs);
    1084         AssertReturn(pThis->cMulticastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE);
    1085         pHlp->pfnSSMGetMem(     pSSM, pThis->aMacMulticastFilter, pThis->cMulticastFilterMacs * sizeof(RTMAC));
    1086 
    1087         if (pThis->cMulticastFilterMacs < VIRTIONET_MAC_FILTER_LEN)
    1088             memset(&pThis->aMacMulticastFilter[pThis->cMulticastFilterMacs], 0,
    1089                    (VIRTIONET_MAC_FILTER_LEN - pThis->cMulticastFilterMacs) * sizeof(RTMAC));
    1090 
    1091         pHlp->pfnSSMGetU32(     pSSM, &pThis->cUnicastFilterMacs);
    1092         AssertReturn(pThis->cUnicastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE);
    1093         pHlp->pfnSSMGetMem(     pSSM, pThis->aMacUnicastFilter, pThis->cUnicastFilterMacs * sizeof(RTMAC));
    1094 
    1095         if (pThis->cUnicastFilterMacs < VIRTIONET_MAC_FILTER_LEN)
    1096             memset(&pThis->aMacUnicastFilter[pThis->cUnicastFilterMacs], 0,
    1097                    (VIRTIONET_MAC_FILTER_LEN - pThis->cUnicastFilterMacs) * sizeof(RTMAC));
    1098 
    1099         rc = pHlp->pfnSSMGetMem(pSSM, pThis->aVlanFilter, sizeof(pThis->aVlanFilter));
    1100         AssertRCReturn(rc, rc);
    1101     }
    1102 
     1297
     1298    /* Save device-specific part */
     1299    pHlp->pfnSSMGetBool(    pSSM, &pThis->fCableConnected);
     1300    pHlp->pfnSSMGetU8(      pSSM, &pThis->fPromiscuous);
     1301    pHlp->pfnSSMGetU8(      pSSM, &pThis->fAllMulticast);
     1302    pHlp->pfnSSMGetU8(      pSSM, &pThis->fAllUnicast);
     1303    pHlp->pfnSSMGetU8(      pSSM, &pThis->fNoMulticast);
     1304    pHlp->pfnSSMGetU8(      pSSM, &pThis->fNoUnicast);
     1305    pHlp->pfnSSMGetU8(      pSSM, &pThis->fNoBroadcast);
     1306
     1307    pHlp->pfnSSMGetU32(     pSSM, &pThis->cMulticastFilterMacs);
     1308    AssertReturn(pThis->cMulticastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE);
     1309    pHlp->pfnSSMGetMem(     pSSM, pThis->aMacMulticastFilter, pThis->cMulticastFilterMacs * sizeof(RTMAC));
     1310
     1311    if (pThis->cMulticastFilterMacs < VIRTIONET_MAC_FILTER_LEN)
     1312        memset(&pThis->aMacMulticastFilter[pThis->cMulticastFilterMacs], 0,
     1313               (VIRTIONET_MAC_FILTER_LEN - pThis->cMulticastFilterMacs) * sizeof(RTMAC));
     1314
     1315    pHlp->pfnSSMGetU32(     pSSM, &pThis->cUnicastFilterMacs);
     1316    AssertReturn(pThis->cUnicastFilterMacs <= VIRTIONET_MAC_FILTER_LEN, VERR_OUT_OF_RANGE);
     1317    pHlp->pfnSSMGetMem(     pSSM, pThis->aMacUnicastFilter, pThis->cUnicastFilterMacs * sizeof(RTMAC));
     1318
     1319    if (pThis->cUnicastFilterMacs < VIRTIONET_MAC_FILTER_LEN)
     1320        memset(&pThis->aMacUnicastFilter[pThis->cUnicastFilterMacs], 0,
     1321               (VIRTIONET_MAC_FILTER_LEN - pThis->cUnicastFilterMacs) * sizeof(RTMAC));
     1322
     1323    rc = pHlp->pfnSSMGetMem(pSSM, pThis->aVlanFilter, sizeof(pThis->aVlanFilter));
     1324    AssertRCReturn(rc, rc);
    11031325    /*
    11041326     * Call the virtio core to let it load its state.
    11051327     */
    1106     rc = virtioCoreR3LoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM);
    1107 
     1328    rc = virtioCoreR3ModernDeviceLoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, uVersion,
     1329                                          VIRTIONET_SAVEDSTATE_VERSION, pThis->cVirtqs);
     1330    AssertRCReturn(rc, rc);
     1331    /*
     1332     * Since the control queue is created proactively in the constructor to accomodate worst-case
     1333     * legacy guests, even though the queue may have been deducted from queue count while saving state,
     1334     * we must explicitly remove queue and associated worker thread and context at this point,
     1335     * or presence of bogus control queue will confuse operations.
     1336     */
     1337    PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[CTRLQIDX];
     1338    if (FEATURE_DISABLED(CTRL_VQ) || !virtioCoreIsVirtqEnabled(&pThis->Virtio, CTRLQIDX))
     1339    {
     1340        virtioCoreR3VirtqDetach(&pThis->Virtio, CTRLQIDX);
     1341        virtioNetR3VirtqDestroy(&pThis->Virtio, pVirtq);
     1342        pVirtq->fAttachedToVirtioCore = false;
     1343        --pThis->cWorkers;
     1344    }
    11081345    /*
    11091346     * Nudge queue workers
    11101347     */
    1111     for (int uIdxWorker = 0; uIdxWorker < pThis->cWorkers; uIdxWorker++)
    1112     {
    1113         PVIRTIONETWORKER pWorker = &pThis->aWorkers[uIdxWorker];
    1114         PVIRTIONETVIRTQ  pVirtq  = &pThis->aVirtqs[uIdxWorker];
     1348    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
     1349    {
     1350        pVirtq  = &pThis->aVirtqs[uVirtqNbr];
    11151351        if (pVirtq->fAttachedToVirtioCore)
    11161352        {
    1117             Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName));
    1118             rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
    1119             AssertRCReturn(rc, rc);
     1353            if (pVirtq->fHasWorker)
     1354            {
     1355                PVIRTIONETWORKER pWorker = &pThis->aWorkers[uVirtqNbr];
     1356                Log7Func(("[%s] Waking %s worker.\n", pThis->szInst, pVirtq->szName));
     1357                rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
     1358                AssertRCReturn(rc, rc);
     1359            }
    11201360        }
    11211361    }
     1362    pThis->virtioNetConfig.uStatus = pThis->Virtio.fDeviceStatus; /* reflects state to guest driver */
     1363    pThis->fVirtioReady = pThis->Virtio.fDeviceStatus & VIRTIO_STATUS_DRIVER_OK;
     1364
    11221365    return rc;
    11231366}
     
    11261369 * @callback_method_impl{FNSSMDEVSAVEEXEC}
    11271370 */
    1128 static DECLCALLBACK(int) virtioNetR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
     1371static DECLCALLBACK(int) virtioNetR3ModernSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
    11291372{
    11301373    PVIRTIONET     pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     
    11351378    Log7Func(("[%s] SAVE EXEC!!\n", pThis->szInst));
    11361379
     1380    /* Store a dummy MAC address that would never be actually assigned to a NIC
     1381     * so that when load exec handler is called it can be easily determined
     1382     * whether saved state is modern or legacy. This works because original
     1383     * legacy code stored assigned NIC address as the first item of SSM state
     1384     */
     1385    RTMAC uVersionMarkerMac = VIRTIONET_VERSION_MARKER_MAC_ADDR;
     1386    pHlp->pfnSSMPutMem(pSSM, &uVersionMarkerMac.au8, sizeof(uVersionMarkerMac.au8));
     1387
    11371388    pHlp->pfnSSMPutU64(     pSSM, pThis->fNegotiatedFeatures);
    11381389
     
    11421393    for (int uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    11431394        pHlp->pfnSSMPutBool(pSSM, pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore);
    1144 
    1145     /* Save config area */
    1146 #if FEATURE_OFFERED(STATUS)
     1395    /*
     1396
     1397     * Save device config area (accessed via MMIO)
     1398     */
    11471399    pHlp->pfnSSMPutMem(     pSSM, pThis->virtioNetConfig.uMacAddress.au8,
    11481400                            sizeof(pThis->virtioNetConfig.uMacAddress.au8));
     1401#if FEATURE_OFFERED(STATUS)
     1402    pHlp->pfnSSMPutU16(     pSSM, pThis->virtioNetConfig.uStatus);
     1403#else
     1404    /*
     1405     * Relevant values are lower bits. Forcing this to 0xffff let's loadExec know this
     1406     * feature was not enabled in saved state. VirtIO 1.0, 5.1.4
     1407     */
     1408    pHlp->pfnSSMPutU16(     pSSM, 0xffff);
     1409
    11491410#endif
    11501411#if FEATURE_OFFERED(MQ)
    11511412    pHlp->pfnSSMPutU16(     pSSM, pThis->virtioNetConfig.uMaxVirtqPairs);
     1413#else
     1414    /*
     1415     * Legal values for max_virtqueue_pairs are 0x1 -> 0x8000 *. Forcing zero let's loadExec know this
     1416     * feature was not enabled in saved state. VirtIO 1.0, 5.1.4.1
     1417     */
     1418    pHlp->pfnSSMPutU16(     pSSM, 0);
    11521419#endif
    11531420
     
    11731440     * Call the virtio core to let it save its state.
    11741441     */
    1175     return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM);
     1442    return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, VIRTIONET_SAVEDSTATE_VERSION, pThis->cVirtqs);
    11761443}
    11771444
     
    11831450#ifdef IN_RING3
    11841451
    1185 DECLINLINE(uint16_t) virtioNetR3Checkum16(const void *pvBuf, size_t cb)
    1186 {
     1452/**
     1453 * Perform 16-bit 1's compliment checksum on provided packet in accordance with VirtIO specification,
     1454 * pertinent to VIRTIO_NET_F_CSUM feature, which 'offloads' the Checksum feature from the driver
     1455 * to save processor cycles, which is ironic in our case, where the controller device ('network card')
     1456 * is emulated on the virtualization host.
     1457 *
     1458 * @note See VirtIO 1.0 spec, 5.1.6.2 Packet Transmission
     1459 *
     1460 * @param pBuf          Pointer to r/w buffer with any portion to calculate checksum for
     1461 * @param cbSize        Number of bytes to checksum
     1462 * @param uStart        Where to start the checksum within the buffer
     1463 * @param uOffset       Offset past uStart point in the buffer to store checksum result
     1464 *
     1465 */
     1466DECLINLINE(void) virtioNetR3Calc16BitChecksum(uint8_t *pBuf, size_t cb, uint16_t uStart, uint16_t uOffset)
     1467{
     1468    AssertReturnVoid(uStart < cb);
     1469    AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cb);
     1470
    11871471    uint32_t  chksum = 0;
    1188     uint16_t *pu = (uint16_t *)pvBuf;
    1189 
     1472    uint16_t *pu = (uint16_t *)(pBuf + uStart);
     1473
     1474    cb -= uStart;
    11901475    while (cb > 1)
    11911476    {
     
    11941479    }
    11951480    if (cb)
    1196         chksum += *(uint8_t*)pu;
     1481        chksum += *(uint8_t *)pu;
    11971482    while (chksum >> 16)
    11981483        chksum = (chksum >> 16) + (chksum & 0xFFFF);
    1199     return ~chksum;
    1200 }
    1201 
    1202 DECLINLINE(void) virtioNetR3CompleteChecksum(uint8_t *pBuf, size_t cbSize, uint16_t uStart, uint16_t uOffset)
    1203 {
    1204     AssertReturnVoid(uStart < cbSize);
    1205     AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize);
    1206     *(uint16_t *)(pBuf + uStart + uOffset) = virtioNetR3Checkum16(pBuf + uStart, cbSize - uStart);
     1484
     1485    /* Store 1's compliment of calculated sum */
     1486    *(uint16_t *)(pBuf + uStart + uOffset) = ~chksum;
    12071487}
    12081488
     
    12371517}
    12381518
    1239 /*
    1240  * Returns true if VirtIO core and device are in a running and operational state
     1519/**
     1520 * Check that the core is setup and ready and co-configured with guest virtio driver,
     1521 * and verifies that the VM is running.
     1522 *
     1523 * @returns true if VirtIO core and device are in a running and operational state
    12411524 */
    12421525DECLINLINE(bool) virtioNetIsOperational(PVIRTIONET pThis, PPDMDEVINS pDevIns)
     
    12651548{
    12661549    int rc = VERR_INVALID_STATE;
    1267 
     1550    Log8Func(("[%s] ", pThis->szInst));
    12681551    if (!virtioNetIsOperational(pThis, pDevIns))
    1269         Log8Func(("[%s] No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));
    1270 
    1271     else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio, pRxVirtq->uIdx))
    1272         Log8Func(("[%s] No Rx bufs available. (%s not enabled)\n",  pThis->szInst, pRxVirtq->szName));
    1273 
    1274     else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxVirtq->uIdx))
    1275         Log8Func(("[%s] No Rx bufs available. (%s empty)\n",  pThis->szInst, pRxVirtq->szName));
     1552        Log8(("No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));
     1553
     1554    else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio,      pRxVirtq->uIdx))
     1555        Log8(("[No Rx bufs available. (%s not enabled)\n", pRxVirtq->szName));
     1556
     1557    else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio,  pRxVirtq->uIdx))
     1558        Log8(("No Rx bufs available. (%s empty)\n", pRxVirtq->szName));
    12761559
    12771560    else
    12781561    {
    1279         Log8Func(("[%s] %s has empty guest bufs avail\n",  pThis->szInst, pRxVirtq->szName));
     1562        Log8(("%s has %d empty guest bufs in avail ring\n", pRxVirtq->szName,
     1563                virtioCoreVirtqAvailBufCount(pDevIns,  &pThis->Virtio, pRxVirtq->uIdx)));
    12801564        rc = VINF_SUCCESS;
    12811565    }
     
    12841568}
    12851569
    1286 static bool virtioNetR3RxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETVIRTQ *pRxVirtq)
     1570/**
     1571 * Find an Rx queue that has Rx packets in it, if *any* do.
     1572 *
     1573 * @todo When multiqueue (MQ) mode is fully supported and tested, some kind of round-robin
     1574 *       or randomization scheme should probably be incorporated here.
     1575 *
     1576 * @returns true if Rx pkts avail on queue and sets pRxVirtq to point to queue w/pkts found
     1577 * @thread  RX
     1578 *
     1579 */
     1580static bool virtioNetR3AreRxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETVIRTQ *pRxVirtq)
    12871581{
    12881582    for (int uVirtqPair = 0; uVirtqPair < pThis->cVirtqPairs; uVirtqPair++)
     
    13111605        return VERR_INTERRUPTED;
    13121606
    1313     if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
    1314     {
    1315         Log10Func(("[%s] Rx bufs now available, releasing waiter...\n", pThis->szInst));
     1607    if (virtioNetR3AreRxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
     1608    {
     1609        Log10Func(("[%s] Rx bufs available, releasing waiter...\n", pThis->szInst));
    13161610        return VINF_SUCCESS;
    13171611    }
     
    13211615    LogFunc(("[%s] %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : ""));
    13221616
    1323 
    13241617    ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, true);
    13251618    STAM_PROFILE_START(&pThis->StatRxOverflow, a);
    13261619
    13271620    do {
    1328         if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
     1621        if (virtioNetR3AreRxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */))
    13291622        {
    13301623            Log10Func(("[%s] Rx bufs now available, releasing waiter...\n", pThis->szInst));
     
    13571650    return VERR_INTERRUPTED;
    13581651}
    1359 
    13601652
    13611653/**
     
    14381730    return (*(char*)pvBuf) & 1;
    14391731}
     1732
    14401733/**
    14411734 * Determines if the packet is to be delivered to upper layer.
     
    14491742{
    14501743
     1744#ifdef LOG_ENABLED
    14511745    if (LogIs11Enabled())
    14521746    {
     
    14651759                 pvBuf,  pszType));
    14661760    }
     1761#endif
    14671762
    14681763    if (pThis->fPromiscuous) {
     
    14851780    {
    14861781        Log11(("acpt (bcast)\n"));
     1782#ifdef LOG_ENABLED
    14871783        if (LogIs12Enabled())
    14881784            virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     1785#endif
    14891786        return true;
    14901787    }
     
    14921789    {
    14931790        Log11(("acpt (all-mcast)\n"));
     1791#ifdef LOG_ENABLED
    14941792        if (LogIs12Enabled())
    14951793            virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     1794#endif
    14961795        return true;
    14971796    }
     
    15001799    {
    15011800        Log11(("acpt (to-node)\n"));
     1801#ifdef LOG_ENABLED
    15021802        if (LogIs12Enabled())
    15031803            virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     1804#endif
    15041805        return true;
    15051806    }
     
    15101811        {
    15111812            Log11(("acpt (mcast whitelist)\n"));
     1813#ifdef LOG_ENABLED
    15121814            if (LogIs12Enabled())
    15131815                virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     1816#endif
    15141817            return true;
    15151818        }
     
    15221825            return true;
    15231826        }
    1524 
     1827#ifdef LOG_ENABLED
    15251828    if (LogIs11Enabled())
    15261829        Log(("... reject\n"));
     1830#endif
    15271831
    15281832    return false;
    15291833}
    15301834
    1531 static int virtioNetR3CopyRxPktToGuest(PPDMDEVINS pDevIns, PVIRTIONET pThis, const void *pvBuf, size_t cb,
    1532                                        PVIRTIONETPKTHDR rxPktHdr, uint16_t cSegsAllocated,
    1533                                        PRTSGBUF pVirtSegBufToGuest, PRTSGSEG paVirtSegsToGuest,
    1534                                        PVIRTIONETVIRTQ pRxVirtq)
    1535 {
    1536     RTGCPHYS GCPhysPktHdrNumBuffers = 0;
    1537     uint8_t  fAddPktHdr = true;
    1538     uint16_t cVirtqBufs  = 0;
    1539     uint64_t uOffset = 0;
    1540 
    1541     while (uOffset < cb)
    1542     {
    1543         PVIRTQBUF pVirtqBuf = NULL;
    1544 
    1545         int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, &pVirtqBuf, true);
    1546         AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc);
    1547 
    1548         /** @todo  Find a better way to deal with this */
    1549         AssertMsgReturnStmt(rc == VINF_SUCCESS && pVirtqBuf->cbPhysReturn,
    1550                             ("Not enough Rx buffers in queue to accomodate ethernet packet\n"),
    1551                             virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf),
    1552                             VERR_INTERNAL_ERROR);
    1553 
    1554         /* Length of first seg of guest Rx S/G buf should never be less than sthe packet header.
    1555          * Otherwise code has to become more complicated, e.g. locate & cache seg idx & offset of
    1556          * virtio_net_header.num_buffers, to facilitate deferring updating GCPhys memory.
    1557          * Re-visit if needed */
    1558 
    1559         AssertMsgReturn(pVirtqBuf->pSgPhysReturn->paSegs[0].cbSeg >= pThis->cbPktHdr,
    1560                             ("Out of Memory"), VERR_NO_MEMORY);
    1561 
    1562         size_t cbBufRemaining = pVirtqBuf->cbPhysReturn;
    1563 
    1564 
    1565         /* Fill the Guest Rx buffer with data received from the interface */
    1566         for (uint16_t cSegs = 0; uOffset < cb && cbBufRemaining; )
     1835
     1836/**
     1837 * This handles the case where Rx packet must be transfered to guest driver via multiple buffers using
     1838 * copy tactics slower than preferred method using a single virtq buf. Yet this is an available option
     1839 * for guests. Although cited in the spec it's to accomodate guest that perhaps have memory constraints
     1840 * wherein guest may benefit from smaller buffers (see MRG_RXBUF feature), in practice it is seen
     1841 * that without MRG_RXBUF the linux guest enqueues 'huge' multi-segment buffers so that the largest
     1842 * conceivable Rx packet can be contained in a single buffer, where for most transactions most of that
     1843 * memory will be unfilled, so it is typically both wasteful and *slower* to avoid MRG_RXBUF.
     1844 *
     1845 * As an optimization, this multi-buffer copy is only used when:
     1846 *
     1847 *     A. Guest has negotiated MRG_RXBUF
     1848 *     B. Next packet in the Rx avail queue isn't big enough to contain Rx pkt hdr+data.
     1849 *
     1850 * Architecture is defined in VirtIO 1.1 5.1.6 (Device Operations), which has improved
     1851 * wording over the VirtIO 1.0 specification, but, as an implementation note, there is one
     1852 * ambiguity that needs clarification:
     1853 *
     1854 *    The VirtIO 1.1, 5.1.6.4 explains something in a potentially misleading way. And note,
     1855 *    the VirtIO spec makes a document-wide assertion that the distinction between
     1856 *    "SHOULD" and "MUST" is to be taken quite literally.
     1857 *
     1858 *    The confusion is that VirtIO 1.1, 5.1.6.3.1 essentially says guest driver "SHOULD" populate
     1859 *    Rx queue with buffers large enough to accomodate full pkt hdr + data. That's a grammatical
     1860 *    error (dangling participle).
     1861 *
     1862 *    In practice we MUST assume "SHOULD" strictly applies to the word *populate*, -not- to buffer
     1863 *    size, because ultimately buffer minimum size is predicated on configuration parameters,
     1864 *    specifically, when MRG_RXBUF feature is disabled, the driver *MUST* provide Rx bufs
     1865 *    (if and when it can provide them), that are *large enough* to hold pkt hdr + payload.
     1866 *
     1867 *    Therefore, proper interpretation of 5.1.6.3.1 is, the guest *should* (ideally) keep Rx virtq
     1868 *    populated with appropriately sized buffers to *prevent starvation* (i.e. starvation may be
     1869 *    unavoidable thus can't be prohibited). As it would be a ludicrous to presume 5.1.6.3.1 is
     1870 *    giving guests leeway to violate MRG_RXBUF feature buf size constraints.
     1871 *
     1872 * @param pDevIns               PDM instance
     1873 * @param pThis                 Device instance
     1874 * @param pvBuf                 Pointer to incoming GSO Rx data from downstream device
     1875 * @param cb                    Amount of data given
     1876 * @param rxPktHdr              Rx pkt Header that's been massaged into VirtIO semantics
     1877 * @param pRxVirtq              Pointer to Rx virtq
     1878 * @param pVirtqBuf             Initial virtq buffer to start copying Rx hdr/pkt to guest into
     1879 *
     1880 */
     1881static int virtioNetR3RxPktMultibufXfer(PPDMDEVINS pDevIns, PVIRTIONET pThis, uint8_t *pvPktBuf, size_t cb,
     1882                                       PVIRTIONETPKTHDR pRxPktHdr, PVIRTIONETVIRTQ pRxVirtq, PVIRTQBUF pVirtqBuf)
     1883{
     1884
     1885    size_t cbBufRemaining = pVirtqBuf->cbPhysReturn;
     1886    size_t cbPktHdr = pThis->cbPktHdr;
     1887
     1888    AssertMsgReturn(cbBufRemaining >= pThis->cbPktHdr,
     1889                    ("guest-provided Rx buf not large enough to store pkt hdr"), VERR_INTERNAL_ERROR);
     1890
     1891    Log7Func(("  Sending packet header to guest...\n"));
     1892
     1893    /* Copy packet header to rx buf provided by caller. */
     1894    uint32_t cbHdrEnqueued = pVirtqBuf->cbPhysReturn == cbPktHdr ? cbPktHdr : 0;
     1895    virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cbPktHdr, pRxPktHdr, pVirtqBuf, cbHdrEnqueued);
     1896
     1897    /* Cache address of uNumBuffers field of pkthdr to update ex post facto */
     1898    RTGCPHYS GCPhysNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers);
     1899    uint16_t cVirtqBufsUsed = 1;
     1900    cbBufRemaining -= cbPktHdr;
     1901    /*
     1902     * Copy packet to guest using as many buffers as necessary, tracking and handling whether
     1903     * the buf containing the packet header was already written to the Rx queue's used buffer ring.
     1904     */
     1905    uint64_t uPktOffset = 0;
     1906    while(uPktOffset < cb)
     1907    {
     1908        Log7Func(("  Sending packet data (in buffer #%d) to guest...\n", cVirtqBufsUsed));
     1909        size_t cbBounded = RT_MIN(cbBufRemaining, cb - uPktOffset);
     1910        (void) virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cbBounded,
     1911                                    pvPktBuf + uPktOffset, pVirtqBuf, cbBounded + (cbPktHdr - cbHdrEnqueued) /* cbEnqueue */);
     1912        ++cVirtqBufsUsed;
     1913        cbBufRemaining -= cbBounded;
     1914        uPktOffset -= cbBounded;
     1915        if (uPktOffset < cb)
    15671916        {
    1568             if (fAddPktHdr)
    1569             {
    1570                 /* Lead with packet header */
    1571                 paVirtSegsToGuest[0].cbSeg = pThis->cbPktHdr;
    1572                 paVirtSegsToGuest[0].pvSeg = RTMemAlloc(pThis->cbPktHdr);
    1573                 AssertReturn(paVirtSegsToGuest[0].pvSeg, VERR_NO_MEMORY);
    1574                 cbBufRemaining -= pThis->cbPktHdr;
    1575 
    1576                 memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, pThis->cbPktHdr);
    1577 
    1578                 if (pThis->ePktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx)
    1579                 {
    1580                     /* Calculate & cache GCPhys addr of field to update after final value is known */
    1581                     GCPhysPktHdrNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys
    1582                                            + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers);
    1583                 }
    1584                 fAddPktHdr = false;
    1585                 cSegs++;
    1586             }
    1587 
    1588             if (cSegs >= cSegsAllocated)
    1589             {
    1590                 cSegsAllocated <<= 1; /* double allocation size */
    1591                 paVirtSegsToGuest = (PRTSGSEG)RTMemRealloc(paVirtSegsToGuest, sizeof(RTSGSEG) * cSegsAllocated);
    1592                 if (!paVirtSegsToGuest)
    1593                     virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf);
    1594                 AssertReturn(paVirtSegsToGuest, VERR_NO_MEMORY);
    1595             }
    1596 
    1597             /* Append remaining Rx pkt or as much current desc chain has room for */
    1598             size_t cbLimited = RT_MIN(cb, cbBufRemaining);
    1599             paVirtSegsToGuest[cSegs].cbSeg = cbLimited;
    1600             paVirtSegsToGuest[cSegs].pvSeg = ((uint8_t *)pvBuf) + uOffset;
    1601             cbBufRemaining -= cbLimited;
    1602             uOffset += cbLimited;
    1603             cVirtqBufs++;
    1604             cSegs++;
    1605             RTSgBufInit(pVirtSegBufToGuest, paVirtSegsToGuest, cSegs);
    1606             Log7Func(("Send Rx pkt to guest...\n"));
    1607             STAM_PROFILE_START(&pThis->StatReceiveStore, a);
    1608             virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx,
    1609                                         pVirtSegBufToGuest, pVirtqBuf, true /* fFence */);
    1610             STAM_PROFILE_STOP(&pThis->StatReceiveStore, a);
    1611 
    1612             if (FEATURE_DISABLED(MRG_RXBUF))
    1613                 break;
     1917            cbHdrEnqueued = cbPktHdr;
     1918            int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, &pVirtqBuf, true);
     1919
     1920            AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc);
     1921
     1922            AssertMsgReturnStmt(rc == VINF_SUCCESS && pVirtqBuf->cbPhysReturn,
     1923                                ("Not enough Rx buffers in queue to accomodate ethernet packet\n"),
     1924                                virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf),
     1925                                VERR_INTERNAL_ERROR);
    16141926        }
    1615         virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf);
    1616     }
    1617 
    1618     if (uOffset < cb)
    1619     {
    1620         LogFunc(("[%s] Packet did not fit into RX queue (packet size=%u)!\n", pThis->szInst, cb));
    1621         return VERR_TOO_MUCH_DATA;
    1622     }
    1623 
    1624 
    1625     if (pThis->ePktHdrType != kVirtioNetLegacyPktHdrWithoutMrgRx)
    1626     {
    1627         /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */
    1628         int rc = virtioCoreGCPhysWrite(&pThis->Virtio, pDevIns, GCPhysPktHdrNumBuffers, &cVirtqBufs, sizeof(cVirtqBufs));
    1629         AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc);
    1630     }
    1631 
     1927    }
     1928
     1929    /* Fix-up pkthdr (in guest phys. memory) with number of buffers (descriptors) that were processed */
     1930    int rc = virtioCoreGCPhysWrite(&pThis->Virtio, pDevIns, GCPhysNumBuffers, &cVirtqBufsUsed, sizeof(cVirtqBufsUsed));
     1931    AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc);
     1932
     1933    virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf);
    16321934    virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, pRxVirtq->uIdx);
    1633 
    1634     return VINF_SUCCESS;
    1635 }
    1636 
     1935    Log7(("\n"));
     1936    return rc;
     1937}
    16371938
    16381939/**
     
    16511952 * @thread  RX
    16521953 */
    1653 static int virtioNetR3HandleRxPacket(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    1654                                      const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso, PVIRTIONETVIRTQ pRxVirtq)
     1954
     1955static int virtioNetR3CopyRxPktToGuest(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, const void *pvBuf, size_t cb,
     1956                                       PVIRTIONETPKTHDR pRxPktHdr, uint8_t cbPktHdr, PVIRTIONETVIRTQ pRxVirtq)
    16551957{
    16561958    RT_NOREF(pThisCC);
    1657 
    1658     LogFunc(("[%s] (%RTmac) pGso %s\n", pThis->szInst, pvBuf, pGso ? "present" : "not present"));
    1659     VIRTIONETPKTHDR rxPktHdr;
    1660 
     1959    PVIRTQBUF pVirtqBuf;
     1960    int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, &pVirtqBuf, true);
     1961
     1962    AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc);
     1963
     1964    AssertMsgReturnStmt(rc == VINF_SUCCESS && pVirtqBuf->cbPhysReturn,
     1965                        ("Not enough Rx buffers or capacity to accommodate ethernet packet\n"),
     1966                        virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf),
     1967                        VERR_INTERNAL_ERROR);
     1968    /*
     1969     * Try to do fast (e.g. single-buffer) copy to guest, even if MRG_RXBUF feature is enabled
     1970     * If
     1971     */
     1972    STAM_PROFILE_START(&pThis->StatReceiveStore, a);
     1973    if (RT_LIKELY(FEATURE_DISABLED(MRG_RXBUF))
     1974        || RT_LIKELY(pVirtqBuf->cbPhysReturn > cb + cbPktHdr))
     1975    {
     1976        Log7Func(("Send Rx packet header and data to guest (single-buffer copy)...\n"));
     1977        pRxPktHdr->uNumBuffers = 1;
     1978        rc = virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cbPktHdr,  pRxPktHdr, pVirtqBuf, 0  /* cbEnqueue */);
     1979        AssertMsgReturn(rc == VINF_SUCCESS, ("%Rrc\n", rc), rc);
     1980        rc = virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, cb, pvBuf, pVirtqBuf, cbPktHdr + cb /* cbEnqueue */);
     1981        AssertMsgReturn(rc == VINF_SUCCESS, ("%Rrc\n", rc), rc);
     1982        virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf);
     1983        virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, pRxVirtq->uIdx);
     1984    }
     1985    else
     1986    {
     1987        Log7Func(("Send Rx pkt to guest (merged-buffer copy [MRG_RXBUF feature])...\n"));
     1988        rc = virtioNetR3RxPktMultibufXfer(pDevIns, pThis, (uint8_t *)pvBuf, cb, pRxPktHdr, pRxVirtq, pVirtqBuf);
     1989        return rc;
     1990    }
     1991    STAM_PROFILE_STOP(&pThis->StatReceiveStore, a);
     1992    return VINF_SUCCESS;
     1993}
     1994
     1995/**
     1996 * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso}
     1997 */
     1998static DECLCALLBACK(int) virtioNetR3NetworkDown_ReceiveGso(
     1999                                 PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso)
     2000{
     2001    PVIRTIONETCC    pThisCC  = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown);
     2002    PPDMDEVINS      pDevIns  = pThisCC->pDevIns;
     2003    PVIRTIONET      pThis    = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     2004    VIRTIONETPKTHDR rxPktHdr = { 0, VIRTIONET_HDR_GSO_NONE, 0, 0, 0, 0, 0 };
     2005
     2006    if (!pThis->fVirtioReady)
     2007    {
     2008        LogRelFunc(("VirtIO not ready, aborting downstream receive\n"));
     2009        return VERR_INTERRUPTED;
     2010    }
     2011    /*
     2012     * If GSO (Global Segment Offloading) was received from downstream PDM network device, massage the
     2013     * PDM-provided GSO parameters into VirtIO semantics, which get passed to guest virtio-net via
     2014     * Rx pkt header.  See VirtIO 1.1, 5.1.6 Device Operation for more information.
     2015     */
    16612016    if (pGso)
    16622017    {
    1663         Log2Func(("[%s] gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
    1664               pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal,
    1665               pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
    1666 
    1667         rxPktHdr.uFlags = VIRTIONET_HDR_F_NEEDS_CSUM;
     2018        LogFunc(("[%s] (%RTmac) \n", pThis->szInst, pvBuf));
     2019
     2020        rxPktHdr.uFlags        = VIRTIONET_HDR_F_NEEDS_CSUM;
     2021        rxPktHdr.uHdrLen       = pGso->cbHdrsTotal;
     2022        rxPktHdr.uGsoSize      = pGso->cbMaxSeg;
     2023        rxPktHdr.uChksumStart  = pGso->offHdr2;
     2024
    16682025        switch (pGso->u8Type)
    16692026        {
     
    16812038                break;
    16822039            default:
    1683                 return VERR_INVALID_PARAMETER;
     2040                LogFunc(("[%s] GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type));
     2041                return VERR_NOT_SUPPORTED;
    16842042        }
    1685         rxPktHdr.uHdrLen        = pGso->cbHdrsTotal;
    1686         rxPktHdr.uGsoSize       = pGso->cbMaxSeg;
    1687         rxPktHdr.uChksumStart   = pGso->offHdr2;
    1688         rxPktHdr.uNumBuffers    = 0;
    16892043        STAM_REL_COUNTER_INC(&pThis->StatReceiveGSO);
    1690     }
    1691     else
    1692     {
    1693         rxPktHdr.uFlags         = 0;
    1694         rxPktHdr.uGsoType       = VIRTIONET_HDR_GSO_NONE;
    1695         rxPktHdr.uHdrLen        = 0;
    1696         rxPktHdr.uGsoSize       = 0;
    1697         rxPktHdr.uChksumStart   = 0;
    1698         rxPktHdr.uChksumOffset  = 0;
    1699         rxPktHdr.uNumBuffers    = 0;
    1700     }
    1701 
    1702     uint16_t cSegsAllocated = VIRTIONET_RX_SEG_COUNT;
    1703 
    1704     PRTSGBUF pVirtSegBufToGuest = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF));
    1705     AssertReturn(pVirtSegBufToGuest, VERR_NO_MEMORY);
    1706 
    1707     PRTSGSEG paVirtSegsToGuest  = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * cSegsAllocated);
    1708     AssertReturnStmt(paVirtSegsToGuest, RTMemFree(pVirtSegBufToGuest), VERR_NO_MEMORY);
    1709 
    1710     int rc = virtioNetR3CopyRxPktToGuest(pDevIns, pThis, pvBuf, cb, &rxPktHdr, cSegsAllocated,
    1711                                         pVirtSegBufToGuest, paVirtSegsToGuest, pRxVirtq);
    1712 
    1713     RTMemFree(paVirtSegsToGuest);
    1714     RTMemFree(pVirtSegBufToGuest);
    1715 
    1716     Log7(("\n"));
    1717     return rc;
    1718 }
    1719 
    1720 /**
    1721  * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso}
    1722  */
    1723 static DECLCALLBACK(int) virtioNetR3NetworkDown_ReceiveGso(PPDMINETWORKDOWN pInterface, const void *pvBuf,
    1724                                                size_t cb, PCPDMNETWORKGSO pGso)
    1725 {
    1726     PVIRTIONETCC    pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown);
    1727     PPDMDEVINS      pDevIns = pThisCC->pDevIns;
    1728     PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1729 
    1730     if (!pThis->fVirtioReady)
    1731     {
    1732         LogRelFunc(("VirtIO not ready, aborting downstream receive\n"));
    1733         return VERR_INTERRUPTED;
    1734     }
    1735 
    1736     if (pGso)
    1737     {
    1738         uint32_t uFeatures = pThis->fNegotiatedFeatures;
    1739 
    1740         switch (pGso->u8Type)
    1741         {
    1742             case PDMNETWORKGSOTYPE_IPV4_TCP:
    1743                 uFeatures &= VIRTIONET_F_GUEST_TSO4;
    1744                 break;
    1745             case PDMNETWORKGSOTYPE_IPV6_TCP:
    1746                 uFeatures &= VIRTIONET_F_GUEST_TSO6;
    1747                 break;
    1748             case PDMNETWORKGSOTYPE_IPV4_UDP:
    1749             case PDMNETWORKGSOTYPE_IPV6_UDP:
    1750                 uFeatures &= VIRTIONET_F_GUEST_UFO;
    1751                 break;
    1752             default:
    1753                 uFeatures = 0;
    1754                 break;
    1755         }
    1756         if (!uFeatures)
    1757         {
    1758             LogFunc(("[%s] GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type));
    1759             return VERR_NOT_SUPPORTED;
    1760         }
    1761     }
    1762 
    1763     Log10Func(("[%s] pvBuf=%p cb=%3u pGso=%p ...\n", pThis->szInst, pvBuf, cb, pGso));
    1764 
    1765     /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue
    1766               selection algorithm feasible or even necessary to prevent starvation? */
    1767 
     2044        Log2Func(("[%s] gso type=%#x, cbHdrsTotal=%u cbHdrsSeg=%u mss=%u offHdr1=%#x offHdr2=%#x\n",
     2045                        pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg,
     2046                        pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
     2047    }
     2048
     2049    /*
     2050     * Find a virtq with Rx bufs on avail ring, if any, and copy the packet to the guest's Rx buffer.
     2051     * @todo pk: PROBABLY NOT A SOPHISTICATED ENOUGH QUEUE SELECTION ALGORTITH FOR OPTIMAL MQ (FEATURE) SUPPORT
     2052     */
    17682053    for (int uVirtqPair = 0; uVirtqPair < pThis->cVirtqPairs; uVirtqPair++)
    17692054    {
    1770 
    17712055        PVIRTIONETVIRTQ pRxVirtq = &pThis->aVirtqs[RXQIDX(uVirtqPair)];
    17722056        if (RT_SUCCESS(virtioNetR3CheckRxBufsAvail(pDevIns, pThis, pRxVirtq)))
    17732057        {
     2058            int rc = VINF_SUCCESS;
    17742059            STAM_PROFILE_START(&pThis->StatReceive, a);
    17752060            virtioNetR3SetReadLed(pThisCC, true);
    1776 
    1777             int rc = VINF_SUCCESS;
    17782061            if (virtioNetR3AddressFilter(pThis, pvBuf, cb))
    17792062            {
    1780                 rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso, pRxVirtq);
     2063                /* rxPktHdr is local stack variable that should not go out of scope in this use */
     2064                rc = virtioNetR3CopyRxPktToGuest(pDevIns, pThis, pThisCC, pvBuf, cb, &rxPktHdr, pThis->cbPktHdr, pRxVirtq);
    17812065                STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb);
    17822066            }
    1783 
    17842067            virtioNetR3SetReadLed(pThisCC, false);
    17852068            STAM_PROFILE_STOP(&pThis->StatReceive, a);
     
    17952078static DECLCALLBACK(int) virtioNetR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
    17962079{
     2080
     2081#ifdef LOG_ENABLED
     2082    PVIRTIONETCC    pThisCC  = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown);
     2083    PPDMDEVINS      pDevIns  = pThisCC->pDevIns;
     2084    PVIRTIONET      pThis    = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     2085    LogFunc(("[%s] (%RTmac)\n", pThis->szInst, pvBuf));
     2086#endif
     2087
    17972088    return virtioNetR3NetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL);
    17982089}
    17992090
    1800 
     2091/*
     2092 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's Rx packet receive filtering.
     2093 * See VirtIO 1.0, 5.1.6.5.1
     2094 *
     2095 * @param pThis         virtio-net instance
     2096 * @param pCtrlPktHdr   Control packet header (which includes command parameters)
     2097 * @param pVirtqBuf     Buffer from ctrlq buffer (contains command data)
     2098 */
    18012099static uint8_t virtioNetR3CtrlRx(PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    18022100                                 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
     
    18642162}
    18652163
     2164/*
     2165 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's MAC filter tables
     2166 * See VirtIO 1.0, 5.1.6.5.2
     2167 *
     2168 * @param pThis         virtio-net instance
     2169 * @param pCtrlPktHdr   Control packet header (which includes command parameters)
     2170 * @param pVirtqBuf     Buffer from ctrlq buffer (contains command data)
     2171 */
    18662172static uint8_t virtioNetR3CtrlMac(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
    18672173{
     
    18822188                            ("DESC chain too small to process CTRL_MAC_ADDR_SET cmd\n"), VIRTIONET_ERROR);
    18832189
    1884             virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->rxFilterMacDefault, sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN));
     2190            virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->rxFilterMacDefault, sizeof(RTMAC));
    18852191            break;
    18862192        }
     
    18902196
    18912197            /* Load unicast MAC filter table */
    1892 
    18932198            AssertMsgReturn(cbRemaining >= sizeof(cMacs),
    18942199                           ("DESC chain too small to process CTRL_MAC_TABLE_SET cmd\n"), VIRTIONET_ERROR);
     
    18962201            /* Fetch count of unicast filter MACs from guest buffer */
    18972202            virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &cMacs, sizeof(cMacs));
    1898 
    18992203            cbRemaining -= sizeof(cMacs);
    19002204
     
    19052209                uint32_t cbMacs = cMacs * sizeof(RTMAC);
    19062210
     2211                AssertMsgReturn(cbMacs <= sizeof(pThis->aMacUnicastFilter)  / sizeof(RTMAC),
     2212                                ("Guest provided Unicast MAC filter table exceeds hardcoded table size"), VIRTIONET_ERROR);
     2213
    19072214                AssertMsgReturn(cbRemaining >= cbMacs,
    19082215                                ("Virtq buffer too small to process CTRL_MAC_TABLE_SET cmd\n"), VIRTIONET_ERROR);
    19092216
     2217
    19102218                /* Fetch unicast table contents from guest buffer */
    19112219                virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->aMacUnicastFilter, cbMacs);
    1912 
    19132220                cbRemaining -= cbMacs;
    19142221            }
     
    19212228            /* Fetch count of multicast filter MACs from guest buffer */
    19222229            virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &cMacs, sizeof(cMacs));
    1923 
    19242230            cbRemaining -= sizeof(cMacs);
    19252231
    19262232            Log10Func(("[%s] Guest provided %d multicast MAC Table entries\n", pThis->szInst, cMacs));
    1927 
    19282233
    19292234            if (cMacs)
     
    19312236                uint32_t cbMacs = cMacs * sizeof(RTMAC);
    19322237
     2238                AssertMsgReturn(cbMacs <= sizeof(pThis->aMacMulticastFilter)  / sizeof(RTMAC),
     2239                                ("Guest provided Unicast MAC filter table exceeds hardcoded table size"), VIRTIONET_ERROR);
     2240
    19332241                AssertMsgReturn(cbRemaining >= cbMacs,
    19342242                                ("Virtq buffer too small to process CTRL_MAC_TABLE_SET cmd\n"), VIRTIONET_ERROR);
     
    19362244                /* Fetch multicast table contents from guest buffer */
    19372245                virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &pThis->aMacMulticastFilter, cbMacs);
    1938 
    19392246                cbRemaining -= cbMacs;
    19402247            }
     
    19432250#ifdef LOG_ENABLED
    19442251            LogFunc(("[%s] unicast MACs:\n", pThis->szInst));
    1945             for(unsigned i = 0; i < cMacs; i++)
     2252            for(unsigned i = 0; i < pThis->cUnicastFilterMacs; i++)
    19462253                LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
    19472254
    19482255            LogFunc(("[%s] multicast MACs:\n", pThis->szInst));
    1949             for(unsigned i = 0; i < cMacs; i++)
     2256            for(unsigned i = 0; i < pThis->cMulticastFilterMacs; i++)
    19502257                LogFunc(("         %RTmac\n", &pThis->aMacMulticastFilter[i]));
    19512258#endif
     
    19592266}
    19602267
     2268/*
     2269 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's MQ (multiqueue) operations.
     2270 * See VirtIO 1.0, 5.1.6.5.5
     2271 *
     2272 * @param pThis         virtio-net instance
     2273 * @param pCtrlPktHdr   Control packet header (which includes command parameters)
     2274 * @param pVirtqBuf     Buffer from ctrlq buffer (contains command data)
     2275 */
    19612276static uint8_t virtioNetR3CtrlMultiQueue(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMDEVINS pDevIns, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
    19622277{
     
    19962311    if (pThis->cVirtqPairs > pThis->cInitializedVirtqPairs)
    19972312    {
    1998         virtioNetR3SetVirtqNames(pThis);
     2313        virtioNetR3SetVirtqNames(pThis, virtioCoreIsLegacyMode(&pThis->Virtio));
    19992314        int rc = virtioNetR3CreateWorkerThreads(pDevIns, pThis, pThisCC);
    20002315        if (RT_FAILURE(rc))
     
    20072322}
    20082323
     2324/*
     2325 * Dispatched to here from virtioNetR3Ctrl() to configure this virtio-net device's VLAN filtering.
     2326 * See VirtIO 1.0, 5.1.6.5.3
     2327 *
     2328 * @param pThis         virtio-net instance
     2329 * @param pCtrlPktHdr   Control packet header (which includes command parameters)
     2330 * @param pVirtqBuf     Buffer from ctrlq buffer (contains command data)
     2331 */
    20092332static uint8_t virtioNetR3CtrlVlan(PVIRTIONET pThis, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf)
    20102333{
     
    20402363}
    20412364
     2365/**
     2366 * Processes control command from guest.
     2367 * See VirtIO 1.0 spec, 5.1.6 "Device Operation" and 5.1.6.5 "Control Virtqueue".
     2368 *
     2369 * The control command is contained in a virtio buffer pulled from the virtio-net defined control queue (ctrlq).
     2370 * Command type is parsed is dispatched to a command-specific device-configuration handler function (e.g. RX, MAC, VLAN, MQ
     2371 * and ANNOUNCE).
     2372 *
     2373 * This function handles all parts of the host-side of the ctrlq round-trip buffer processing.
     2374 *
     2375 * Invoked by worker for virtio-net defince control queue to process a queued control command buffer.
     2376 *
     2377 * @param pDevIns       PDM device instance
     2378 * @param pThis         virtio-net device instance
     2379 * @param pThisCC       virtio-net device instance
     2380 * @param pVirtqBuf     pointer to buffer pulled from virtq (input to this function)
     2381 */
    20422382static void virtioNetR3Ctrl(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    20432383                            PVIRTQBUF pVirtqBuf)
    20442384{
     2385    if (!(pThis->fNegotiatedFeatures & VIRTIONET_F_CTRL_VQ))
     2386        LogFunc(("[%s] WARNING: Guest using CTRL queue w/o negotiating VIRTIONET_F_CTRL_VQ feature\n", pThis->szInst));
     2387
    20452388    LogFunc(("[%s] Received CTRL packet from guest\n", pThis->szInst));
    20462389
     
    20992442                break;
    21002443            }
     2444#if FEATURE_OFFERED(STATUS)
    21012445            pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_ANNOUNCE;
     2446#endif
    21022447            Log7Func(("[%s] Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst));
    21032448            break;
     
    21452490}
    21462491
    2147 static int virtioNetR3ReadHeader(PVIRTIOCORE pVirtio, PVIRTIONET pThis, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame)
     2492/**
     2493 * Reads virtio-net pkt header from provided Phy. addr of virtio descriptor chain
     2494 * (e.g. S/G segment from guest-driver provided buffer pulled from Tx virtq)
     2495 * Verifies state and supported modes, sets TCP header size.
     2496 *
     2497 * @param pVirtio      VirtIO core instance data
     2498 * @param pThis        virtio-net instance
     2499 * @param pDevIns      PDM device instance
     2500 * @param GCPhys       Phys. Address from where to read virtio-net pkt header
     2501 * @param pPktHdr      Where to store read Tx pkt hdr (virtio pkt hdr size is determined from instance configuration)
     2502 * @param cbFrame      Total pkt frame size to inform bounds check
     2503 */
     2504static int virtioNetR3ReadVirtioTxPktHdr(PVIRTIOCORE pVirtio, PVIRTIONET pThis, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, PVIRTIONETPKTHDR pPktHdr, size_t cbFrame)
    21482505{
    21492506    int rc = virtioCoreGCPhysRead(pVirtio, pDevIns, GCPhys, pPktHdr, pThis->cbPktHdr);
     
    21572514    if (pPktHdr->uGsoType)
    21582515    {
    2159         uint32_t uMinHdrSize;
    2160 
    21612516        /* Segmentation offloading cannot be done without checksumming, and we do not support ECN */
    21622517        AssertMsgReturn(    RT_LIKELY(pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM)
     
    21642519                         ("Unsupported ECN request in pkt header\n"), VERR_NOT_SUPPORTED);
    21652520
     2521        uint32_t uTcpHdrSize;
    21662522        switch (pPktHdr->uGsoType)
    21672523        {
    21682524            case VIRTIONET_HDR_GSO_TCPV4:
    21692525            case VIRTIONET_HDR_GSO_TCPV6:
    2170                 uMinHdrSize = sizeof(RTNETTCP);
     2526                uTcpHdrSize = sizeof(RTNETTCP);
    21712527                break;
    21722528            case VIRTIONET_HDR_GSO_UDP:
    2173                 uMinHdrSize = 0;
     2529                uTcpHdrSize = 0;
    21742530                break;
    21752531            default:
     
    21782534        }
    21792535        /* Header + MSS must not exceed the packet size. */
    2180         AssertMsgReturn(RT_LIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGsoSize <= cbFrame),
     2536        AssertMsgReturn(RT_LIKELY(uTcpHdrSize + pPktHdr->uChksumStart + pPktHdr->uGsoSize <= cbFrame),
    21812537                    ("Header plus message exceeds packet size"), VERR_BUFFER_OVERFLOW);
    21822538    }
     
    21912547}
    21922548
     2549/**
     2550 * Transmits single GSO frame via PDM framework to downstream PDM device, to emit from virtual NIC.
     2551 *
     2552 * This does final prep of GSO parameters including checksum calculation if configured
     2553 * (e.g. if VIRTIONET_HDR_F_NEEDS_CSUM flag is set).
     2554 *
     2555 * @param pThis         virtio-net instance
     2556 * @param pThisCC       virtio-net instance
     2557 * @param pSgBuf        PDM S/G buffer containing pkt and hdr to transmit
     2558 * @param pGso          GSO parameters used for the packet
     2559 * @param pPktHdr       virtio-net pkt header to adapt to PDM semantics
     2560 */
    21932561static int virtioNetR3TransmitFrame(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMSCATTERGATHER pSgBuf,
    21942562                               PPDMNETWORKGSO pGso, PVIRTIONETPKTHDR pPktHdr)
    21952563{
     2564
    21962565    virtioNetR3PacketDump(pThis, (uint8_t *)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, "--> Outgoing");
    21972566    if (pGso)
    21982567    {
    2199         /* Some guests (RHEL) may report HdrLen excluding transport layer header! */
    2200         /*
    2201          * We cannot use cdHdrs provided by the guest because of different ways
    2202          * it gets filled out by different versions of kernels.
    2203          */
    2204         //if (pGso->cbHdrs < pPktHdr->uCSumStart + pPktHdr->uCSumOffset + 2)
     2568        /* Some guests (RHEL) may report HdrLen excluding transport layer header!
     2569         * Thus cannot use cdHdrs provided by the guest because of different ways
     2570         * it gets filled out by different versions of kernels. */
     2571        Log4Func(("%s HdrLen before adjustment %d.\n", pThis->szInst, pGso->cbHdrsTotal));
     2572        switch (pGso->u8Type)
    22052573        {
    2206             Log4Func(("%s HdrLen before adjustment %d.\n",
    2207                   pThis->szInst, pGso->cbHdrsTotal));
    2208             switch (pGso->u8Type)
    2209             {
    2210                 case PDMNETWORKGSOTYPE_IPV4_TCP:
    2211                 case PDMNETWORKGSOTYPE_IPV6_TCP:
    2212                     pGso->cbHdrsTotal = pPktHdr->uChksumStart +
    2213                         ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pPktHdr->uChksumStart))->th_off * 4;
    2214 
    2215                     AssertMsgReturn(pSgBuf->cbUsed > pGso->cbHdrsTotal,
    2216                         ("cbHdrsTotal exceeds size of frame"), VERR_BUFFER_OVERFLOW);
    2217 
    2218                     pGso->cbHdrsSeg   = pGso->cbHdrsTotal;
    2219                     break;
    2220                 case PDMNETWORKGSOTYPE_IPV4_UDP:
    2221                     pGso->cbHdrsTotal = (uint8_t)(pPktHdr->uChksumStart + sizeof(RTNETUDP));
    2222                     pGso->cbHdrsSeg = pPktHdr->uChksumStart;
    2223                     break;
    2224             }
    2225             /* Update GSO structure embedded into the frame */
    2226             ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal;
    2227             ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg   = pGso->cbHdrsSeg;
    2228             Log4Func(("%s adjusted HdrLen to %d.\n",
    2229                   pThis->szInst, pGso->cbHdrsTotal));
     2574            case PDMNETWORKGSOTYPE_IPV4_TCP:
     2575            case PDMNETWORKGSOTYPE_IPV6_TCP:
     2576                pGso->cbHdrsTotal = pPktHdr->uChksumStart +
     2577                    ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pPktHdr->uChksumStart))->th_off * 4;
     2578                AssertMsgReturn(pSgBuf->cbUsed > pGso->cbHdrsTotal,
     2579                    ("cbHdrsTotal exceeds size of frame"), VERR_BUFFER_OVERFLOW);
     2580                pGso->cbHdrsSeg   = pGso->cbHdrsTotal;
     2581                break;
     2582            case PDMNETWORKGSOTYPE_IPV4_UDP:
     2583                pGso->cbHdrsTotal = (uint8_t)(pPktHdr->uChksumStart + sizeof(RTNETUDP));
     2584                pGso->cbHdrsSeg = pPktHdr->uChksumStart;
     2585                break;
    22302586        }
     2587        /* Update GSO structure embedded into the frame */
     2588        ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal;
     2589        ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg   = pGso->cbHdrsSeg;
     2590        Log4Func(("%s adjusted HdrLen to %d.\n",
     2591              pThis->szInst, pGso->cbHdrsTotal));
    22312592        Log2Func(("%s gso type=%x cbHdrsTotal=%u cbHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
    22322593                  pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg,
     
    22402601         * This is not GSO frame but checksum offloading is requested.
    22412602         */
    2242         virtioNetR3CompleteChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed,
     2603        virtioNetR3Calc16BitChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed,
    22432604                             pPktHdr->uChksumStart, pPktHdr->uChksumOffset);
    22442605    }
     
    22472608}
    22482609
    2249 static int virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
     2610/**
     2611 * Non-reentrant function transmits all available packets from specified Tx virtq to downstream
     2612 * PDM device (if cable is connected). For each Tx pkt, virtio-net pkt header is converted
     2613 * to required GSO information (VBox host network stack semantics)
     2614 *
     2615 * @param pDevIns           PDM device instance
     2616 * @param pThis             virtio-net device instance
     2617 * @param pThisCC           virtio-net device instance
     2618 * @param pTxVirtq          Address of transmit virtq
     2619 * @param fOnWorkerThread   Flag to PDM whether to use caller's or or PDM transmit worker's thread.
     2620 */
     2621static int virtioNetR3TransmitPkts(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    22502622                                         PVIRTIONETVIRTQ pTxVirtq, bool fOnWorkerThread)
    22512623{
    2252 
    22532624    PVIRTIOCORE pVirtio = &pThis->Virtio;
    22542625
     
    22682639
    22692640    /*
    2270      * Only one thread is allowed to transmit at a time, others should skip
    2271      * transmission as the packets will be picked up by the transmitting
    2272      * thread.
     2641     * Only one thread is allowed to transmit at a time, others should skip transmission as the packets
     2642     * will be picked up by the transmitting thread.
    22732643     */
    22742644    if (!ASMAtomicCmpXchgU32(&pThis->uIsTransmitting, 1, 0))
    22752645        return VERR_IGNORED;
    2276 
    2277 
    22782646
    22792647    PPDMINETWORKUP pDrv = pThisCC->pDrv;
     
    22882656        }
    22892657    }
    2290 
    22912658    int cPkts = virtioCoreVirtqAvailBufCount(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx);
    22922659    if (!cPkts)
     
    23132680        PVIRTIOSGSEG paSegsFromGuest = pSgPhysSend->paSegs;
    23142681        uint32_t cSegsFromGuest = pSgPhysSend->cSegs;
    2315         size_t uSize = 0;
     2682        size_t uFrameSize = 0;
    23162683
    23172684        AssertMsgReturn(paSegsFromGuest[0].cbSeg >= pThis->cbPktHdr,
     
    23222689        AssertMsgReturn(pPktHdr, ("Out of Memory\n"), VERR_NO_MEMORY);
    23232690
    2324         /* Compute total frame size. */
    2325         for (unsigned i = 0; i < cSegsFromGuest && uSize < VIRTIONET_MAX_FRAME_SIZE; i++)
    2326             uSize +=  paSegsFromGuest[i].cbSeg;
    2327 
    2328         Log5Func(("[%s] complete frame is %u bytes.\n", pThis->szInst, uSize));
    2329         Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE);
     2691        /* Compute total frame size from guest (including virtio-net pkt hdr) */
     2692        for (unsigned i = 0; i < cSegsFromGuest && uFrameSize < VIRTIONET_MAX_FRAME_SIZE; i++)
     2693            uFrameSize +=  paSegsFromGuest[i].cbSeg;
     2694
     2695        Log5Func(("[%s] complete frame is %u bytes.\n", pThis->szInst, uFrameSize));
     2696        Assert(uFrameSize <= VIRTIONET_MAX_FRAME_SIZE);
    23302697
    23312698        /* Truncate oversized frames. */
    2332         if (uSize > VIRTIONET_MAX_FRAME_SIZE)
    2333             uSize = VIRTIONET_MAX_FRAME_SIZE;
     2699        if (uFrameSize > VIRTIONET_MAX_FRAME_SIZE)
     2700            uFrameSize = VIRTIONET_MAX_FRAME_SIZE;
    23342701
    23352702        if (pThisCC->pDrv)
    23362703        {
    2337             uint64_t uOffset;
    2338 
    2339             uSize -= pThis->cbPktHdr;
    2340             rc = virtioNetR3ReadHeader(pVirtio, pThis, pDevIns, paSegsFromGuest[0].GCPhys, pPktHdr, uSize);
     2704            uFrameSize -= pThis->cbPktHdr;
     2705            /*
     2706             * Peel off pkt header and convert to PDM/GSO semantics.
     2707             */
     2708            rc = virtioNetR3ReadVirtioTxPktHdr(pVirtio, pThis, pDevIns, paSegsFromGuest[0].GCPhys, pPktHdr, uFrameSize /* cbFrame */);
    23412709            if (RT_FAILURE(rc))
    23422710                return rc;
     
    23452713            PDMNETWORKGSO  Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, pPktHdr);
    23462714
     2715            /* Allocate PDM transmit buffer to send guest provided network frame from to VBox network leaf device */
    23472716            PPDMSCATTERGATHER pSgBufToPdmLeafDevice;
    2348             rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uSize, pGso, &pSgBufToPdmLeafDevice);
     2717            rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uFrameSize, pGso, &pSgBufToPdmLeafDevice);
     2718
     2719            /*
     2720             * Copy virtio-net guest S/G buffer to PDM leaf driver S/G buffer
     2721             * converting from GCphys to virt memory at the same time
     2722             */
    23492723            if (RT_SUCCESS(rc))
    23502724            {
     
    23532727
    23542728                size_t cbCopied = 0;
    2355                 size_t cbTotal = 0;
    2356                 size_t cbRemain = pSgBufToPdmLeafDevice->cbUsed = uSize;
    2357                 uOffset = 0;
     2729                size_t cbRemain = pSgBufToPdmLeafDevice->cbUsed = uFrameSize;
     2730                uint64_t uOffset = 0;
    23582731                while (cbRemain)
    23592732                {
     
    23692742                    cbRemain -= cbCopied;
    23702743                    uOffset += cbCopied;
    2371                     cbTotal += cbCopied;
    23722744                }
    23732745
    2374                 LogFunc((".... Copied %lu bytes to %lu byte guest buffer, residual=%lu\n",
    2375                      cbTotal, pVirtqBuf->cbPhysSend, pVirtqBuf->cbPhysSend - cbTotal));
     2746                LogFunc((".... Copied %lu/%lu bytes to %lu byte guest buffer. Buf residual=%lu\n",
     2747                     uOffset, uFrameSize, pVirtqBuf->cbPhysSend, virtioCoreGCPhysChainCalcLengthLeft(pSgPhysSend)));
    23762748
    23772749                rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, pPktHdr);
     
    23882760            else
    23892761            {
    2390                 Log4Func(("Failed to allocate S/G buffer: size=%u rc=%Rrc\n", uSize, rc));
     2762                Log4Func(("Failed to allocate S/G buffer: frame size=%u rc=%Rrc\n", uFrameSize, rc));
    23912763                /* Stop trying to fetch TX descriptors until we get more bandwidth. */
    23922764                virtioCoreR3VirtqBufRelease(pVirtio, pVirtqBuf);
     
    23942766            }
    23952767
    2396             /* Point to next descriptor chain in avail ring of virtq */
    23972768            virtioCoreR3VirtqAvailBufNext(pVirtio, pTxVirtq->uIdx);
    23982769
    23992770            /* No data to return to guest, but necessary to put elem (e.g. desc chain head idx) on used ring */
    24002771            virtioCoreR3VirtqUsedBufPut(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx, NULL, pVirtqBuf, true /* fFence */);
    2401 
    2402             /* Update used ring idx and notify guest that we've transmitted the data it sent */
    24032772            virtioCoreVirtqUsedRingSync(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx);
    24042773        }
     
    24282797    STAM_COUNTER_INC(&pThis->StatTransmitByNetwork);
    24292798
    2430     (void)virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/);
     2799    (void)virtioNetR3TransmitPkts(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/);
    24312800}
    24322801
     
    24382807    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    24392808    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    2440     RT_NOREF(hTimer, pvUser);
    24412809
    24422810    SET_LINK_UP(pThis);
    2443 
    24442811    virtioNetWakeupRxBufWaiter(pDevIns);
    2445 
    2446     LogFunc(("[%s] Link is up\n", pThis->szInst));
    24472812
    24482813    if (pThisCC->pDrv)
    24492814        pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, PDMNETWORKLINKSTATE_UP);
    2450 }
    2451 
    2452 /**
    2453  * Takes down the link temporarily if it's current status is up.
     2815
     2816    LogFunc(("[%s] Link is up\n", pThis->szInst));
     2817    RT_NOREF(hTimer, pvUser);
     2818}
     2819
     2820/**
     2821 * Takes down the link temporarily if its current status is up.
    24542822 *
    24552823 * This is used during restore and when replumbing the network link.
     
    24652833static void virtioNetR3TempLinkDown(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    24662834{
    2467 
    24682835    if (IS_LINK_UP(pThis))
    24692836    {
    24702837        SET_LINK_DOWN(pThis);
    24712838
    2472         /* Restore the link back in 5 seconds. */
     2839        /* Re-establish link in 5 seconds. */
    24732840        int rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->hLinkUpTimer, pThis->cMsLinkUpDelay);
    24742841        AssertRC(rc);
     
    24892856    bool fRequestedLinkStateIsUp = (enmState == PDMNETWORKLINKSTATE_UP);
    24902857
     2858#ifdef LOG_ENABLED
    24912859    if (LogIs7Enabled())
    24922860    {
     
    25072875        }
    25082876    }
     2877#endif
    25092878
    25102879    if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME)
    25112880    {
    2512 
    25132881        if (IS_LINK_UP(pThis))
    25142882        {
     
    25822950}
    25832951
     2952/**
     2953 * Creates a worker for specified queue, along with semaphore to throttle the worker.
     2954 *
     2955 * @param pDevIns       - PDM device instance
     2956 * @param pThis         - virtio-net instance
     2957 * @param pWorker       - Pointer to worker state
     2958 * @param pWorkerR3     - Pointer to worker state
     2959 * @param pVirtq        - Pointer to virtq
     2960 */
    25842961static int virtioNetR3CreateOneWorkerThread(PPDMDEVINS pDevIns, PVIRTIONET pThis,
    25852962                                            PVIRTIONETWORKER pWorker, PVIRTIONETWORKERR3 pWorkerR3,
     
    25902967
    25912968    int rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pWorker->hEvtProcess);
    2592     LogFunc(("PDMDevHlpSUPSemEventCreate(pDevIns, &pWorker->hEvtProcess=%p)", &pWorker->hEvtProcess));
    2593     LogFunc(("pWorker->hEvtProcess = %x\n", pWorker->hEvtProcess));
    25942969
    25952970    if (RT_FAILURE(rc))
     
    26062981                                   N_("Error creating thread for Virtual Virtq %s\n"), pVirtq->uIdx);
    26072982
    2608     pWorker->fAssigned = true;  /* Because worker's state held in fixed-size array w/empty slots */
     2983    pWorker->fAssigned = true;  /* Because worker's state in fixed-size array initialized w/empty slots */
    26092984
    26102985    LogFunc(("%s pThread: %p\n", pVirtq->szName, pWorkerR3->pThread));
     
    26182993    int rc;
    26192994
    2620 
    2621     /* Create the Control Queue worker anyway whether or not it is feature-negotiated or utilized by the guest,
    2622      * as it's relatively low overhead resource-wise.  This is for two reasons: First, at the time of this comment
    2623      * queues and workers are configured pre-feature negotiation; secondly, legacy guest drivers are allowed to start
    2624      * using the device prior to feature negotiation, and we can only know we are dealing with a modern guest driver
    2625      * after feature negotiation. */
     2995    /* Create the Control Queue worker anyway whether or not it is feature-negotiated or utilized by the guest.
     2996     * See related comment for queue construction in the device constructor function for more context.
     2997     */
    26262998
    26272999    PVIRTIONETVIRTQ pCtlVirtq = &pThis->aVirtqs[CTRLQIDX];
     
    26513023
    26523024    return rc;
     3025}
     3026
     3027static void virtioNetConfigurePktHdr(PVIRTIONET pThis, uint32_t fLegacy)
     3028{
     3029    /* Calculate network packet header type and size based on what we know now */
     3030    pThis->cbPktHdr = sizeof(VIRTIONETPKTHDR);
     3031    if (!fLegacy)
     3032        /* Modern (e.g. >= VirtIO 1.0) device specification's pkt size rules */
     3033        if (FEATURE_ENABLED(MRG_RXBUF))
     3034            pThis->ePktHdrType = kVirtioNetModernPktHdrWithMrgRx;
     3035        else /* Modern guest driver with MRG_RX feature disabled */
     3036            pThis->ePktHdrType = kVirtioNetModernPktHdrWithoutMrgRx;
     3037    else
     3038    {
     3039        /* Legacy (e.g. < VirtIO 1.0) device specification's pkt size rules */
     3040        if (FEATURE_ENABLED(MRG_RXBUF))
     3041            pThis->ePktHdrType = kVirtioNetLegacyPktHdrWithMrgRx;
     3042        else /* Legacy guest with MRG_RX feature disabled */
     3043        {
     3044            pThis->ePktHdrType = kVirtioNetLegacyPktHdrWithoutMrgRx;
     3045            pThis->cbPktHdr -= RT_SIZEOFMEMB(VIRTIONETPKTHDR, uNumBuffers);
     3046        }
     3047    }
    26533048}
    26543049
     
    26823077        if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio,  pVirtq->uIdx))
    26833078        {
    2684             /* Atomic interlocks avoid missing alarm while going to sleep & notifier waking the awoken */
     3079            /*  Precisely coordinated atomic interlocks avoid a race condition that results in hung thread
     3080             *  wherein a sloppily coordinated wake-up notification during a transition into or out
     3081             * of sleep leaves notifier and target mutually confused about actual & intended state.
     3082             */
    26853083            ASMAtomicWriteBool(&pWorker->fSleeping, true);
    2686 
    26873084            bool fNotificationSent = ASMAtomicXchgBool(&pWorker->fNotified, false);
    26883085            if (!fNotificationSent)
     
    27013098            }
    27023099            ASMAtomicWriteBool(&pWorker->fSleeping, false);
    2703 
    27043100        }
    2705 
    2706         /* Dispatch to the handler for the queue this worker is set up to drive */
    2707 
     3101        /*
     3102         * Dispatch to the handler for the queue this worker is set up to drive
     3103         */
    27083104         if (pVirtq->fCtlVirtq)
    27093105         {
     
    27133109             if (rc == VERR_NOT_AVAILABLE)
    27143110             {
    2715                 Log10Func(("[%s] %s worker woken. Nothing found in queue/n", pThis->szInst, pVirtq->szName));
     3111                Log10Func(("[%s] %s worker woken. Nothing found in queue\n", pThis->szInst, pVirtq->szName));
    27163112                continue;
    27173113             }
     
    27223118         {
    27233119             Log10Func(("[%s] %s worker woken. Virtq has data to transmit\n",  pThis->szInst, pVirtq->szName));
    2724              virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */);
     3120             virtioNetR3TransmitPkts(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */);
    27253121         }
    2726 
    2727          /* Rx queues aren't handled by our worker threads. Instead, the PDM network
    2728           * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback,
    2729           * which waits until woken by virtioNetVirtqNotified()
     3122         /* Note: Surprise! Rx queues aren't handled by local worker threads. Instead, the PDM network leaf driver
     3123          * invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback, which waits until woken by virtioNetVirtqNotified()
    27303124          * indicating that guest IN buffers have been added to Rx virt queue.
    27313125          */
     
    27353129}
    27363130
    2737 
    27383131/**
    27393132 * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged}
     3133 *
     3134 * Called back by the core code when VirtIO's ready state has changed.
    27403135 */
    27413136static DECLCALLBACK(void) virtioNetR3StatusChg(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint32_t fVirtioReady)
     
    27483143    if (fVirtioReady)
    27493144    {
    2750         Log(("-----------------------------------------------------------------------------------------\n"));
    2751         Log(("%-23s: %s *** VirtIO Ready ***\n-----------------------------------------------------------------------------------------\n",
    2752                  __FUNCTION__, pThis->szInst));
    2753 
     3145#ifdef LOG_ENABLED
     3146        Log(("\n%-23s: %s *** VirtIO Ready ***\n\n", __FUNCTION__, pThis->szInst));
     3147        virtioCorePrintDeviceFeatures(&pThis->Virtio, NULL, s_aDevSpecificFeatures, RT_ELEMENTS(s_aDevSpecificFeatures));
     3148#endif
     3149        pThis->fResetting = false;
    27543150        pThis->fNegotiatedFeatures = virtioCoreGetNegotiatedFeatures(pVirtio);
    2755 #ifdef LOG_ENABLED
    2756         virtioCorePrintDeviceFeatures(&pThis->Virtio, NULL, s_aDevSpecificFeatures,
    2757             RT_ELEMENTS(s_aDevSpecificFeatures));
    2758 #endif
    2759 
    27603151        pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0;
    2761 
    2762         pThis->fResetting = false;
    27633152
    27643153        for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
     
    27803169    else
    27813170    {
    2782         Log(("%-23s: %s VirtIO is resetting\n", __FUNCTION__, pThis->szInst));
     3171        Log(("\n%-23s: %s VirtIO is resetting ***\n", __FUNCTION__, pThis->szInst));
    27833172
    27843173        pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0;
     
    28023191
    28033192        for (uint16_t uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
     3193        {
     3194            virtioCoreR3VirtqDetach(&pThis->Virtio, uVirtqNbr);
    28043195            pThis->aVirtqs[uVirtqNbr].fAttachedToVirtioCore = false;
    2805     }
    2806 }
    2807 
    2808 static DECLCALLBACK(void) virtioGuestVersionHandler(PVIRTIOCORE pVirtio, uint32_t fModern)
    2809 {
    2810     LogFunc(("Guest Driver version is %s\n", fModern ? "modern" : "legacy"));
    2811 
    2812     PVIRTIONET pThis = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio);
    2813 
    2814     /* Calculate network packet header type and size based on what we know now */
    2815     pThis->cbPktHdr = sizeof(VIRTIONETPKTHDR);
    2816 
    2817     if (fModern)
    2818         pThis->ePktHdrType = kVirtioNetModernPktHdr_1_0;
    2819     else if (FEATURE_DISABLED(MRG_RXBUF))
    2820     {
    2821         pThis->ePktHdrType = kVirtioNetLegacyPktHdrWithoutMrgRx;
    2822         pThis->cbPktHdr -= RT_SIZEOFMEMB(VIRTIONETPKTHDR, uNumBuffers);
    2823     }
    2824     else /* Legacy guest with MRG_RX feature enabled */
    2825         pThis->ePktHdrType = kVirtioNetLegacyPktHdr;
    2826 }
    2827 
     3196        }
     3197    }
     3198}
     3199
     3200/**
     3201 * @callback_method_impl{VIRTIOCORER3,pfnFeatureNegotiationComplete}
     3202 */
     3203static DECLCALLBACK(void) pfnFeatureNegotiationComplete(PVIRTIOCORE pVirtio, uint64_t fDriverFeatures, uint32_t fLegacy)
     3204{
     3205    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pVirtio->pDevInsR3, PVIRTIONET);
     3206
     3207    LogFunc(("[Feature Negotiation Complete] Guest Driver version is: %s\n", fLegacy ? "legacy" : "modern"));
     3208    virtioNetConfigurePktHdr(pThis, fLegacy);
     3209    virtioNetR3SetVirtqNames(pThis, fLegacy);
     3210
     3211    /* Senseless for modern guest to use control queue in this case. (See Note 1 in PDM-invoked device constructor) */
     3212    if (!fLegacy && !(fDriverFeatures & VIRTIONET_F_CTRL_VQ))
     3213        virtioNetR3VirtqDestroy(pVirtio, &pThis->aVirtqs[CTRLQIDX]);
     3214}
    28283215
    28293216#endif /* IN_RING3 */
     
    28323219 * @interface_method_impl{PDMDEVREGR3,pfnDetach}
    28333220 *
    2834  * One harddisk at one port has been unplugged.
    28353221 * The VM is suspended at this point.
    28363222 */
     
    28613247    PVIRTIONETCC     pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    28623248
    2863     RT_NOREF(fFlags);
    2864 
    28653249    Log7Func(("[%s]", pThis->szInst));
    2866 
    28673250    AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
    2868 
    2869     RT_NOREF(pThis);
    28703251
    28713252    int rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThisCC->IBase, &pThisCC->pDrvBase, "Network Port");
     
    28803261                    Log(("[%s] No attached driver!\n", pThis->szInst));
    28813262
     3263    RT_NOREF2(pThis, fFlags);
    28823264    return rc;
    28833265}
     
    28943276    return VINF_SUCCESS;
    28953277}
    2896 
    28973278
    28983279/**
     
    29203301
    29213302    Log(("[%s] Destroying instance\n", pThis->szInst));
    2922 
    29233303    if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT)
    29243304    {
     
    29293309
    29303310    virtioNetR3DestroyWorkerThreads(pDevIns, pThis, pThisCC);
    2931 
    29323311    virtioCoreR3Term(pDevIns, &pThis->Virtio, &pThisCC->Virtio);
    2933 
    29343312    return VINF_SUCCESS;
    29353313}
     
    29373315/**
    29383316 * @interface_method_impl{PDMDEVREGR3,pfnConstruct}
     3317 *
     3318 * Notes about revising originally VirtIO 1.0+ only virtio-net device emulator to be "transitional",
     3319 * a VirtIO term meaning this now interoperates with both "legacy" (e.g. pre-1.0) and "modern" (1.0+)
     3320 * guest virtio-net drivers. The changes include migrating VMs saved using prior DevVirtioNet.cpp (0.95)
     3321 * saveExec/loadExec semantics to use 1.0 save/load semantics.
     3322 *
     3323 * Regardless of the 1.0 spec's overall helpful guidance for implementing transitional devices,
     3324 * A bit is left to the imagination, e.g. some things have to be determined deductively
     3325 * (AKA "the hard way").
     3326 *
     3327 * Case in point: According to VirtIO 0.95 ("legacy") specification, section 2.2.1, "historically"
     3328 * drivers may start driving prior to feature negotiation and prior to drivers setting DRIVER_OK
     3329 * status, "provided driver doesn't use features that alter early use of this device".  That
     3330 * is Interpreted here to mean a virtio-net driver must respect default settings (such as implicit
     3331 * pkt header default size, as determined per Note 1 below).
     3332 *
     3333 * ----------------------------------------------------------------------------------------------
     3334 * Transitional device initialization Note 1:  Identifying default value for network Rx pkt hdr size.
     3335 * (VirtIO 1.0 specification section 5.1.6.1)
     3336 *
     3337 * Guest virtio legacy drivers may begin operations prematurely, regardless of early spec's
     3338 * initialization sequence (see note 2 below). Legacy drivers implicitly default to using the
     3339 * (historically) shortest-length network packet header *unless* VIRTIONET_F_MRG_RXBUF feature is
     3340 * negotiated. If feature negotiation phase is [optionally] enacted by a legacy guest (i.e. we strictly
     3341 * enforce full initialization protocol for modern guests), virtioNetConfigurePktHdr() is invoked again to
     3342 * finalize device's network packet header size. Best-guess at default packet header size is deduced, e.g.
     3343 * isn't documented, as follows: A legacy guest with VIRTIONET_F_MRG_RXBUF not-yet-negotiated is the only
     3344 * case where network I/O could possibly occur with any reasonable assumption about packet type/size,
     3345 * because logically other permutations couldn't possibly be inferred until feature negotiation
     3346 * is complete. Specifically, those cases are:
     3347 *
     3348 * 1. A modern driver (detected only when VIRTIONET_F_VERSION_1 feature is ack'd by guest, and,
     3349 * simultaneously, VIRTIONET_F_MRG_RXBUF feature is accepted or declined (determining network receive-packet
     3350 * processing behavior).
     3351 *
     3352 * 2. A legacy driver that has agreed to use VIRTIONET_F_MRG_RXBUF feature, resulting in a two-byte larger pkt hdr,
     3353 * (as well as deciding Rx packet processing behavior).
     3354 *
     3355 * ----------------------------------------------------------------------------------------------
     3356 * Transitional device initialization Note 2:  Creating unnegotiated control queue.
     3357 * (VirtIO 1.0 spec, sections 5.1.5 and 5.1.6.5)
     3358 *
     3359 * Create all queues immediately, prior to feature negotiation, including control queue (irrespective
     3360 * of the fact it's too early in initialization for control feature to be approved by guest). This
     3361 * transitional device must deal with legacy guests which *can* (and on linux have been seen to) use
     3362 * the control queue prior to feature negotiation.
     3363 *
     3364 * The initial assumption is *modern" guest virtio-net drivers out in the wild could never reasonably
     3365 * attempt something as obviously risky as using ctrlq without first acking VIRTIO_NET_F_CTRL_VQ
     3366 * feature to establish it. For now, we create the control queue proactively to accomodate a potentially
     3367 * badly behaved but officially sanctioned legacy virtio-net driver, but *destroy* that same queue
     3368 * if a driver announces as 'modern' during feature finalization yet leaves VIRTIO_NET_F_CTRL_VQ un-ack'd.
    29393369 */
    29403370static DECLCALLBACK(int) virtioNetR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
     
    29463376
    29473377    /*
    2948      * Quick initialization of the state data, making sure that the destructor always works.
     3378     * Quickly initialize state data to ensure destructor always works.
    29493379     */
    29503380    Log7Func(("PDM device instance: %d\n", iInstance));
    29513381    RTStrPrintf(pThis->szInst, sizeof(pThis->szInst), "virtio-net #%d", iInstance);
    29523382
    2953     pThisCC->pDevIns     = pDevIns;
    2954     pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface;
    2955     pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed;
     3383    pThisCC->pDevIns                          = pDevIns;
     3384    pThisCC->IBase.pfnQueryInterface          = virtioNetR3QueryInterface;
     3385    pThisCC->ILeds.pfnQueryStatusLed          = virtioNetR3QueryStatusLed;
    29563386    pThisCC->led.u32Magic = PDMLED_MAGIC;
    29573387
     
    29703400     * Validate configuration.
    29713401     */
    2972     PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MAC|CableConnected|LineSpeed|LinkUpDelay|StatNo", "");
     3402    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MAC|CableConnected|LineSpeed|LinkUpDelay|StatNo|Legacy", "");
    29733403
    29743404    /* Get config params */
     
    30143444#   endif
    30153445
    3016     pThis->virtioNetConfig.uMaxVirtqPairs   = VIRTIONET_MAX_QPAIRS;
    3017     pThisCC->Virtio.pfnGuestVersionHandler  = virtioGuestVersionHandler;
    3018     pThisCC->Virtio.pfnVirtqNotified        = virtioNetVirtqNotified;
    3019     pThisCC->Virtio.pfnStatusChanged        = virtioNetR3StatusChg;
    3020     pThisCC->Virtio.pfnDevCapRead           = virtioNetR3DevCapRead;
    3021     pThisCC->Virtio.pfnDevCapWrite          = virtioNetR3DevCapWrite;
     3446    pThis->virtioNetConfig.uMaxVirtqPairs          = VIRTIONET_MAX_QPAIRS;
     3447    pThisCC->Virtio.pfnFeatureNegotiationComplete  = pfnFeatureNegotiationComplete;
     3448    pThisCC->Virtio.pfnVirtqNotified               = virtioNetVirtqNotified;
     3449    pThisCC->Virtio.pfnStatusChanged               = virtioNetR3StatusChg;
     3450    pThisCC->Virtio.pfnDevCapRead                  = virtioNetR3DevCapRead;
     3451    pThisCC->Virtio.pfnDevCapWrite                 = virtioNetR3DevCapWrite;
    30223452
    30233453    VIRTIOPCIPARAMS VirtioPciParams;
    3024     VirtioPciParams.uDeviceId               = PCI_DEVICE_ID_VIRTIONET_HOST;
    3025     VirtioPciParams.uClassBase              = PCI_CLASS_BASE_NETWORK_CONTROLLER;
    3026     VirtioPciParams.uClassSub               = PCI_CLASS_SUB_NET_ETHERNET_CONTROLLER;
    3027     VirtioPciParams.uClassProg              = PCI_CLASS_PROG_UNSPECIFIED;
    3028     VirtioPciParams.uSubsystemId            = PCI_DEVICE_ID_VIRTIONET_HOST;  /* VirtIO 1.0 allows PCI Device ID here */
    3029     VirtioPciParams.uInterruptLine          = 0x00;
    3030     VirtioPciParams.uInterruptPin           = 0x01;
     3454    VirtioPciParams.uDeviceId                      = PCI_DEVICE_ID_VIRTIONET_HOST;
     3455    VirtioPciParams.uClassBase                     = PCI_CLASS_BASE_NETWORK_CONTROLLER;
     3456    VirtioPciParams.uClassSub                      = PCI_CLASS_SUB_NET_ETHERNET_CONTROLLER;
     3457    VirtioPciParams.uClassProg                     = PCI_CLASS_PROG_UNSPECIFIED;
     3458    VirtioPciParams.uSubsystemId                   = PCI_DEVICE_ID_VIRTIONET_HOST;  /* VirtIO 1.0 allows PCI Device ID here */
     3459    VirtioPciParams.uInterruptLine                 = 0x00;
     3460    VirtioPciParams.uInterruptPin                  = 0x01;
    30313461
    30323462    /* Create semaphore used to synchronize/throttle the downstream LUN's Rx waiter thread. */
     
    30353465        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create event semaphore"));
    30363466
    3037 
    3038     /* Initialize VirtIO core. (pfnStatusChanged callback when both host VirtIO core & guest driver are ready) */
     3467    pThis->fOfferLegacy = VIRTIONET_TRANSITIONAL_ENABLE_FLAG;
     3468    virtioNetConfigurePktHdr(pThis, pThis->fOfferLegacy); /* set defaults */
     3469
     3470    /* Initialize VirtIO core. (*pfnStatusChanged)() callback occurs when both host VirtIO core & guest driver are ready) */
    30393471    rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInst,
    3040                           VIRTIONET_HOST_FEATURES_OFFERED,
     3472                          VIRTIONET_HOST_FEATURES_OFFERED, pThis->fOfferLegacy,
    30413473                          &pThis->virtioNetConfig /*pvDevSpecificCap*/, sizeof(pThis->virtioNetConfig));
    30423474    if (RT_FAILURE(rc))
     
    30463478    if (!virtioNetValidateRequiredFeatures(pThis->fNegotiatedFeatures))
    30473479        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated."));
    3048 
    3049 
    3050     /*
    3051      * Initialize queues.  Due to this being a transitional device (e.g. accommodating both modern
    3052      * and legacy drivers), the control queue must be created whether or not the VIRTIO_NET_F_CTRL_VQ
    3053      * is negotiated, because legacy drivers are not bound to begin configuration and I/O until
    3054      * feature negotiation is complete.  In the final analysis, there may be no good reason to
    3055      * enforce VIRTIO_NET_F_CTRL_VQ as a prerequisite to handling guest control queue transactions,
    3056      * but merely to log violations (e.g. control transactions without feature explicitly enabled),
    3057      * once, thus not being strict with regard to misbehaving modern drivers.
    3058      */
    3059 
    3060     pThis->cVirtqPairs = 1;  /* default, VirtIO 1.0, 5.1.6.5.5 */
     3480    pThis->cVirtqPairs = pThis->virtioNetConfig.uMaxVirtqPairs;
    30613481    pThis->cVirtqs += pThis->cVirtqPairs * 2 + 1;
    30623482    pThis->aVirtqs[CTRLQIDX].fCtlVirtq = true;
    30633483
    3064     virtioNetR3SetVirtqNames(pThis);
     3484    virtioNetR3SetVirtqNames(pThis, pThis->fOfferLegacy);
    30653485    for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtqs; uVirtqNbr++)
    30663486    {
     
    30683488        PVIRTIONETWORKER pWorker = &pThis->aWorkers[uVirtqNbr];
    30693489        PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[uVirtqNbr];
    3070         pVirtq->uIdx = uVirtqNbr;
    3071         pWorker->uIdx = uVirtqNbr;
    3072         pWorkerR3->uIdx = uVirtqNbr;
     3490        pVirtq->uIdx = pWorker->uIdx = pWorkerR3->uIdx = uVirtqNbr;
    30733491    }
    30743492    /*
     
    30993517                    AssertRCReturn(rc, rc);
    31003518    }
    3101 
    31023519    /*
    31033520     * Status driver
     
    31093526
    31103527    pThisCC->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pUpBase, PDMILEDCONNECTORS);
    3111 
    31123528    /*
    31133529     * Register saved state.
    31143530     */
    3115     rc = PDMDevHlpSSMRegister(pDevIns, VIRTIONET_SAVED_STATE_VERSION, sizeof(*pThis),
    3116                               virtioNetR3SaveExec, virtioNetR3LoadExec);
     3531    rc = PDMDevHlpSSMRegister(pDevIns, VIRTIONET_SAVEDSTATE_VERSION, sizeof(*pThis),
     3532                              virtioNetR3ModernSaveExec, virtioNetR3ModernDeviceLoadExec);
    31173533    AssertRCReturn(rc, rc);
    3118 
    3119    /*
     3534    /*
    31203535     * Statistics and debug stuff.
    31213536     * The /Public/ bits are official and used by session info in the GUI.
     
    31443559    PDMDevHlpSTAMRegister(pDevIns, &pThis->StatTransmitByThread,    STAMTYPE_COUNTER, "Transmit/ByThread",      STAMUNIT_COUNT,          "Thread-initiated transmissions");
    31453560# endif
    3146 
    31473561    /*
    31483562     * Register the debugger info callback (ignore errors).
     
    31743588 * The device registration structure.
    31753589 */
    3176 const PDMDEVREG g_DeviceVirtioNet_1_0 =
     3590const PDMDEVREG g_DeviceVirtioNet =
    31773591{
    31783592    /* .uVersion = */               PDM_DEVREG_VERSION,
    31793593    /* .uReserved0 = */             0,
    3180     /* .szName = */                 "virtio-net-1-dot-0",
     3594    /* .szName = */                 "virtio-net",
    31813595    /* .fFlags = */                 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_NEW_STYLE | PDM_DEVREG_FLAGS_RZ,
    31823596    /* .fClass = */                 PDM_DEVREG_CLASS_NETWORK,
  • trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp

    r91920 r92939  
    19961996     * Call the virtio core to let it load its state.
    19971997     */
    1998     rc = virtioCoreR3LoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM);
     1998    rc = virtioCoreR3ModernDeviceLoadExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM,
     1999                                           uVersion, VIRTIOSCSI_SAVED_STATE_VERSION, pThis->virtioScsiConfig.uNumVirtqs);
    19992000
    20002001    /*
     
    20872088     * Call the virtio core to let it save its state.
    20882089     */
    2089     return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM);
     2090    return virtioCoreR3SaveExec(&pThis->Virtio, pDevIns->pHlpR3, pSSM, VIRTIOSCSI_SAVED_STATE_VERSION, VIRTIOSCSI_VIRTQ_CNT);
    20902091}
    20912092
     
    24692470
    24702471    rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInstance,
    2471                           VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED,
     2472                          VIRTIOSCSI_HOST_SCSI_FEATURES_OFFERED, 0 /*fOfferLegacy*/,
    24722473                          &pThis->virtioScsiConfig /*pvDevSpecificCap*/, sizeof(pThis->virtioScsiConfig));
    24732474    if (RT_FAILURE(rc))
  • trunk/src/VBox/Devices/VirtIO/VirtioCore.cpp

    r92091 r92939  
    4242*   Defined Constants And Macros                                                                                                 *
    4343*********************************************************************************************************************************/
     44
    4445#define INSTANCE(a_pVirtio)                 ((a_pVirtio)->szInstance)
    4546#define VIRTQNAME(a_pVirtio, a_uVirtq)      ((a_pVirtio)->aVirtqueues[(a_uVirtq)].szName)
    4647
    47 
    4848#define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq) \
    4949            (virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq) == 0)
    5050
    51 
    5251#define IS_DRIVER_OK(a_pVirtio)             ((a_pVirtio)->fDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
    5352#define WAS_DRIVER_OK(a_pVirtio)            ((a_pVirtio)->fPrevDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
     53
     54/**
     55 * These defines are used to track  guest virtio-net driver writing driver features accepted flags
     56 * in two 32-bit operations (in arbitrary order), and one bit dedicated to ensured 'features complete'
     57 * is handled once.
     58 */
     59#define DRIVER_FEATURES_0_WRITTEN                        1   /**< fDriverFeatures[0]  written by guest virtio-net */
     60#define DRIVER_FEATURES_1_WRITTEN                        2   /**< fDriverFeatures[1]  written by guest virtio-net */
     61#define DRIVER_FEATURES_0_AND_1_WRITTEN                  3   /**< Both 32-bit parts of fDriverFeatures[] written  */
     62#define DRIVER_FEATURES_COMPLETE_HANDLED                 4   /**< Features negotiation complete handler called    */
    5463
    5564/**
     
    6877
    6978
    70 /** Marks the start of the virtio saved state (just for sanity). */
    71 #define VIRTIO_SAVEDSTATE_MARKER                        UINT64_C(0x1133557799bbddff)
    72 /** The current saved state version for the virtio core. */
    73 #define VIRTIO_SAVEDSTATE_VERSION                       UINT32_C(1)
    74 
    75 
    7679/*********************************************************************************************************************************
    7780*   Structures and Typedefs                                                                                                      *
    7881*********************************************************************************************************************************/
    79 
    8082
    8183/** @name virtq related flags
     
    9092
    9193/**
    92  * virtq related structs
    93  * (struct names follow VirtIO 1.0 spec, typedef use VBox style)
     94 * virtq-related structs
     95 * (struct names follow VirtIO 1.0 spec, field names use VBox styled naming, w/respective spec'd name in comments)
    9496 */
    9597typedef struct virtq_desc
     
    125127} VIRTQ_USED_T, *PVIRTQ_USED_T;
    126128
    127 
    128129const char *virtioCoreGetStateChangeText(VIRTIOVMSTATECHANGED enmState)
    129130{
     
    141142
    142143static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq);
    143 static int  virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec);
     144static int  virtioNudgeGuest(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec);
     145
     146DECLINLINE(uint16_t) virtioCoreR3CountPendingBufs(uint16_t uRingIdx, uint16_t uShadowIdx, uint16_t uQueueSize)
     147{
     148    if (uShadowIdx == uRingIdx)
     149        return 0;
     150    else
     151    if (uShadowIdx > uRingIdx)
     152        return uShadowIdx - uRingIdx;
     153    return uQueueSize - (uRingIdx - uShadowIdx);
     154}
    144155
    145156/** @name Internal queue operations
     
    156167    uint16_t const cVirtqItems = RT_MAX(pVirtq->uQueueSize, 1); /* Make sure to avoid div-by-zero. */
    157168
    158         virtioCoreGCPhysRead(pVirtio, pDevIns,
    159                           pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
    160                           pDesc, sizeof(VIRTQ_DESC_T));
     169    virtioCoreGCPhysRead(pVirtio, pDevIns,
     170                         pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * (idxDesc % cVirtqItems),
     171                         pDesc, sizeof(VIRTQ_DESC_T));
    161172}
    162173#endif
     
    207218                         pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF(VIRTQ_AVAIL_T, fFlags),
    208219                         &fFlags, sizeof(fFlags));
    209 
    210220    return fFlags;
    211221}
     
    249259}
    250260
    251 
    252261#ifdef IN_RING3
    253262DECLINLINE(uint16_t) virtioReadUsedRingIdx(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQUEUE pVirtq)
     
    289298
    290299    if (uIdxActual < uIdxShadow)
    291         uIdxDelta = (uIdxActual + VIRTQ_SIZE) - uIdxShadow;
     300        uIdxDelta = (uIdxActual + pVirtq->uQueueSize) - uIdxShadow;
    292301    else
    293302        uIdxDelta = uIdxActual - uIdxShadow;
    294 
    295     LogFunc(("%s, %u %s\n",
    296         pVirtq->szName, uIdxDelta, uIdxDelta == 1 ? "entry" : "entries"));
    297303
    298304    return uIdxDelta;
     
    320326    if (!pVirtio->fLegacyDriver && !pVirtq->uEnable)
    321327    {
    322         LogRelFunc(("virtq: %d (%s) not enabled\n", uVirtq, VIRTQNAME(pVirtio, uVirtq)));
     328        LogRelFunc(("virtq: %s not enabled\n", VIRTQNAME(pVirtio, uVirtq)));
    323329        return 0;
    324330    }
    325 
    326331    return virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq);
    327332}
     
    440445           else
    441446               cbPrint = RTStrPrintf(pszOut, cbRemain, "%02x %s", c, (col + 1) % 8 ? "" : "  ");
    442             ADJCURSOR(cbPrint);
     447           ADJCURSOR(cbPrint);
    443448        }
    444449        for (uint16_t idx = row * 16; idx < row * 16 + 16; idx++)
     
    456461#undef ADJCURSOR
    457462}
    458 #endif /* LOG_ENABLED */
    459 
    460 /** API function: See header file */
    461 int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio)
    462 {
    463     Log12Func(("%s", pVirtio->fLegacyDriver ? "Legacy Guest Driver handling mode\n" : ""));
    464     return pVirtio->fLegacyDriver;
    465 }
     463
    466464
    467465/** API function: See header file */
     
    470468                                int fHasIndex, uint32_t idx)
    471469{
    472     if (!LogIs6Enabled())
    473         return;
    474 
    475     char szIdx[16];
    476     if (fHasIndex)
    477         RTStrPrintf(szIdx, sizeof(szIdx), "[%d]", idx);
    478     else
    479         szIdx[0] = '\0';
    480 
    481     if (cb == 1 || cb == 2 || cb == 4 || cb == 8)
    482     {
    483         char szDepiction[64];
    484         size_t cchDepiction;
    485         if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */
    486             cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s[%d:%d]",
    487                                        pszMember, szIdx, uOffset, uOffset + cb - 1);
     470    if (LogIs6Enabled())
     471    {
     472        char szIdx[16];
     473        if (fHasIndex)
     474            RTStrPrintf(szIdx, sizeof(szIdx), "[%d]", idx);
    488475        else
    489             cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s", pszMember, szIdx);
    490 
    491         /* padding */
    492         if (cchDepiction < 30)
    493             szDepiction[cchDepiction++] = ' ';
    494         while (cchDepiction < 30)
    495             szDepiction[cchDepiction++] = '.';
    496         szDepiction[cchDepiction] = '\0';
    497 
    498         RTUINT64U uValue;
    499         uValue.u = 0;
    500         memcpy(uValue.au8, pv, cb);
    501         Log6(("%-23s: Guest %s %s %#0*RX64\n",
    502                   pszFunc, fWrite ? "wrote" : "read ", szDepiction, 2 + cb * 2, uValue.u));
    503     }
    504     else /* odd number or oversized access, ... log inline hex-dump style */
    505     {
    506         Log6(("%-23s: Guest %s %s%s[%d:%d]: %.*Rhxs\n",
    507                   pszFunc, fWrite ? "wrote" : "read ", pszMember,
    508                   szIdx, uOffset, uOffset + cb, cb, pv));
     476            szIdx[0] = '\0';
     477
     478        if (cb == 1 || cb == 2 || cb == 4 || cb == 8)
     479        {
     480            char szDepiction[64];
     481            size_t cchDepiction;
     482            if (uOffset != 0 || cb != uMemberSize) /* display bounds if partial member access */
     483                cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s[%d:%d]",
     484                                           pszMember, szIdx, uOffset, uOffset + cb - 1);
     485            else
     486                cchDepiction = RTStrPrintf(szDepiction, sizeof(szDepiction), "%s%s", pszMember, szIdx);
     487
     488            /* padding */
     489            if (cchDepiction < 30)
     490                szDepiction[cchDepiction++] = ' ';
     491            while (cchDepiction < 30)
     492                szDepiction[cchDepiction++] = '.';
     493            szDepiction[cchDepiction] = '\0';
     494
     495            RTUINT64U uValue;
     496            uValue.u = 0;
     497            memcpy(uValue.au8, pv, cb);
     498            Log6(("%-23s: Guest %s %s %#0*RX64\n",
     499                      pszFunc, fWrite ? "wrote" : "read ", szDepiction, 2 + cb * 2, uValue.u));
     500        }
     501        else /* odd number or oversized access, ... log inline hex-dump style */
     502        {
     503            Log6(("%-23s: Guest %s %s%s[%d:%d]: %.*Rhxs\n",
     504                      pszFunc, fWrite ? "wrote" : "read ", pszMember,
     505                      szIdx, uOffset, uOffset + cb, cb, pv));
     506        }
    509507    }
    510508    RT_NOREF2(fWrite, pszFunc);
     
    512510
    513511/**
    514  * Makes the MMIO-mapped Virtio fDeviceStatus registers non-cryptic (buffers to
    515  * keep the output clean during multi-threaded activity)
     512 * Log MMIO-mapped Virtio fDeviceStatus register bitmask, naming the bits
    516513 */
    517514DECLINLINE(void) virtioCoreFormatDeviceStatus(uint8_t bStatus, char *pszBuf, size_t uSize)
    518515{
    519 
    520 #define ADJCURSOR(len) cp += len; uSize -= len; sep = (char *)" | ";
    521 
     516#   define ADJCURSOR(len) { cp += len; uSize -= len; sep = (char *)" | "; }
    522517    memset(pszBuf, 0, uSize);
    523     size_t len;
    524     char *cp = pszBuf;
    525     char *sep = (char *)"";
    526 
    527     if (bStatus == 0) {
     518    char *cp = pszBuf, *sep = (char *)"";
     519    int len;
     520    if (bStatus == 0)
    528521        RTStrPrintf(cp, uSize, "RESET");
    529         return;
    530     }
    531     if (bStatus & VIRTIO_STATUS_ACKNOWLEDGE)
    532     {
    533         len = RTStrPrintf(cp, uSize, "ACKNOWLEDGE");
    534         ADJCURSOR(len);
    535    }
    536     if (bStatus & VIRTIO_STATUS_DRIVER)
    537     {
    538         len = RTStrPrintf(cp, uSize, "%sDRIVER", sep);
    539         ADJCURSOR(len);
    540     }
    541     if (bStatus & VIRTIO_STATUS_FEATURES_OK)
    542     {
    543         len = RTStrPrintf(cp, uSize, "%sFEATURES_OK", sep);
    544         ADJCURSOR(len);
    545     }
    546     if (bStatus & VIRTIO_STATUS_DRIVER_OK)
    547     {
    548         len = RTStrPrintf(cp, uSize, "%sDRIVER_OK", sep);
    549         ADJCURSOR(len);
    550     }
    551     if (bStatus & VIRTIO_STATUS_FAILED)
    552     {
    553         len = RTStrPrintf(cp, uSize, "%sFAILED", sep);
    554         ADJCURSOR(len);
    555     }
    556     if (bStatus & VIRTIO_STATUS_DEVICE_NEEDS_RESET)
    557         RTStrPrintf(cp, uSize, "%sNEEDS_RESET", sep);
    558 
    559 #undef ADJCURSOR
     522    else
     523    {
     524        if (bStatus & VIRTIO_STATUS_ACKNOWLEDGE)
     525        {
     526            len = RTStrPrintf(cp, uSize, "ACKNOWLEDGE");
     527            ADJCURSOR(len);
     528        }
     529        if (bStatus & VIRTIO_STATUS_DRIVER)
     530        {
     531            len = RTStrPrintf(cp, uSize, "%sDRIVER", sep);
     532            ADJCURSOR(len);
     533        }
     534        if (bStatus & VIRTIO_STATUS_FEATURES_OK)
     535        {
     536            len = RTStrPrintf(cp, uSize, "%sFEATURES_OK", sep);
     537            ADJCURSOR(len);
     538        }
     539        if (bStatus & VIRTIO_STATUS_DRIVER_OK)
     540        {
     541            len = RTStrPrintf(cp, uSize, "%sDRIVER_OK", sep);
     542            ADJCURSOR(len);
     543        }
     544        if (bStatus & VIRTIO_STATUS_FAILED)
     545        {
     546            len = RTStrPrintf(cp, uSize, "%sFAILED", sep);
     547            ADJCURSOR(len);
     548        }
     549        if (bStatus & VIRTIO_STATUS_DEVICE_NEEDS_RESET)
     550            RTStrPrintf(cp, uSize, "%sNEEDS_RESET", sep);
     551    }
     552#   undef ADJCURSOR
     553}
     554
     555#endif /* LOG_ENABLED */
     556
     557/** API function: See header file */
     558int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio)
     559{
     560    return pVirtio->fLegacyDriver;
    560561}
    561562
     
    570571    pVirtq->uUsedIdxShadow  = 0;
    571572    pVirtq->fUsedRingEvent = false;
     573    pVirtq->fAttached = true;
    572574    RTStrCopy(pVirtq->szName, sizeof(pVirtq->szName), pcszName);
    573575    return VINF_SUCCESS;
     576}
     577
     578int virtioCoreR3VirtqDetach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     579{
     580    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtqNbr];
     581    pVirtq->uVirtq          = 0;
     582    pVirtq->uAvailIdxShadow = 0;
     583    pVirtq->uUsedIdxShadow  = 0;
     584    pVirtq->fUsedRingEvent  = false;
     585    pVirtq->fAttached       = false;
     586    memset(pVirtq->szName, 0, sizeof(pVirtq->szName));
     587    return VINF_SUCCESS;
     588}
     589
     590bool virtioCoreR3VirtqIsAttached(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     591{
     592    return pVirtio->aVirtqueues[uVirtqNbr].fAttached;
     593}
     594
     595bool virtioCoreR3VirtqIsEnabled(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr)
     596{
     597    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtqNbr];
     598    return (bool)pVirtq->uEnable && pVirtq->GCPhysVirtqDesc;
    574599}
    575600
     
    582607
    583608    /** @todo add ability to dump physical contents described by any descriptor (using existing VirtIO core API function) */
    584 //    bool fDump      = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)"
     609//  bool fDump      = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)"
    585610
    586611    uint16_t uAvailIdx       = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtq);
     
    648673        pHlp->pfnPrintf(pHlp,     "      No desc chains available\n");
    649674    pHlp->pfnPrintf(pHlp, "\n");
    650 
    651675}
    652676
     
    661685    return cRefs;
    662686}
    663 
    664687
    665688/** API Function: See header file */
     
    687710void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio)
    688711{
    689     virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
    690 }
     712    virtioNudgeGuest(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
     713}
     714
    691715
    692716/** API Function: See header file */
    693717void virtioCoreVirtqEnableNotify(PVIRTIOCORE pVirtio, uint16_t uVirtq, bool fEnable)
    694718{
    695 
    696719    Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues));
    697720    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
     
    719742        if (!pVirtio->fLegacyDriver)
    720743            pVirtio->fGenUpdatePending = true;
    721         virtioKick(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
     744        virtioNudgeGuest(pVirtio->pDevInsR3, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig);
    722745    }
    723746}
     
    748771    return VINF_SUCCESS;
    749772}
    750 
    751773
    752774/** API Function: See header file */
     
    797819    {
    798820        PVIRTIOSGSEG pSeg;
    799 
    800821        /*
    801822         * Malicious guests may go beyond paSegsIn or paSegsOut boundaries by linking
     
    804825         * the following aborts I/O if breach and employs a simple log throttling algorithm to notify.
    805826         */
    806         if (cSegsIn + cSegsOut >= VIRTQ_SIZE)
     827        if (cSegsIn + cSegsOut >= pVirtq->uQueueSize)
    807828        {
    808829            static volatile uint32_t s_cMessages  = 0;
     
    823844        if (desc.fFlags & VIRTQ_DESC_F_WRITE)
    824845        {
    825             Log6Func(("%s IN  idx=%u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
     846            Log6Func(("%s IN  idx=%-4u seg=%-3u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsIn, desc.GCPhysBuf, desc.cb));
    826847            cbIn += desc.cb;
    827848            pSeg = &paSegsIn[cSegsIn++];
     
    829850        else
    830851        {
    831             Log6Func(("%s OUT desc_idx=%u seg=%u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb));
     852            Log6Func(("%s OUT desc_idx=%-4u seg=%-3u addr=%RGp cb=%u\n", pVirtq->szName, uDescIdx, cSegsOut, desc.GCPhysBuf, desc.cb));
    832853            cbOut += desc.cb;
    833854            pSeg = &paSegsOut[cSegsOut++];
     
    840861#endif
    841862        }
    842 
    843863        pSeg->GCPhys = desc.GCPhysBuf;
    844864        pSeg->cbSeg = desc.cb;
    845 
    846865        uDescIdx = desc.uDescIdxNext;
    847866    } while (desc.fFlags & VIRTQ_DESC_F_NEXT);
     
    915934    AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    916935
    917     Log6Func(("    Copying device data to %s (%s guest), desc chain idx %d\n",
    918               VIRTQNAME(pVirtio, uVirtq), pVirtio->fLegacyDriver ? "legacy" : "modern", virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
    919 
    920     /* Copy s/g buf (virtual memory) to guest phys mem (IN direction). */
     936    Log6Func(("    Copying device data to %s, [desc:%u → used ring:%u]\n",
     937              VIRTQNAME(pVirtio, uVirtq), pVirtqBuf->uHeadIdx, pVirtq->uUsedIdxShadow));
     938
     939    /* Copy s/g buf (virtual memory) to guest phys mem (VirtIO "IN" direction). */
    921940
    922941    size_t cbCopy = 0, cbTotal = 0, cbRemain = 0;
     
    944963    }
    945964
    946     /* If this write-ahead crosses threshold where the driver wants to get an event, flag it */
     965    /* Flag if write-ahead crosses threshold where guest driver indicated it wants event notification */
    947966    if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
    948967        if (pVirtq->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq))
     
    951970    /*
    952971     * Place used buffer's descriptor in used ring but don't update used ring's slot index.
    953      * That will be done with a subsequent client call to virtioCoreVirtqUsedRingSync() */
     972     * That will be done with a subsequent client call to virtioCoreVirtqUsedRingSync()
     973     */
    954974    virtioWriteUsedElem(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow++, pVirtqBuf->uHeadIdx, (uint32_t)cbTotal);
    955975
    956     if (pSgVirtReturn)
    957         Log6Func(("     ... %d segs, %zu bytes, copied to %u byte buf. residual: %zu bytes\n",
    958                   pSgVirtReturn->cSegs, cbTotal - cbRemain,  pVirtqBuf->cbPhysReturn, pVirtqBuf->cbPhysReturn - cbTotal));
    959 
    960     Log6Func(("    %s used_idx=%u\n", VIRTQNAME(pVirtio, uVirtq), virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq)));
     976#ifdef LOG_ENABLED
     977    if (LogIs6Enabled() && pSgVirtReturn)
     978    {
     979
     980        LogFunc(("     ... %d segs, %zu bytes, copied to %u byte buf@offset=%u. Residual: %zu bytes\n",
     981             pSgVirtReturn->cSegs,  cbTotal - cbRemain,  pVirtqBuf->cbPhysReturn,
     982              ((virtioCoreGCPhysChainCalcBufSize(pVirtqBuf->pSgPhysReturn) -
     983                virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn)) - (cbTotal - cbRemain)),
     984                virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn) ));
     985
     986        uint16_t uPending = virtioCoreR3CountPendingBufs(
     987                                virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq),
     988                                pVirtq->uUsedIdxShadow, pVirtq->uQueueSize);
     989
     990        LogFunc(("    %u used buf%s not synced in %s\n", uPending, uPending == 1 ? "" : "s ",
     991                    VIRTQNAME(pVirtio, uVirtq)));
     992    }
     993#endif
     994    return VINF_SUCCESS;
     995}
     996
     997/** API function: See Header file  */
     998int virtioCoreR3VirtqUsedBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq,
     999                                size_t cb, void const *pv, PVIRTQBUF pVirtqBuf, uint32_t cbEnqueue, bool fFence)
     1000{
     1001    Assert(uVirtq < RT_ELEMENTS(pVirtio->aVirtqueues));
     1002    Assert(pv);
     1003
     1004    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
     1005    PVIRTIOSGBUF pSgPhysReturn = pVirtqBuf->pSgPhysReturn;
     1006
     1007    Assert(pVirtqBuf->u32Magic == VIRTQBUF_MAGIC);
     1008    Assert(pVirtqBuf->cRefs > 0);
     1009
     1010    AssertMsgReturn(IS_DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
     1011
     1012    Log6Func(("    Copying device data to %s, [desc chain head idx:%u]\n",
     1013              VIRTQNAME(pVirtio, uVirtq), pVirtqBuf->uHeadIdx));
     1014
     1015    /*
     1016     * Convert virtual memory simple buffer to guest physical memory (VirtIO descriptor chain)
     1017     */
     1018    uint8_t *pvBuf = (uint8_t *)pv;
     1019    size_t cbRemain = cb, cbCopy = 0;
     1020    while (cbRemain)
     1021    {
     1022        cbCopy = RT_MIN(pSgPhysReturn->cbSegLeft, cbRemain);
     1023        Assert(cbCopy > 0);
     1024        virtioCoreGCPhysWrite(pVirtio, pDevIns, (RTGCPHYS)pSgPhysReturn->GCPhysCur, pvBuf, cbCopy);
     1025        virtioCoreGCPhysChainAdvance(pSgPhysReturn, cbCopy);
     1026        pvBuf += cbCopy;
     1027        cbRemain -= cbCopy;
     1028    }
     1029    LogFunc(("     ...%zu bytes, copied to %u byte buf@offset=%u. Residual: %zu bytes\n",
     1030              cb ,  pVirtqBuf->cbPhysReturn,
     1031              ((virtioCoreGCPhysChainCalcBufSize(pVirtqBuf->pSgPhysReturn) -
     1032                 virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn)) - cb),
     1033                 virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn)));
     1034
     1035    if (cbEnqueue)
     1036    {
     1037        if (fFence)
     1038        {
     1039            RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); /* needed? */
     1040            Assert(!(cbCopy >> 32));
     1041        }
     1042        /* Flag if write-ahead crosses threshold where guest driver indicated it wants event notification */
     1043        if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX)
     1044            if (pVirtq->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq))
     1045                pVirtq->fUsedRingEvent = true;
     1046        /*
     1047         * Place used buffer's descriptor in used ring but don't update used ring's slot index.
     1048         * That will be done with a subsequent client call to virtioCoreVirtqUsedRingSync()
     1049         */
     1050        Log6Func(("    Enqueue desc chain head idx %u to %s used ring @ %u\n", pVirtqBuf->uHeadIdx,
     1051                VIRTQNAME(pVirtio, uVirtq), pVirtq->uUsedIdxShadow));
     1052
     1053        virtioWriteUsedElem(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow++, pVirtqBuf->uHeadIdx, cbEnqueue);
     1054
     1055#ifdef LOG_ENABLED
     1056        if (LogIs6Enabled())
     1057        {
     1058            uint16_t uPending = virtioCoreR3CountPendingBufs(
     1059                                    virtioReadUsedRingIdx(pDevIns, pVirtio, pVirtq),
     1060                                    pVirtq->uUsedIdxShadow, pVirtq->uQueueSize);
     1061
     1062            LogFunc(("    %u used buf%s not synced in %s\n",
     1063                    uPending, uPending == 1 ? "" : "s ", VIRTQNAME(pVirtio, uVirtq)));
     1064        }
     1065#endif
     1066    } /* fEnqueue */
    9611067
    9621068    return VINF_SUCCESS;
     
    9761082            ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    9771083
    978     Log6Func(("    %s ++used_idx=%u\n", pVirtq->szName, pVirtq->uUsedIdxShadow));
     1084    Log6Func(("    Sync %s used ring (%u → idx)\n",
     1085                        pVirtq->szName, pVirtq->uUsedIdxShadow));
    9791086
    9801087    virtioWriteUsedRingIdx(pDevIns, pVirtio, pVirtq, pVirtq->uUsedIdxShadow);
     
    9981105    PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
    9991106
    1000     /* See VirtIO 1.0, section 4.1.5.2 It implies that uVirtq and uNotifyIdx should match.
    1001      * Disregarding this notification may cause throughput to stop, however there's no way to know
    1002      * which was queue was intended for wake-up if the two parameters disagree. */
    1003 
     1107    /* VirtIO 1.0, section 4.1.5.2 implies uVirtq and uNotifyIdx should match. Disregarding any of
     1108     * these notifications (if those indicies disagree) may break device/driver synchronization,
     1109     * causing eternal throughput starvation, yet there's no specified way to disambiguate
     1110     * which queue to wake-up in any awkward situation where the two parameters differ.
     1111     */
    10041112    AssertMsg(uNotifyIdx == uVirtq,
    10051113              ("Guest kicked virtq %d's notify addr w/non-corresponding virtq idx %d\n",
     
    10101118    PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
    10111119
    1012     Log6Func(("%s (desc chains: %u)\n", pVirtq->szName,
     1120    Log6Func(("%s: (desc chains: %u)\n", pVirtq->szName ? pVirtq->szName : "?UNAMED QUEUE?",
    10131121        virtioCoreVirtqAvailCnt(pDevIns, pVirtio, pVirtq)));
    10141122
     
    10481156                   pVirtq->szName, (uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, pVirtq)));
    10491157#endif
    1050             virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
     1158            virtioNudgeGuest(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
    10511159            pVirtq->fUsedRingEvent = false;
    10521160            return;
     
    10621170        if (!(virtioReadAvailRingFlags(pDevIns, pVirtio, pVirtq) & VIRTQ_AVAIL_F_NO_INTERRUPT))
    10631171        {
    1064             virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
     1172            virtioNudgeGuest(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtq->uMsixVector);
    10651173            return;
    10661174        }
     
    10771185 * @param   uVec        MSI-X vector, if enabled
    10781186 */
    1079 static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixVector)
     1187static int virtioNudgeGuest(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uMsixVector)
    10801188{
    10811189    if (uCause == VIRTIO_ISR_VIRTQ_INTERRUPT)
    1082         Log6Func(("reason: buffer added to 'used' ring.\n"));
     1190        Log6Func(("Reason for interrupt - buffer added to 'used' ring.\n"));
    10831191    else
    10841192    if (uCause == VIRTIO_ISR_DEVICE_CONFIG)
    1085        Log6Func(("reason: device config change\n"));
     1193       Log6Func(("Reason for interrupt - device config change\n"));
    10861194
    10871195    if (!pVirtio->fMsiSupport)
     
    11321240{
    11331241    LogFunc(("Resetting device VirtIO state\n"));
    1134     pVirtio->fLegacyDriver          = 1;   /* Assume this. Cleared if VIRTIO_F_VERSION_1 feature ack'd */
     1242    pVirtio->fLegacyDriver          = pVirtio->fOfferLegacy;   /* Cleared if VIRTIO_F_VERSION_1 feature ack'd */
    11351243    pVirtio->uDeviceFeaturesSelect  = 0;
    11361244    pVirtio->uDriverFeaturesSelect  = 0;
     
    11681276}
    11691277#endif /* IN_RING3 */
     1278
     1279/*
     1280 * Determines whether guest virtio driver is modern or legacy and does callback
     1281 * informing device-specific code that feature negotiation is complete.
     1282 * Should be called only once (coordinated via the 'toggle' flag)
     1283 */
     1284#ifdef IN_RING3
     1285DECLINLINE(void) virtioR3DoFeaturesCompleteOnceOnly(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC)
     1286{
     1287        if (pVirtio->uDriverFeatures & VIRTIO_F_VERSION_1)
     1288        {
     1289            LogFunc(("VIRTIO_F_VERSION_1 feature ack'd by guest\n"));
     1290            pVirtio->fLegacyDriver = 0;
     1291        }
     1292        else
     1293        {
     1294            if (pVirtio->fOfferLegacy)
     1295            {
     1296                pVirtio->fLegacyDriver = 1;
     1297                LogFunc(("VIRTIO_F_VERSION_1 feature was NOT set by guest\n"));
     1298            }
     1299            else
     1300                AssertMsgFailed(("Guest didn't accept VIRTIO_F_VERSION_1, but fLegacyOffered flag not set.\n"));
     1301        }
     1302        pVirtioCC->pfnFeatureNegotiationComplete(pVirtio, pVirtio->uDriverFeatures, pVirtio->fLegacyDriver);
     1303        pVirtio->fDriverFeaturesWritten |= DRIVER_FEATURES_COMPLETE_HANDLED;
     1304}
     1305#endif
    11701306
    11711307/**
     
    12281364                case 0:
    12291365                    memcpy(&pVirtio->uDriverFeatures, pv, cb);
     1366                    pVirtio->fDriverFeaturesWritten |= DRIVER_FEATURES_0_WRITTEN;
     1367            LogFunc(("Set DRIVER_FEATURES_0_WRITTEN. pVirtio->fDriverFeaturesWritten=%d\n", pVirtio->fDriverFeaturesWritten));
     1368                    if (     (pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_0_AND_1_WRITTEN) == DRIVER_FEATURES_0_AND_1_WRITTEN
     1369                        && !(pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_COMPLETE_HANDLED))
     1370#ifdef IN_RING0
     1371                        return VINF_IOM_R3_MMIO_WRITE;
     1372#endif
     1373#ifdef IN_RING3
     1374                        virtioR3DoFeaturesCompleteOnceOnly(pVirtio, pVirtioCC);
     1375#endif
    12301376                    VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess);
    12311377                    break;
    12321378                case 1:
    12331379                    memcpy((char *)&pVirtio->uDriverFeatures + sizeof(uint32_t), pv, cb);
    1234                     if (pVirtio->uDriverFeatures & VIRTIO_F_VERSION_1)
    1235                     {
     1380                    pVirtio->fDriverFeaturesWritten |= DRIVER_FEATURES_1_WRITTEN;
     1381            LogFunc(("Set DRIVER_FEATURES_1_WRITTEN. pVirtio->fDriverFeaturesWritten=%d\n", pVirtio->fDriverFeaturesWritten));
     1382                    if (     (pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_0_AND_1_WRITTEN) == DRIVER_FEATURES_0_AND_1_WRITTEN
     1383                        && !(pVirtio->fDriverFeaturesWritten & DRIVER_FEATURES_COMPLETE_HANDLED))
    12361384#ifdef IN_RING0
    12371385                        return VINF_IOM_R3_MMIO_WRITE;
    12381386#endif
    12391387#ifdef IN_RING3
    1240                         pVirtio->fLegacyDriver = 0;
    1241                         pVirtioCC->pfnGuestVersionHandler(pVirtio, 1 /* fModern */);
    1242 #endif
    1243                     }
     1388                        virtioR3DoFeaturesCompleteOnceOnly(pVirtio, pVirtioCC);
     1389#endif
    12441390                    VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_PCI_COMMON_CFG_T, uOffsetOfAccess + sizeof(uint32_t));
    12451391                    break;
     
    13891535 * This I/O handler exists only to handle access from legacy drivers.
    13901536 */
    1391 
    13921537static DECLCALLBACK(VBOXSTRICTRC) virtioLegacyIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
    13931538{
    1394 
    13951539    PVIRTIOCORE   pVirtio = PDMINS_2_DATA(pDevIns, PVIRTIOCORE);
    13961540    STAM_PROFILE_ADV_START(&pVirtio->CTX_SUFF(StatRead), a);
    13971541
    13981542    RT_NOREF(pvUser);
     1543    Log(("%-23s: Port read at offset=%RTiop, cb=%#x%s",
     1544        __FUNCTION__, offPort, cb,
     1545        VIRTIO_DEV_CONFIG_MATCH_MEMBER(fIsrStatus, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort) ? "" : "\n"));
    13991546
    14001547    void *pv = pu32; /* To use existing macros */
     
    14121559    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
    14131560    {
    1414         uint32_t val = pVirtio->uDriverFeatures & 0xffffffff;
     1561        uint32_t val = pVirtio->uDriverFeatures &  UINT32_C(0xffffffff);
    14151562        memcpy(pu32, &val, cb);
    14161563        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures, VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
     
    14201567    {
    14211568        *(uint8_t *)pu32 = pVirtio->fDeviceStatus;
    1422 
    14231569        if (LogIs7Enabled())
    14241570        {
     
    14351581        pVirtio->uISR = 0;
    14361582        virtioLowerInterrupt( pDevIns,  0);
    1437         Log((" ISR read and cleared\n"));
     1583        Log((" (ISR read and cleared)\n"));
    14381584    }
    14391585    else
     
    14821628        return rc;
    14831629    }
    1484 
    14851630    STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatRead), a);
    14861631    return VINF_SUCCESS;
    14871632}
    1488 
    14891633
    14901634/**
     
    15041648    int fWrite = 1;         /* To use existing macros */
    15051649
    1506 //    LogFunc(("Write to port offset=%RTiop, cb=%#x, u32=%#x\n", offPort, cb, u32));
     1650    Log(("%-23s: Port written at offset=%RTiop, cb=%#x, u32=%#x\n",  __FUNCTION__, offPort, cb, u32));
    15071651
    15081652    if (VIRTIO_DEV_CONFIG_MATCH_MEMBER(   uVirtqSelect,        VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort))
     
    15351679                pVirtio->uDriverFeatures &= VIRTIO_DEV_INDEPENDENT_LEGACY_FEATURES_OFFERED;
    15361680        }
     1681        if (!((pVirtio->fDriverFeaturesWritten ^= 1) & 1))
     1682        {
     1683#ifdef IN_RING0
     1684            Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__));
     1685            return VINF_IOM_R3_MMIO_WRITE;
     1686#endif
     1687#ifdef IN_RING3
     1688            PVIRTIOCORECC pVirtioCC = PDMINS_2_DATA_CC(pDevIns, PVIRTIOCORECC);
     1689            virtioR3DoFeaturesCompleteOnceOnly(pVirtio, pVirtioCC);
     1690#endif
     1691        }
    15371692        VIRTIO_DEV_CONFIG_LOG_ACCESS(uDriverFeatures,          VIRTIO_LEGACY_PCI_COMMON_CFG_T, offPort);
    15381693    }
     
    15561711            Log(("%-23s: Guest wrote fDeviceStatus ................ (%s)\n", __FUNCTION__, szOut));
    15571712        }
    1558 
    15591713        if (fDriverStateImproved  || fDriverInitiatedReset)
    15601714        {
     
    16931847
    16941848        /*
    1695          * Additionally, anytime any part of the device-specific configuration (which our client maintains)
    1696          * is READ it needs to be checked to see if it changed since the last time any part was read, in
    1697          * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1)
     1849         * Anytime any part of the dev-specific dev config (which this virtio core implementation sees
     1850         * as a blob, and virtio dev-specific code separates into fields) is READ, it must be compared
     1851         * for deltas from previous read to maintain a config gen. seq. counter (VirtIO 1.0, section 4.1.4.3.1)
    16981852         */
    16991853        bool fDevSpecificFieldChanged = RT_BOOL(memcmp(pVirtioCC->pbDevSpecificCfg + uOffset,
     
    17061860        {
    17071861            ++pVirtio->uConfigGeneration;
    1708             Log6Func(("Bumped cfg. generation to %d because %s%s\n",
    1709                       pVirtio->uConfigGeneration,
     1862            Log6Func(("Bumped cfg. generation to %d because %s%s\n", pVirtio->uConfigGeneration,
    17101863                      fDevSpecificFieldChanged ? "<dev cfg changed> " : "",
    17111864                      pVirtio->fGenUpdatePending ? "<update was pending>" : ""));
     
    17691922#else
    17701923        STAM_PROFILE_ADV_STOP(&pVirtio->CTX_SUFF(StatWrite), a);
     1924        Log6(("%-23s: RING0 => RING3 (demote)\n", __FUNCTION__));
    17711925        return VINF_IOM_R3_MMIO_WRITE;
    17721926#endif
     
    18191973    if (uAddress == pVirtio->uPciCfgDataOff)
    18201974    {
    1821         /*
    1822          * VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability
    1823          * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
    1824          * (the virtio_pci_cfg_cap capability), and access data items.
    1825          * This is used by BIOS to gain early boot access to the the storage device.
    1826          */
     1975     /* See comments in PCI Cfg capability initialization (in capabilities setup section of this code) */
    18271976        struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap;
    18281977        uint32_t uLength = pPciCap->uLength;
     
    18632012    if (uAddress == pVirtio->uPciCfgDataOff)
    18642013    {
    1865         /* VirtIO 1.0 spec section 4.1.4.7 describes a required alternative access capability
    1866          * whereby the guest driver can specify a bar, offset, and length via the PCI configuration space
    1867          * (the virtio_pci_cfg_cap capability), and access data items.
    1868          * This is used by BIOS to gain early boot access to the the storage device.*/
    1869 
     2014        /* See comments in PCI Cfg capability initialization (in capabilities setup section of this code) */
    18702015        struct virtio_pci_cap *pPciCap = &pVirtioCC->pPciCfgCap->pciCap;
    18712016        uint32_t uLength = pPciCap->uLength;
     
    18892034
    18902035/*********************************************************************************************************************************
    1891 *   Saved state.                                                                                                                 *
     2036*   Saved state (SSM)                                                                                                            *
    18922037*********************************************************************************************************************************/
     2038
     2039
     2040/**
     2041 * Loads a saved device state (called from device-specific code on SSM final pass)
     2042 *
     2043 * @param   pVirtio     Pointer to the shared virtio state.
     2044 * @param   pHlp        The ring-3 device helpers.
     2045 * @param   pSSM        The saved state handle.
     2046 * @returns VBox status code.
     2047 */
     2048int virtioCoreR3LegacyDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp,
     2049                               PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uVirtioLegacy_3_1_Beta)
     2050{
     2051    int rc;
     2052    uint32_t uDriverFeaturesLegacy32bit;
     2053
     2054    rc = pHlp->pfnSSMGetU32(  pSSM, &uDriverFeaturesLegacy32bit);
     2055    AssertRCReturn(rc, rc);
     2056    pVirtio->uDriverFeatures = (uint64_t)uDriverFeaturesLegacy32bit;
     2057
     2058    rc = pHlp->pfnSSMGetU16(  pSSM, &pVirtio->uVirtqSelect);
     2059    AssertRCReturn(rc, rc);
     2060
     2061    rc = pHlp->pfnSSMGetU8(   pSSM, &pVirtio->fDeviceStatus);
     2062    AssertRCReturn(rc, rc);
     2063
     2064    char szOut[80] = { 0 };
     2065    virtioCoreFormatDeviceStatus(pVirtio->fDeviceStatus, szOut, sizeof(szOut));
     2066    Log(("Loaded legacy device status = (%s)\n", szOut));
     2067
     2068    rc = pHlp->pfnSSMGetU8(   pSSM, &pVirtio->uISR);
     2069    AssertRCReturn(rc, rc);
     2070
     2071    uint32_t cQueues = 3; /* Thes constant default value copied from earliest v0.9 code */
     2072    if (uVersion > uVirtioLegacy_3_1_Beta)
     2073    {
     2074        rc = pHlp->pfnSSMGetU32(pSSM, &cQueues);
     2075        AssertRCReturn(rc, rc);
     2076    }
     2077
     2078    AssertLogRelMsgReturn(cQueues <= VIRTQ_MAX_COUNT, ("%#x\n", cQueues), VERR_SSM_LOAD_CONFIG_MISMATCH);
     2079    AssertLogRelMsgReturn(pVirtio->uVirtqSelect < cQueues || (cQueues == 0 && pVirtio->uVirtqSelect),
     2080                          ("uVirtqSelect=%u cQueues=%u\n", pVirtio->uVirtqSelect, cQueues),
     2081                          VERR_SSM_LOAD_CONFIG_MISMATCH);
     2082
     2083    Log(("\nRestoring %d  legacy-only virtio-net device queues from saved state:\n", cQueues));
     2084    for (unsigned uVirtq = 0; uVirtq < cQueues; uVirtq++)
     2085    {
     2086        PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[uVirtq];
     2087
     2088        if (uVirtq == cQueues - 1)
     2089            RTStrPrintf(pVirtq->szName, sizeof(pVirtq->szName), "legacy-ctrlq");
     2090        else if (uVirtq % 2)
     2091            RTStrPrintf(pVirtq->szName, sizeof(pVirtq->szName), "legacy-xmitq<%d>", uVirtq / 2);
     2092        else
     2093            RTStrPrintf(pVirtq->szName, sizeof(pVirtq->szName), "legacy-recvq<%d>", uVirtq / 2);
     2094
     2095        rc = pHlp->pfnSSMGetU16(pSSM, &pVirtq->uQueueSize);
     2096        AssertRCReturn(rc, rc);
     2097
     2098        uint32_t uVirtqPfn;
     2099        rc = pHlp->pfnSSMGetU32(pSSM, &uVirtqPfn);
     2100        AssertRCReturn(rc, rc);
     2101
     2102        rc = pHlp->pfnSSMGetU16(pSSM, &pVirtq->uAvailIdxShadow);
     2103        AssertRCReturn(rc, rc);
     2104
     2105        rc = pHlp->pfnSSMGetU16(pSSM, &pVirtq->uUsedIdxShadow);
     2106        AssertRCReturn(rc, rc);
     2107
     2108        if (uVirtqPfn)
     2109        {
     2110            pVirtq->GCPhysVirtqDesc  = (uint64_t)uVirtqPfn * VIRTIO_PAGE_SIZE;
     2111            pVirtq->GCPhysVirtqAvail = pVirtq->GCPhysVirtqDesc + sizeof(VIRTQ_DESC_T) * pVirtq->uQueueSize;
     2112            pVirtq->GCPhysVirtqUsed  =
     2113                RT_ALIGN(pVirtq->GCPhysVirtqAvail + RT_UOFFSETOF_DYN(VIRTQ_AVAIL_T, auRing[pVirtq->uQueueSize]), VIRTIO_PAGE_SIZE);
     2114            pVirtq->uEnable = 1;
     2115        }
     2116        else
     2117        {
     2118            LogFunc(("WARNING: QUEUE \"%s\" PAGE NUMBER ZERO IN SAVED STATE\n", pVirtq->szName));
     2119            pVirtq->uEnable = 0;
     2120        }
     2121        pVirtq->uNotifyOffset = 0;  /* unused in legacy mode */
     2122        pVirtq->uMsixVector   = 0;  /* unused in legacy mode */
     2123    }
     2124    pVirtio->fGenUpdatePending = 0; /* unused in legacy mode */
     2125    pVirtio->uConfigGeneration = 0; /* unused in legacy mode */
     2126    pVirtio->uPciCfgDataOff    = 0; /* unused in legacy mode (port I/O used instead)   */
     2127
     2128    return VINF_SUCCESS;
     2129}
     2130
     2131/**
     2132 * Loads a saved device state (called from device-specific code on SSM final pass)
     2133 *
     2134 * Note: This loads state saved by a Modern (VirtIO 1.0+) device, of which this transitional device is one,
     2135 *       and thus supports both legacy and modern guest virtio drivers.
     2136 *
     2137 * @param   pVirtio     Pointer to the shared virtio state.
     2138 * @param   pHlp        The ring-3 device helpers.
     2139 * @param   pSSM        The saved state handle.
     2140 * @returns VBox status code.
     2141 */
     2142int virtioCoreR3ModernDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uTestVersion, uint32_t cQueues)
     2143{
     2144    RT_NOREF2(cQueues, uVersion);
     2145    LogFunc(("\n"));
     2146    /*
     2147     * Check the marker and (embedded) version number.
     2148     */
     2149    uint64_t uMarker = 0;
     2150    int rc;
     2151
     2152    rc = pHlp->pfnSSMGetU64(pSSM, &uMarker);
     2153    AssertRCReturn(rc, rc);
     2154    if (uMarker != VIRTIO_SAVEDSTATE_MARKER)
     2155        return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
     2156                                        N_("Expected marker value %#RX64 found %#RX64 instead"),
     2157                                        VIRTIO_SAVEDSTATE_MARKER, uMarker);
     2158    uint32_t uVersionSaved = 0;
     2159    rc = pHlp->pfnSSMGetU32(pSSM, &uVersionSaved);
     2160    AssertRCReturn(rc, rc);
     2161    if (uVersionSaved != uTestVersion)
     2162        return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
     2163                                        N_("Unsupported virtio version: %u"), uVersionSaved);
     2164    /*
     2165     * Load the state.
     2166     */
     2167    rc = pHlp->pfnSSMGetU32(  pSSM, &pVirtio->fLegacyDriver);
     2168    AssertRCReturn(rc, rc);
     2169    rc = pHlp->pfnSSMGetBool( pSSM, &pVirtio->fGenUpdatePending);
     2170    AssertRCReturn(rc, rc);
     2171    rc = pHlp->pfnSSMGetU8(   pSSM, &pVirtio->fDeviceStatus);
     2172    AssertRCReturn(rc, rc);
     2173    rc = pHlp->pfnSSMGetU8(   pSSM, &pVirtio->uConfigGeneration);
     2174    AssertRCReturn(rc, rc);
     2175    rc = pHlp->pfnSSMGetU8(   pSSM, &pVirtio->uPciCfgDataOff);
     2176    AssertRCReturn(rc, rc);
     2177    rc = pHlp->pfnSSMGetU8(   pSSM, &pVirtio->uISR);
     2178    AssertRCReturn(rc, rc);
     2179    rc = pHlp->pfnSSMGetU16(  pSSM, &pVirtio->uVirtqSelect);
     2180    AssertRCReturn(rc, rc);
     2181    rc = pHlp->pfnSSMGetU32(  pSSM, &pVirtio->uDeviceFeaturesSelect);
     2182    AssertRCReturn(rc, rc);
     2183    rc = pHlp->pfnSSMGetU32(  pSSM, &pVirtio->uDriverFeaturesSelect);
     2184    AssertRCReturn(rc, rc);
     2185    rc = pHlp->pfnSSMGetU64(  pSSM, &pVirtio->uDriverFeatures);
     2186    AssertRCReturn(rc, rc);
     2187
     2188    /** @todo Adapt this loop use cQueues argument instead of static queue count (safely with SSM versioning) */
     2189    for (uint32_t i = 0; i < VIRTQ_MAX_COUNT; i++)
     2190    {
     2191        PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[i];
     2192        rc = pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqDesc);
     2193        AssertRCReturn(rc, rc);
     2194        rc = pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqAvail);
     2195        AssertRCReturn(rc, rc);
     2196        rc = pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqUsed);
     2197        AssertRCReturn(rc, rc);
     2198        rc = pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uNotifyOffset);
     2199        AssertRCReturn(rc, rc);
     2200        rc = pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uMsixVector);
     2201        AssertRCReturn(rc, rc);
     2202        rc = pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uEnable);
     2203        AssertRCReturn(rc, rc);
     2204        rc = pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uQueueSize);
     2205        AssertRCReturn(rc, rc);
     2206        rc = pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uAvailIdxShadow);
     2207        AssertRCReturn(rc, rc);
     2208        rc = pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uUsedIdxShadow);
     2209        AssertRCReturn(rc, rc);
     2210        rc = pHlp->pfnSSMGetMem( pSSM, pVirtq->szName,  sizeof(pVirtq->szName));
     2211        AssertRCReturn(rc, rc);
     2212    }
     2213    return VINF_SUCCESS;
     2214}
    18932215
    18942216/**
     
    19002222 * @returns VBox status code.
    19012223 */
    1902 int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
    1903 {
     2224int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t cQueues)
     2225{
     2226    RT_NOREF(cQueues);
     2227    /** @todo figure out a way to save cQueues (with SSM versioning) */
     2228
    19042229    LogFunc(("\n"));
    19052230    pHlp->pfnSSMPutU64(pSSM, VIRTIO_SAVEDSTATE_MARKER);
    1906     pHlp->pfnSSMPutU32(pSSM, VIRTIO_SAVEDSTATE_VERSION);
    1907 
     2231    pHlp->pfnSSMPutU32(pSSM, uVersion);
     2232
     2233    pHlp->pfnSSMPutU32( pSSM, pVirtio->fLegacyDriver);
    19082234    pHlp->pfnSSMPutBool(pSSM, pVirtio->fGenUpdatePending);
    19092235    pHlp->pfnSSMPutU8(  pSSM, pVirtio->fDeviceStatus);
     
    19322258        AssertRCReturn(rc, rc);
    19332259    }
    1934 
    1935     return VINF_SUCCESS;
    1936 }
    1937 
    1938 /**
    1939  * Called from the FNSSMDEVLOADEXEC function of the device.
    1940  *
    1941  * @param   pVirtio     Pointer to the shared virtio state.
    1942  * @param   pHlp        The ring-3 device helpers.
    1943  * @param   pSSM        The saved state handle.
    1944  * @returns VBox status code.
    1945  */
    1946 int virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM)
    1947 {
    1948     LogFunc(("\n"));
    1949     /*
    1950      * Check the marker and (embedded) version number.
    1951      */
    1952     uint64_t uMarker = 0;
    1953     int rc = pHlp->pfnSSMGetU64(pSSM, &uMarker);
    1954     AssertRCReturn(rc, rc);
    1955     if (uMarker != VIRTIO_SAVEDSTATE_MARKER)
    1956         return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    1957                                         N_("Expected marker value %#RX64 found %#RX64 instead"),
    1958                                         VIRTIO_SAVEDSTATE_MARKER, uMarker);
    1959     uint32_t uVersion = 0;
    1960     rc = pHlp->pfnSSMGetU32(pSSM, &uVersion);
    1961     AssertRCReturn(rc, rc);
    1962     if (uVersion != VIRTIO_SAVEDSTATE_VERSION)
    1963         return pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
    1964                                         N_("Unsupported virtio version: %u"), uVersion);
    1965     /*
    1966      * Load the state.
    1967      */
    1968     pHlp->pfnSSMGetBool( pSSM, &pVirtio->fGenUpdatePending);
    1969     pHlp->pfnSSMGetU8(   pSSM, &pVirtio->fDeviceStatus);
    1970     pHlp->pfnSSMGetU8(   pSSM, &pVirtio->uConfigGeneration);
    1971     pHlp->pfnSSMGetU8(   pSSM, &pVirtio->uPciCfgDataOff);
    1972     pHlp->pfnSSMGetU8(   pSSM, &pVirtio->uISR);
    1973     pHlp->pfnSSMGetU16(  pSSM, &pVirtio->uVirtqSelect);
    1974     pHlp->pfnSSMGetU32(  pSSM, &pVirtio->uDeviceFeaturesSelect);
    1975     pHlp->pfnSSMGetU32(  pSSM, &pVirtio->uDriverFeaturesSelect);
    1976     pHlp->pfnSSMGetU64(  pSSM, &pVirtio->uDriverFeatures);
    1977 
    1978     for (uint32_t i = 0; i < VIRTQ_MAX_COUNT; i++)
    1979     {
    1980         PVIRTQUEUE pVirtq = &pVirtio->aVirtqueues[i];
    1981 
    1982         pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqDesc);
    1983         pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqAvail);
    1984         pHlp->pfnSSMGetGCPhys64( pSSM, &pVirtq->GCPhysVirtqUsed);
    1985         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uNotifyOffset);
    1986         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uMsixVector);
    1987         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uEnable);
    1988         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uQueueSize);
    1989         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uAvailIdxShadow);
    1990         pHlp->pfnSSMGetU16(      pSSM, &pVirtq->uUsedIdxShadow);
    1991         rc = pHlp->pfnSSMGetMem( pSSM, pVirtq->szName,  sizeof(pVirtq->szName));
    1992         AssertRCReturn(rc, rc);
    1993     }
    1994 
    19952260    return VINF_SUCCESS;
    19962261}
     
    20022267
    20032268/**
    2004  * This must be called by the client to handle VM state changes
    2005  * after the client takes care of its device-specific tasks for the state change.
    2006  * (i.e. Reset, suspend, power-off, resume)
     2269 * This must be called by the client to handle VM state changes after the client takes care of its device-specific
     2270 * tasks for the state change (i.e. reset, suspend, power-off, resume)
    20072271 *
    20082272 * @param   pDevIns     The device instance.
     
    20572321/** API Function: See header file */
    20582322int virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, PVIRTIOPCIPARAMS pPciParams,
    2059                      const char *pcszInstance, uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg)
     2323                     const char *pcszInstance, uint64_t fDevSpecificFeatures, uint32_t fOfferLegacy,
     2324                     void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg)
    20602325{
    20612326    /*
    2062      * The pVirtio state must be the first member of the shared device instance
    2063      * data, otherwise we cannot get our bearings in the PCI configuration callbacks.
     2327     * Virtio state must be the first member of shared device instance data,
     2328     * otherwise can't get our bearings in PCI config callbacks.
    20642329     */
    20652330    AssertLogRelReturn(pVirtio == PDMINS_2_DATA(pDevIns, PVIRTIOCORE), VERR_STATE_CHANGED);
     
    20732338    AssertReturn(pVirtioCC->pfnStatusChanged, VERR_INVALID_POINTER);
    20742339    AssertReturn(pVirtioCC->pfnVirtqNotified, VERR_INVALID_POINTER);
    2075     AssertReturn(pVirtioCC->pfnGuestVersionHandler,  VERR_INVALID_POINTER);
     2340    AssertReturn(pVirtioCC->pfnFeatureNegotiationComplete,  VERR_INVALID_POINTER);
    20762341    AssertReturn(VIRTQ_SIZE > 0 && VIRTQ_SIZE <= 32768,  VERR_OUT_OF_RANGE); /* VirtIO specification-defined limit */
    20772342
    20782343#if 0 /* Until pdmR3DvHlp_PCISetIrq() impl is fixed and Assert that limits vec to 0 is removed
    2079        * The legacy MSI support has not been implemented yet
     2344       * VBox legacy MSI support has not been implemented yet
    20802345       */
    20812346# ifdef VBOX_WITH_MSI_DEVICES
     
    20842349#endif
    20852350
    2086     /* Tell the device-specific code that guest is in legacy mode (for now) */
    2087     pVirtioCC->pfnGuestVersionHandler(pVirtio, false /* fModern */);
    2088 
    20892351    /*
    2090      * The host features offered include both device-specific features
    2091      * and reserved feature bits (device independent)
     2352     * Host features (presented as a smörgasbord for guest to select from)
     2353     * include both dev-specific features & reserved dev-independent features (bitmask).
    20922354     */
    20932355    pVirtio->uDeviceFeatures = VIRTIO_F_VERSION_1
    20942356                             | VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED
    20952357                             | fDevSpecificFeatures;
     2358
     2359    pVirtio->fLegacyDriver = pVirtio->fOfferLegacy = fOfferLegacy;
    20962360
    20972361    RTStrCopy(pVirtio->szInstance, sizeof(pVirtio->szInstance), pcszInstance);
     
    21382402    uint32_t cbRegion = 0;
    21392403
    2140     /* Common capability (VirtIO 1.0 spec, section 4.1.4.3) */
     2404    /*
     2405     * Common capability (VirtIO 1.0, section 4.1.4.3)
     2406     */
    21412407    pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[0x40];
    21422408    pCfg->uCfgType = VIRTIO_PCI_CAP_COMMON_CFG;
     
    21522418
    21532419    /*
    2154      * Notify capability (VirtIO 1.0 spec, section 4.1.4.4). Note: uLength is based on the choice
    2155      * of this implementation to make each queue's uNotifyOffset equal to (VirtqSelect) ordinal
    2156      * value of the queue (different strategies are possible according to spec).
     2420     * Notify capability (VirtIO 1.0, section 4.1.4.4).
     2421     *
     2422     * The size of the spec-defined subregion described by this VirtIO capability is
     2423     * based-on the choice of this implementation to make the notification area of each
     2424     * queue equal to queue's ordinal position (e.g. queue selector value). The VirtIO
     2425     * specification leaves it up to implementation to define queue notification area layout.
    21572426     */
    21582427    pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext];
     
    21702439    pVirtioCC->pNotifyCap->uNotifyOffMultiplier = VIRTIO_NOTIFY_OFFSET_MULTIPLIER;
    21712440
    2172     /* ISR capability (VirtIO 1.0 spec, section 4.1.4.5)
     2441    /* ISR capability (VirtIO 1.0, section 4.1.4.5)
    21732442     *
    2174      * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. Example/diagram
    2175      * of spec shows it as a 32-bit field with upper bits 'reserved'
    2176      * Will take spec's words more literally than the diagram for now.
     2443     * VirtIO 1.0 spec says 8-bit, unaligned in MMIO space. The specification example/diagram
     2444     * illustrates this capability as 32-bit field with upper bits 'reserved'. Those depictions
     2445     * differ. The spec's wording, not the diagram, is seen to work in practice.
    21772446     */
    21782447    pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext];
     
    21892458    pVirtioCC->pIsrCap = pCfg;
    21902459
    2191     /*  PCI Cfg capability (VirtIO 1.0 spec, section 4.1.4.7)
    2192      *  This capability doesn't get page-MMIO mapped. Instead uBar, uOffset and uLength are intercepted
    2193      *  by trapping PCI configuration I/O and get modulated by consumers to locate fetch and read/write
    2194      *  values from any region. NOTE: The linux driver not only doesn't use this feature, it will not
    2195      *  even list it as present if uLength isn't non-zero and also 4-byte-aligned as the linux driver is
    2196      *  initializing.
     2460    /*  PCI Cfg capability (VirtIO 1.0, section 4.1.4.7)
     2461     *
     2462     *  This capability facilitates early-boot access to this device (BIOS).
     2463     *  This region isn't page-MMIO mapped. PCI configuration accesses are intercepted,
     2464     *  wherein uBar, uOffset and uLength are modulated by consumers to locate and read/write
     2465     *  values in any part of any region. (NOTE: Linux driver doesn't utilize this feature.
     2466     *  This capability only appears in lspci output on Linux if uLength is non-zero, 4-byte aligned,
     2467     *  during initialization of linux virtio driver).
    21972468     */
    21982469    pVirtio->uPciCfgDataOff = pCfg->uCapNext + RT_OFFSETOF(VIRTIO_PCI_CFG_CAP_T, uPciCfgData);
     
    22112482    if (pVirtioCC->pbDevSpecificCfg)
    22122483    {
    2213         /* Device specific config capability (via VirtIO 1.0, section 4.1.4.6).
     2484        /* Device-specific config capability (VirtIO 1.0, section 4.1.4.6).
     2485         *
    22142486         * Client defines the device-specific config struct and passes size to virtioCoreR3Init()
    2215          * to inform this. */
     2487         * to inform this.
     2488         */
    22162489        pCfg = (PVIRTIO_PCI_CAP_T)&pPciDev->abConfig[pCfg->uCapNext];
    22172490        pCfg->uCfgType = VIRTIO_PCI_CAP_DEVICE_CFG;
     
    22632536        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: out of memory allocating string")); /* can we put params in this error? */
    22642537
    2265     /* As a transitional device that supports legacy VirtIO drivers, this VirtIO device generic implementation presents
    2266      * legacy driver interface in I/O space at BAR0. The following maps the common (e.g. device independent)
    2267      * dev config area as well as device-specific dev config area (whose size is passed to init function of this VirtIO
    2268      * generic device code) for access via Port I/O, since legacy drivers (e.g. pre VirtIO 1.0) don't use MMIO callbacks.
    2269      * (See VirtIO 1.1, Section 4.1.4.8).
    2270      */
    2271     rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, VIRTIO_REGION_LEGACY_IO, sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T) + cbDevSpecificCfg,
    2272                                       virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/, pVirtioCC->pcszPortIoName,
    2273                                       NULL /*paExtDescs*/, &pVirtio->hLegacyIoPorts);
    2274     AssertLogRelRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register legacy config in I/O space at BAR0 */")));
     2538    if (pVirtio->fOfferLegacy)
     2539    {
     2540        /* As a transitional device that supports legacy VirtIO drivers, this VirtIO device generic implementation presents
     2541         * legacy driver interface in I/O space at BAR0. The following maps the common (e.g. device independent)
     2542         * dev config area as well as device-specific dev config area (whose size is passed to init function of this VirtIO
     2543         * generic device code) for access via Port I/O, since legacy drivers (e.g. pre VirtIO 1.0) don't use MMIO callbacks.
     2544         * (See VirtIO 1.1, Section 4.1.4.8).
     2545         */
     2546        rc = PDMDevHlpPCIIORegionCreateIo(pDevIns, VIRTIO_REGION_LEGACY_IO, sizeof(VIRTIO_LEGACY_PCI_COMMON_CFG_T) + cbDevSpecificCfg,
     2547                                          virtioLegacyIOPortOut, virtioLegacyIOPortIn, NULL /*pvUser*/, pVirtioCC->pcszPortIoName,
     2548                                          NULL /*paExtDescs*/, &pVirtio->hLegacyIoPorts);
     2549        AssertLogRelRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio: cannot register legacy config in I/O space at BAR0 */")));
     2550    }
    22752551
    22762552    /*  Note: The Linux driver at drivers/virtio/virtio_pci_modern.c tries to map at least a page for the
    2277      * 'unknown' device-specific capability without querying the capability to figure
    2278      *  out size, so pad with an extra page
     2553     * 'unknown' device-specific capability without querying the capability to determine size, so pad w/extra page.
    22792554     */
    22802555    rc = PDMDevHlpPCIIORegionCreateMmio(pDevIns, VIRTIO_REGION_PCI_CAP, RT_ALIGN_32(cbRegion + VIRTIO_PAGE_SIZE, VIRTIO_PAGE_SIZE),
     
    23042579# endif /* VBOX_WITH_STATISTICS */
    23052580
    2306     virtioResetDevice(pDevIns, pVirtio); /* Reset VirtIO specific state of device */
    2307 
    23082581    return VINF_SUCCESS;
    23092582}
  • trunk/src/VBox/Devices/VirtIO/VirtioCore.h

    r92091 r92939  
    3636# define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) do { } while (0)
    3737#endif
     38
     39/** Marks the start of the virtio saved state (just for sanity). */
     40#define VIRTIO_SAVEDSTATE_MARKER                        UINT64_C(0x1133557799bbddff)
    3841
    3942/** Pointer to the shared VirtIO state. */
     
    5760#define VIRTIO_PAGE_SIZE                 4096                    /**< Page size used by VirtIO specification   */
    5861
    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)      */
    66 
    67 
    68 /** The following virtioCoreGCPhysChain*() functions mimic the functionality of the related RT s/g functions,
    69  *  except they work with the data type GCPhys rather than void *
     62/**
     63 * @todo Move the following virtioCoreGCPhysChain*() functions mimic the functionality of the related
     64 *       into some VirtualBox source tree common location and out of this code.
     65 *
     66 *       They behave identically to the S/G utilities in the RT library, except they work with that
     67 *       GCPhys data type specifically instead of void *, to avoid potentially disastrous mismatch
     68 *       between sizeof(void *) and sizeof(GCPhys).
     69 *
    7070 */
    7171typedef struct VIRTIOSGSEG                                      /**< An S/G entry                              */
     
    9191
    9292/**
    93  * VirtIO buffers are descriptor chains (scatter-gather vectors). Each buffer is described
    94  * by the index of its head descriptor, which in optionally chains to another descriptor
    95  * and so on.
    96  *
    97  * Each descriptor, [len, GCPhys] pair in the chain represents either an OUT segment (e.g. guest-to-host)
    98  * or an IN segment (host-to-guest). A VIRTQBUF is created and retured from a call to
    99  * virtioCoreR3VirtqAvailBufPeek() or virtioCoreR3VirtqAvailBufGet(). That function consolodates
    100  * the VirtIO descriptor chain into a representation, where pSgPhysSend is a GCPhys s/g buffer containing
    101  * all of the OUT descriptors and pSgPhysReturn is a GCPhys s/g buffer containing all of IN descriptors
    102  * to be filled with data on the host to return to theguest.
     93 * VirtIO buffers are descriptor chains (e.g. scatter-gather vectors). A VirtIO buffer is referred to by the index
     94 * of its head descriptor. Each descriptor optionally chains to another descriptor, and so on.
     95 *
     96 * For any given descriptor, each length and GCPhys pair in the chain represents either an OUT segment (e.g. guest-to-host)
     97 * or an IN segment (host-to-guest).
     98 *
     99 * A VIRTQBUF is created and retured from a call to to either virtioCoreR3VirtqAvailBufPeek() or virtioCoreR3VirtqAvailBufGet().
     100 *
     101 * Those functions consolidate the VirtIO descriptor chain into a single representation where:
     102 *
     103 *     pSgPhysSend    GCPhys s/g buffer containing all of the (VirtIO) OUT descriptors
     104 *     pSgPhysReturn  GCPhys s/g buffer containing all of the (VirtIO)  IN descriptors
     105 *
     106 * The OUT descriptors are data sent from guest to host (dev-specific commands and/or data)
     107 * The IN are to be filled with data (converted to physical) on host, to be returned to guest
     108 *
    103109 */
    104110typedef struct VIRTQBUF
     
    166172static const VIRTIO_FEATURES_LIST s_aCoreFeatures[] =
    167173{
     174    { VIRTIO_F_VERSION_1,               "   VERSION_1            Guest driver supports VirtIO specification V1.0+ (e.g. \"modern\")\n" },
     175    { VIRTIO_F_RING_EVENT_IDX,          "   RING_EVENT_IDX       Enables use_event and avail_event fields described in 2.4.7, 2.4.8\n" },
    168176    { VIRTIO_F_RING_INDIRECT_DESC,      "   RING_INDIRECT_DESC   Driver can use descriptors with VIRTQ_DESC_F_INDIRECT flag set\n" },
    169     { VIRTIO_F_RING_EVENT_IDX,          "   RING_EVENT_IDX       Enables use_event and avail_event fields described in 2.4.7, 2.4.8\n" },
    170     { VIRTIO_F_VERSION_1,               "   VERSION              Used to detect legacy drivers.\n" },
    171177};
    172 
    173178
    174179#define VIRTIO_DEV_INDEPENDENT_FEATURES_OFFERED ( 0 )            /**< TBD: Add VIRTIO_F_INDIRECT_DESC           */
     
    202207    kvirtIoVmStateChangedFor32BitHack = 0x7fffffff
    203208} VIRTIOVMSTATECHANGED;
    204 
    205 
    206209
    207210/** @def Virtio Device PCI Capabilities type codes */
     
    305308typedef struct VIRTQUEUE
    306309{
    307     RTGCPHYS                    GCPhysVirtqDesc;                  /**< (MMIO) PhysAdr per-Q desc structs   GUEST */
    308     RTGCPHYS                    GCPhysVirtqAvail;                 /**< (MMIO) PhysAdr per-Q avail structs  GUEST */
    309     RTGCPHYS                    GCPhysVirtqUsed;                  /**< (MMIO) PhysAdr per-Q used structs   GUEST */
    310     uint16_t                    uMsixVector;                      /**< (MMIO) Per-queue vector for MSI-X   GUEST */
    311     uint16_t                    uEnable;                          /**< (MMIO) Per-queue enable             GUEST */
    312     uint16_t                    uNotifyOffset;                    /**< (MMIO) per-Q notify offset          HOST */
    313     uint16_t                    uQueueSize;                       /**< (MMIO) Per-queue size          HOST/GUEST */
     310    RTGCPHYS                    GCPhysVirtqDesc;                  /**< (MMIO) Addr of virtq's desc  ring   GUEST */
     311    RTGCPHYS                    GCPhysVirtqAvail;                 /**< (MMIO) Addr of virtq's avail ring   GUEST */
     312    RTGCPHYS                    GCPhysVirtqUsed;                  /**< (MMIO) Addr of virtq's used  ring   GUEST */
     313    uint16_t                    uMsixVector;                      /**< (MMIO) MSI-X vector                 GUEST */
     314    uint16_t                    uEnable;                          /**< (MMIO) Queue enable flag            GUEST */
     315    uint16_t                    uNotifyOffset;                    /**< (MMIO) Notification offset for queue HOST */
     316    uint16_t                    uQueueSize;                       /**< (MMIO) Size of queue           HOST/GUEST */
    314317    uint16_t                    uAvailIdxShadow;                  /**< Consumer's position in avail ring         */
    315318    uint16_t                    uUsedIdxShadow;                   /**< Consumer's position in used ring          */
     
    317320    char                        szName[32];                       /**< Dev-specific name of queue                */
    318321    bool                        fUsedRingEvent;                   /**< Flags if used idx to notify guest reached */
    319     uint8_t                     padding[3];
     322    bool                        fAttached;                        /**< Flags if dev-specific client attached     */
    320323} VIRTQUEUE, *PVIRTQUEUE;
    321324
     
    331334    uint64_t                    uDeviceFeatures;                  /**< (MMIO) Host features offered         HOST */
    332335    uint64_t                    uDriverFeatures;                  /**< (MMIO) Host features accepted       GUEST */
     336    uint32_t                    fDriverFeaturesWritten;           /**< (MMIO) Host features complete tracking    */
    333337    uint32_t                    uDeviceFeaturesSelect;            /**< (MMIO) hi/lo select uDeviceFeatures GUEST */
    334338    uint32_t                    uDriverFeaturesSelect;            /**< (MMIO) hi/lo select uDriverFeatures GUEST */
     
    343347    uint8_t                     fMsiSupport;                      /**< Flag set if using MSI instead of ISR      */
    344348    uint16_t                    uVirtqSelect;                     /**< (MMIO) queue selector               GUEST */
    345     uint32_t                    fLegacyDriver;                    /**< Set if guest driver < VirtIO 1.0          */
     349    uint32_t                    fLegacyDriver;                    /**< Set if guest drv < VirtIO 1.0 and allowed */
     350    uint32_t                    fOfferLegacy;                     /**< Set at init call from dev-specific code   */
    346351
    347352    /** @name The locations of the capability structures in PCI config space and the BAR.
     
    354359    /** @} */
    355360
    356 
    357 
    358361    IOMMMIOHANDLE               hMmioPciCap;                      /**< MMIO handle of PCI cap. region (\#2)      */
    359362    IOMIOPORTHANDLE             hLegacyIoPorts;                   /**< Handle of legacy I/O port range.          */
    360 
    361363
    362364#ifdef VBOX_WITH_STATISTICS
     
    374376    STAMPROFILEADV              StatWriteRC;                       /** I/O port and MMIO R3 Write profiling      */
    375377#endif
    376 
    377 
    378378    /** @} */
     379
    379380} VIRTIOCORE;
    380381
     
    389390     * @{  */
    390391    /**
    391      * Implementation-specific client callback to report VirtIO version as modern or legacy.
    392      * That's the only meaningful distinction in the VirtIO specification. Beyond that
    393      * versioning is loosely discernable through feature negotiation. There will be two callbacks,
    394      * the first indicates the guest driver is considered legacy VirtIO, as it is critical to
    395      * assume that initially. A 2nd callback will occur during feature negotiation
    396      * which will indicate the guest is modern, if the guest acknowledges VIRTIO_F_VERSION_1,
    397      * feature, or legacy if the feature isn't negotiated. That 2nd callback allows
    398      * the device-specific code to configure its behavior in terms of both guest version and features.
     392     * Implementation-specific client callback to report VirtIO when feature negotiation is
     393     * complete. It should be invoked by the VirtIO core only once.
    399394     *
    400      * @param   pVirtio    Pointer to the shared virtio state.
    401      * @param   fModern    True if guest driver identified itself as modern (e.g. VirtIO 1.0 featured)
     395     * @param   pVirtio           Pointer to the shared virtio state.
     396     * @param   fDriverFeatures   Bitmask of features the guest driver has accepted/declined.
     397     * @param   fLegacy           true if legacy mode offered and until guest driver identifies itself
     398     *                            as modern(e.g. VirtIO 1.0 featured)
    402399     */
    403     DECLCALLBACKMEMBER(void, pfnGuestVersionHandler,(PVIRTIOCORE pVirtio, uint32_t fModern));
     400    DECLCALLBACKMEMBER(void, pfnFeatureNegotiationComplete, (PVIRTIOCORE pVirtio, uint64_t fDriverFeatures, uint32_t fLegacy));
    404401
    405402    /**
     
    436433    DECLCALLBACKMEMBER(int, pfnDevCapWrite,(PPDMDEVINS pDevIns, uint32_t offCap, const void *pvBuf, uint32_t cbWrite));
    437434
    438 
    439435    /**
    440436     * When guest-to-host queue notifications are enabled, the guest driver notifies the host
     
    469465{
    470466    /**
    471      * When guest-to-host queue notifications are enabled, the guest driver notifies the host
    472      * that the avail queue has buffers, and this callback informs the client.
     467     * This callback notifies the device-specific portion of this device implementation (if guest-to-host
     468     * queue notifications are enabled), that the guest driver has notified the host (this device)
     469     * that the VirtIO "avail" ring of a queue has some new s/g buffers added by the guest VirtIO driver.
    473470     *
    474471     * @param   pVirtio    Pointer to the shared virtio state.
     
    488485} VIRTIOCORERC;
    489486
    490 
    491487/** @typedef VIRTIOCORECC
    492488 * The instance data for the current context. */
    493489typedef CTX_SUFF(VIRTIOCORE) VIRTIOCORECC;
    494490
    495 
    496491/** @name API for VirtIO parent device
    497492 * @{ */
     
    502497 * This should be called from PDMDEVREGR3::pfnConstruct.
    503498 *
    504  * @param   pDevIns                 The device instance.
     499 * @param   pDevIns                 Device instance.
    505500 * @param   pVirtio                 Pointer to the shared virtio state.  This
    506501 *                                  must be the first member in the shared
     
    519514int virtioCoreR3Init(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC,
    520515                          PVIRTIOPCIPARAMS pPciParams, const char *pcszInstance,
    521                           uint64_t fDevSpecificFeatures, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg);
    522 
     516                          uint64_t fDevSpecificFeatures, uint32_t fOfferLegacy, void *pvDevSpecificCfg, uint16_t cbDevSpecificCfg);
    523517/**
    524518 * Initiate orderly reset procedure. This is an exposed API for clients that might need it.
     
    532526 * 'Attaches' host device-specific implementation's queue state to host VirtIO core
    533527 * virtqueue management infrastructure, informing the virtio core of the name of the
    534  * queue associated with the queue number. uVirtqNbr is used as the 'handle' for virt queues
    535  * in this API (and is opaquely the index into the VirtIO core's array of queue state).
    536  *
    537  * Virtqueue numbers are VirtIO specification defined (i.e. they are unique within each
    538  * VirtIO device type).
     528 * queue to associate with the queue number.
     529
     530 * Note: uVirtqNbr (ordinal index) is used as the 'handle' for virtqs in this VirtioCore
     531 * implementation's API (as an opaque selector into the VirtIO core's array of queues' states).
     532 *
     533 * Virtqueue numbers are actually VirtIO-specification defined device-specifically
     534 * (i.e. they are unique within each VirtIO device type), but are in some cases scalable
     535 * so only the pattern of queue numbers is defined by the spec and implementations may contain
     536 * a self-determined plurality of queues.
    539537 *
    540538 * @param   pVirtio     Pointer to the shared virtio state.
     
    547545
    548546/**
    549  * Enables or disables a virtq
     547 * Detaches host device-specific implementation's queue state from the host VirtIO core
     548 * virtqueue management infrastructure, informing the VirtIO core that the queue is
     549 * not utilized by the device-specific code.
    550550 *
    551551 * @param   pVirtio     Pointer to the shared virtio state.
    552552 * @param   uVirtqNbr   Virtq number
    553  * @param   fEnable     Flags whether to enable or disable the virtq
    554  *
    555  */
    556 void  virtioCoreVirtqEnable(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, bool fEnable);
     553 * @param   pcszName    Name to give queue
     554 *
     555 * @returns VBox status code.
     556 */
     557int  virtioCoreR3VirtqDetach(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
     558
     559/**
     560 * Checks to see whether queue is attached to core.
     561 *
     562 * @param   pVirtio     Pointer to the shared virtio state.
     563 * @param   uVirtqNbr   Virtq number
     564 *
     565 * Returns boolean true or false indicating whether dev-specific reflection
     566 * of queue is attached to core.
     567 */
     568bool  virtioCoreR3VirtqIsAttached(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
     569
     570/**
     571 * Checks to see whether queue is enabled.
     572 *
     573 * @param   pVirtio     Pointer to the shared virtio state.
     574 * @param   uVirtqNbr   Virtq number
     575 *
     576 * Returns boolean true or false indicating core queue enable state.
     577 * There is no API function to enable the queue, because the actual enabling is handled
     578 * by the guest via MMIO.
     579 *
     580 * NOTE: Guest VirtIO driver's claim over this state is overridden (which violates VirtIO 1.0 spec
     581 * in a carefully controlled manner) in the case where the queue MUST be disabled, due to observed
     582 * control queue corruption (e.g. null GCPhys virtq base addr) while restoring legacy-only device's
     583 * (DevVirtioNet.cpp) as a way to flag that the queue is unusable-as-saved and must to be removed.
     584 * That is all handled in the load/save exec logic. Device reset could potentially, depending on
     585 * parameters passed from host VirtIO device to guest VirtIO driver, result in guest re-establishing
     586 * queue, except, in that situation, the queue operational state would be valid.
     587 */
     588bool  virtioCoreR3VirtqIsEnabled(PVIRTIOCORE pVirtio, uint16_t uVirtqNbr);
    557589
    558590/**
    559591 * Enable or disable notification for the specified queue.
    560592 *
    561  * With notification enabled, the guest driver notifies the host device (via MMIO
    562  * to the queue notification offset describe in VirtIO 1.0, 4.1.4.4 "Notification Structure Layout")
    563  * whenever the guest driver adds a new entry to the avail ring of the respective queue.
    564  *
    565  * Note: In the VirtIO world, the device sets flags in the used ring to communicate to the driver how to
    566  * handle notifications for the avail ring and the drivers sets flags in the avail ring to communicate
    567  * to the device how to handle sending interrupts for the used ring.
     593 * When queue notifications are enabled, the guest VirtIO driver notifies host VirtIO device
     594 * (via MMIO, see VirtIO 1.0, 4.1.4.4 "Notification Structure Layout") whenever guest driver adds
     595 * a new s/g buffer to the "avail" ring of the queue.
     596 *
     597 * Note: VirtIO queue layout includes flags the device controls in "used" ring to inform guest
     598 * driver if it should notify host of guest's buffer additions to the "avail" ring, and
     599 * conversely, the guest driver sets flags in the "avail" ring to communicate to host device
     600 * whether or not to interrupt guest when it adds buffers to used ring.
    568601 *
    569602 * @param   pVirtio     Pointer to the shared virtio state.
     
    581614
    582615/**
    583  * Displays the VirtIO spec-related features offered and their accepted/declined status
    584  * by both the VirtIO core and dev-specific device code (which invokes this function).
    585  * The result is a comprehensive list of available features the VirtIO specification
    586  * defines, which ones were actually offered by the device, and which ones were accepted
    587  * by the guest driver, thus providing a legible summary view of the configuration
    588  * the device is operating with.
    589  *
     616 * Displays a well-formated human-readable translation of otherwise inscrutable bitmasks
     617 * that embody features VirtIO specification definitions, indicating: Totality of features
     618 * that can be implemented by host and guest, which features were offered by the host, and
     619 * which were actually accepted by the guest. It displays it as a summary view of the device's
     620 * finalized operational state (host-guest negotiated architecture) in such a way that shows
     621 * which options are available for implementing or enabling.
     622 *
     623 * The non-device-specific VirtIO features list are managed by core API (e.g. implied).
     624 * Only dev-specific features must be passed as parameter.
     625
    590626 * @param   pVirtio     Pointer to the shared virtio state.
    591627 * @param   pHlp        Pointer to the debug info hlp struct
    592  * @param   s_aDevSpecificFeatures
    593  *                      Features specification lists for device-specific implementation
    594  *                      (i.e: net controller, scsi controller ...)
     628 * @param   s_aDevSpecificFeatures  Dev-specific features (virtio-net, virtio-scsi...)
    595629 * @param   cFeatures   Number of features in aDevSpecificFeatures
    596630 */
     
    599633
    600634/*
    601  * Debuging assist feature displays the state of the VirtIO core code, which includes
     635 * Debug-assist utility function to display state of the VirtIO core code, including
    602636 * an overview of the state of all of the queues.
    603637 *
     
    608642 *
    609643 * This is implemented currently to be invoked by the inheriting device-specific code
    610  * (see DevVirtioNet for an example, which receives the debugvm callback directly).
    611  * DevVirtioNet lists the available sub-options if no arguments are provided. In that
     644 * (see the the VirtualBox virtio-net (VirtIO network controller device implementation)
     645 * for an example of code that receive debugvm callback directly).
     646 *
     647 * DevVirtioNet lists available sub-options if no arguments are provided. In that
    612648 * example this virtq info related function is invoked hierarchically when virtio-net
    613649 * displays its device-specific queue info.
     
    629665
    630666/**
    631  * This function is identical to virtioCoreR3VirtqAvailBufGet(), except it doesn't 'consume'
    632  * the buffer from the avail ring of the virtq. The peek operation becomes identical to a get
    633  * operation if virtioCoreR3VirtqAvailRingNext() is called to consume the buffer from the avail ring,
    634  * at which point virtioCoreR3VirtqUsedBufPut() must be called to complete the roundtrip
    635  * transaction by putting the descriptor on the used ring.
    636  *
     667 * This function is identical to virtioCoreR3VirtqAvailBufGet(), *except* it doesn't consume
     668 * peeked buffer from avail ring of the virtq. The function *becomes* identical to the
     669 * virtioCoreR3VirtqAvailBufGet() only if virtioCoreR3VirtqAvailRingNext() is invoked to
     670 * consume buf from the queue's avail ring, followed by invocation of virtioCoreR3VirtqUsedBufPut(),
     671 * to hand host-processed buffer back to guest, which completes guest-initiated virtq buffer circuit.
    637672 *
    638673 * @param   pDevIns     The device instance.
     
    652687/**
    653688 * This function fetches the next buffer (descriptor chain) from the VirtIO "avail" ring of
    654  * indicated queue, and converts the buf's s/g vectors into OUT (e.g. guest-to-host)
     689 * indicated queue, separating the buf's s/g vectors into OUT (e.g. guest-to-host)
    655690 * components and and IN (host-to-guest) components.
    656691 *
    657  * The caller is responsible for GCPhys to host virtual memory conversions. If the
     692 * Caller is responsible for GCPhys to host virtual memory conversions. If the
    658693 * virtq buffer being peeked at is "consumed", virtioCoreR3VirtqAvailRingNext() must
    659  * be called and in that case virtioCoreR3VirtqUsedBufPut() must be called to
    660  * complete the roundtrip virtq transaction.
     694 * be called, and after that virtioCoreR3VirtqUsedBufPut() must be called to
     695 * complete the buffer transfer cycle with the guest.
    661696 *
    662697 * @param   pDevIns     The device instance.
     
    678713
    679714/**
    680  * Fetches a specific descriptor chain using avail ring of indicated queue and converts the descriptor
    681  * chain into its OUT (to device) and IN (to guest) components.
     715 * Fetches a specific descriptor chain using avail ring of indicated queue and converts the
     716 * descriptor chain into its OUT (to device) and IN (to guest) components.
    682717 *
    683718 * The caller is responsible for GCPhys to host virtual memory conversions and *must*
     
    704739/**
    705740 * Returns data to the guest to complete a transaction initiated by virtioCoreR3VirtqAvailBufGet(),
    706  * or virtioCoreR3VirtqAvailBufPeek()/virtioCoreR3VirtqBufSync() call pairs to complete each
    707  * intervening a roundtrip transaction, ultimately putting each descriptor chain pulled from the
    708  * avail ring of a queue onto the used ring of the queue. wherein I/O transactions are always
    709  * initiated by the guest and completed by the host. In other words, for the host to send any
    710  * data to the guest, the guest must provide buffers, for the host to fill, via the avail ring
    711  * of the virtq.
     741 * (or virtioCoreR3VirtqAvailBufPeek()/virtioCoreR3VirtqBufSync() call pair), to complete each
     742 * buffer transfer transaction (guest-host buffer cycle), ultimately moving each descriptor chain
     743 * from the avail ring of a queue onto the used ring of the queue. Note that VirtIO buffer
     744 * transactions are *always* initiated by the guest and completed by the host. In other words,
     745 * for the host to send any I/O related data to the guest (and in some cases configuration data),
     746 * the guest must provide buffers via the virtq's avail ring, for the host to fill.
    712747 *
    713748 * At some some point virtioCoreR3VirtqUsedRingSync() must be called to return data to the guest,
    714  * completing all pending virtioCoreR3VirtqAvailBufPut() transactions that have accumulated since
    715  * the last call to virtioCoreR3VirtqUsedRingSync()
    716 
    717  * @note This does a write-ahead to the used ring of the guest's queue. The data
    718  *       written won't be seen by the guest until the next call to virtioCoreVirtqUsedRingSync()
    719  *
     749 * completing all pending virtioCoreR3VirtqAvailBufPut() operations that have accumulated since
     750 * the last call to virtioCoreR3VirtqUsedRingSync().
     751
     752 * @note This function effectively performs write-ahead to the used ring of the virtq.
     753 *       Data written won't be seen by the guest until the next call to virtioCoreVirtqUsedRingSync()
    720754 *
    721755 * @param   pDevIns         The device instance (for reading).
     
    729763 *                          buffer originally pulled from the queue.
    730764 *
    731  * @param   fFence          If true, put up copy fence (memory barrier) after
     765 * @param   fFence          If true (default), put up copy-fence (memory barrier) after
    732766 *                          copying to guest phys. mem.
    733767 *
     
    741775 */
    742776int virtioCoreR3VirtqUsedBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtqNbr, PRTSGBUF pSgVirtReturn,
    743                                  PVIRTQBUF pVirtqBuf, bool fFence);
     777                                 PVIRTQBUF pVirtqBuf, bool fFence = true);
     778
     779
     780/**
     781 * Quicker variant of same-named function (directly above) that it overloads,
     782 * Instead, this variant accepts as input a pointer to a buffer and count,
     783 * instead of S/G buffer thus doesn't have to copy between two S/G buffers and avoids some overhead.
     784 *
     785 * @param   pDevIns         The device instance (for reading).
     786 * @param   pVirtio         Pointer to the shared virtio state.
     787 * @param   uVirtqNbr       Virtq number
     788 * @param   cb              Number of bytes to add to copy to phys. buf.
     789 * @param   pv              Virtual mem buf to copy to phys buf.
     790 * @param   cbEnqueue       How many bytes in packet to enqueue (0 = don't enqueue)
     791 * @param   fFence          If true (default), put up copy-fence (memory barrier) after
     792 *                          copying to guest phys. mem.
     793 *
     794 * @returns VBox status code.
     795 * @retval  VINF_SUCCESS       Success
     796 * @retval  VERR_INVALID_STATE VirtIO not in ready state
     797 * @retval  VERR_NOT_AVAILABLE Virtq is empty
     798 *
     799 * @note    This function will not release any reference to pVirtqBuf.  The
     800 *          caller must take care of that.
     801 */
     802int virtioCoreR3VirtqUsedBufPut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t uVirtq, size_t cb, const void *pv,
     803                            PVIRTQBUF pVirtqBuf, uint32_t cbEnqueue, bool fFence = true);
     804
     805
    744806/**
    745807 * Advance index of avail ring to next entry in specified virtq (see virtioCoreR3VirtqAvailBufPeek())
     
    751813
    752814/**
    753  * Checks to see if guest has acknowledged device's VIRTIO_F_VERSION_1 feature.
    754  * If not, it's presumed to be a VirtIO legacy guest driver. Note that legacy drivers
    755  * may start using the device prematurely, as opposed to the rigorously sane protocol
    756  * prescribed by the "modern" VirtIO spec. Early access implies a legacy driver.
    757  * Therefore legacy mode is the assumption until feature negotiation.
     815 * Checks to see if guest has accepted host device's VIRTIO_F_VERSION_1 (i.e. "modern")
     816 * behavioral modeling, indicating guest agreed to comply with the modern VirtIO 1.0+ specification.
     817 * Otherwise unavoidable presumption is that the host device is dealing with legacy VirtIO
     818 * guest drive, thus must be prepared to cope with less mature architecture and behaviors
     819 * from  prototype era of VirtIO. (see comments in PDM-invoked device constructor for more information).
    758820 *
    759821 * @param   pVirtio      Pointer to the virtio state.
     
    761823int virtioCoreIsLegacyMode(PVIRTIOCORE pVirtio);
    762824
     825/**
     826 * This VirtIO transitional device supports "modern" (rev 1.0+) as well as "legacy" (e.g. < 1.0) VirtIO drivers.
     827 * Some legacy guest drivers are known to mishandle PCI bus mastering wherein the PCI flavor of GC phys
     828 * access functions can't be used. The following wrappers select the memory access method based on whether the
     829 * device is operating in legacy mode or not.
     830 */
     831DECLINLINE(int) virtioCoreGCPhysWrite(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbWrite)
     832{
     833    int rc;
     834    if (virtioCoreIsLegacyMode(pVirtio))
     835        rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
     836    else
     837        rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
     838    return rc;
     839}
     840
     841DECLINLINE(int) virtioCoreGCPhysRead(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
     842{
     843    int rc;
     844    if (virtioCoreIsLegacyMode(pVirtio))
     845        rc = PDMDevHlpPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
     846    else
     847        rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
     848    return rc;
     849}
     850
     851/*
     852 * (See comments for corresponding function in sg.h)
     853 */
    763854DECLINLINE(void) virtioCoreGCPhysChainInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs)
    764855{
     
    782873}
    783874
     875/*
     876 * (See comments for corresponding function in sg.h)
     877 */
    784878DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainGet(PVIRTIOSGBUF pGcSgBuf, size_t *pcbData)
    785879{
     
    826920}
    827921
     922/*
     923 * (See comments for corresponding function in sg.h)
     924 */
    828925DECLINLINE(void) virtioCoreGCPhysChainReset(PVIRTIOSGBUF pGcSgBuf)
    829926{
     
    843940}
    844941
     942/*
     943 * (See comments for corresponding function in sg.h)
     944 */
    845945DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainAdvance(PVIRTIOSGBUF pGcSgBuf, size_t cbAdvance)
    846946{
     
    860960}
    861961
     962/*
     963 * (See comments for corresponding function in sg.h)
     964 */
    862965DECLINLINE(RTGCPHYS) virtioCoreGCPhysChainGetNextSeg(PVIRTIOSGBUF pGcSgBuf, size_t *pcbSeg)
    863966{
     
    871974}
    872975
    873 DECLINLINE(size_t) virtioCoreGCPhysChainCalcBufSize(PVIRTIOSGBUF pGcSgBuf)
     976/**
     977 * Calculate the length of a GCPhys s/g buffer by tallying the size of each segment.
     978 *
     979 * @param   pGcSgBuf        Guest Context (GCPhys) S/G buffer to calculate length of
     980 */
     981DECLINLINE(size_t) virtioCoreGCPhysChainCalcBufSize(PCVIRTIOSGBUF pGcSgBuf)
    874982{
    875983    size_t   cb = 0;
    876984    unsigned i  = pGcSgBuf->cSegs;
    877      while (i-- > 0)
    878          cb += pGcSgBuf->paSegs[i].cbSeg;
    879      return cb;
    880  }
    881 
     985    while (i-- > 0)
     986        cb += pGcSgBuf->paSegs[i].cbSeg;
     987    return cb;
     988}
     989
     990/*
     991 * (See comments for corresponding function in sg.h)
     992 */
     993DECLINLINE(size_t) virtioCoreGCPhysChainCalcLengthLeft(PVIRTIOSGBUF pGcSgBuf)
     994{
     995    size_t   cb = pGcSgBuf->cbSegLeft;
     996    unsigned i  = pGcSgBuf->cSegs;
     997    while (i-- > pGcSgBuf->idxSeg + 1)
     998        cb += pGcSgBuf->paSegs[i].cbSeg;
     999    return cb;
     1000}
    8821001#define VIRTQNAME(a_pVirtio, a_uVirtq) ((a_pVirtio)->aVirtqueues[(a_uVirtq)].szName)
    8831002
    8841003/**
    885  * Add some bytes to a virtq (s/g) buffer, converting them from virtual memory to GCPhys
    886  *
    887  * To be performant it is left to the caller to validate the size of the buffer with regard
    888  * to data being pulled from it to avoid overruns/underruns.
     1004 * Convert and append bytes from a virtual-memory simple buffer to VirtIO guest's
     1005 * physical memory described by a buffer pulled form the avail ring of a virtq.
    8891006 *
    8901007 * @param   pVirtio     Pointer to the shared virtio state.
    891  * @param   pVirtqBuf   output: virtq buffer
     1008 * @param   pVirtqBuf   VirtIO buffer to fill
    8921009 * @param   pv          input: virtual memory buffer to receive bytes
    8931010 * @param   cb          number of bytes to add to the s/g buffer.
     
    8951012DECLINLINE(void) virtioCoreR3VirqBufFill(PVIRTIOCORE pVirtio, PVIRTQBUF pVirtqBuf, void *pv, size_t cb)
    8961013{
    897     uint8_t *pb = (uint8_t *)pv;
    898     size_t cbLim = RT_MIN(pVirtqBuf->cbPhysReturn, cb);
    899     while (cbLim)
     1014    uint8_t *pvBuf = (uint8_t *)pv;
     1015    size_t cbRemain = cb, cbTotal = 0;
     1016    PVIRTIOSGBUF pSgPhysReturn = pVirtqBuf->pSgPhysReturn;
     1017    while (cbRemain)
    9001018    {
    901         size_t cbSeg = cbLim;
    902         RTGCPHYS GCPhys = virtioCoreGCPhysChainGetNextSeg(pVirtqBuf->pSgPhysReturn, &cbSeg);
    903         PDMDevHlpPCIPhysWrite(pVirtio->pDevInsR3, GCPhys, pb, cbSeg);
    904         pb += cbSeg;
    905         cbLim -= cbSeg;
    906         pVirtqBuf->cbPhysSend -= cbSeg;
     1019        uint32_t cbBounded = RT_MIN(pSgPhysReturn->cbSegLeft, cbRemain);
     1020        Assert(cbBounded > 0);
     1021        virtioCoreGCPhysWrite(pVirtio, CTX_SUFF(pVirtio->pDevIns), (RTGCPHYS)pSgPhysReturn->GCPhysCur, pvBuf, cbBounded);
     1022        virtioCoreGCPhysChainAdvance(pSgPhysReturn, cbBounded);
     1023        pvBuf += cbBounded;
     1024        cbRemain -= cbBounded;
     1025        cbTotal += cbBounded;
    9071026    }
    908     LogFunc(("Added %d/%d bytes to %s buffer, head idx: %u (%d bytes remain)\n",
    909              cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq),
    910              pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysReturn));
    911 }
    912 
    913 /**
    914  * Extract some bytes out of a virtq (s/g) buffer, converting them from GCPhys to virtual memory
    915  *
    916  * To be performant it is left to the caller to validate the size of the buffer with regard
    917  * to data being pulled from it to avoid overruns/underruns.
     1027    LogFunc(("Appended %d bytes to guest phys buf [head: %u]. %d bytes unused in buf.)\n",
     1028             cbTotal, pVirtqBuf->uHeadIdx, virtioCoreGCPhysChainCalcLengthLeft(pSgPhysReturn)));
     1029}
     1030
     1031/**
     1032 * Extract some bytes from of a virtq s/g buffer, converting them from GCPhys space to
     1033 * to ordinary virtual memory (i.e. making data directly accessible to host device code)
     1034 *
     1035 * As a performance optimization, it is left to the caller to validate buffer size.
    9181036 *
    9191037 * @param   pVirtio     Pointer to the shared virtio state.
     
    9371055    LogFunc(("Drained %d/%d bytes from %s buffer, head idx: %u (%d bytes left)\n",
    9381056             cb - cbLim, cb, VIRTQNAME(pVirtio, pVirtqBuf->uVirtq),
    939              pVirtqBuf->uHeadIdx, pVirtqBuf->cbPhysSend));
     1057             pVirtqBuf->uHeadIdx, virtioCoreGCPhysChainCalcLengthLeft(pVirtqBuf->pSgPhysReturn)));
    9401058}
    9411059
     
    10161134 * VirtIO implementation to identify this device's operational configuration after features
    10171135 * have been negotiated with guest VirtIO driver. Feature negotiation entails host indicating
    1018  * to guest which features it supports, then guest accepting among those offered which features
     1136 * to guest which features it supports, then guest accepting from among the offered, which features
    10191137 * it will enable. That becomes the agreement between the host and guest. The bitmask containing
    10201138 * virtio core features plus device-specific features is provided as a parameter to virtioCoreR3Init()
     
    10311149
    10321150/**
    1033  * Get the the name of the VM state change associated with the enumeration variable
     1151 * Get name of the VM state change associated with the enumeration variable
    10341152 *
    10351153 * @param enmState       VM state (enumeration value)
     
    10781196/**
    10791197 * Debug assist for any consumer device code
    1080 &
    10811198 * Do a hex dump of memory in guest physical context
    10821199 *
     
    10931210 */
    10941211
    1095 /**
    1096  * Calculate the length of a GCPhys s/g buffer by tallying the size of each segment.
    1097  *
    1098  * @param   pGcSgBuf        Guest Context (GCPhys) S/G buffer to calculate length of
    1099  */
    1100 DECLINLINE(size_t) virtioCoreGCPhysChainCalcBufSize(PCVIRTIOSGBUF pGcSgBuf)
    1101 {
    1102     size_t   cb = 0;
    1103     unsigned i  = pGcSgBuf->cSegs;
    1104     while (i-- > 0)
    1105         cb += pGcSgBuf->paSegs[i].cbSeg;
    1106     return cb;
    1107 }
    1108 
    1109 /**
    1110  * This VirtIO transitional device supports "modern" (rev 1.0+) as well as "legacy" (e.g. < 1.0) VirtIO drivers.
    1111  * Some legacy guest drivers are known to mishandle PCI bus mastering wherein the PCI flavor of GC phys
    1112  * access functions can't be used. The following wrappers select the mem access method based on whether the
    1113  * device is operating in legacy mode or not.
    1114  */
    1115 DECLINLINE(int) virtioCoreGCPhysWrite(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbWrite)
    1116 {
    1117     int rc;
    1118     if (virtioCoreIsLegacyMode(pVirtio))
    1119         rc = PDMDevHlpPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
    1120     else
    1121         rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite);
    1122     return rc;
    1123 }
    1124 
    1125 DECLINLINE(int) virtioCoreGCPhysRead(PVIRTIOCORE pVirtio, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
    1126 {
    1127     int rc;
    1128     if (virtioCoreIsLegacyMode(pVirtio))
    1129         rc = PDMDevHlpPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
    1130     else
    1131         rc = PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pvBuf, cbRead);
    1132     return rc;
    1133 }
    1134 
    11351212/** Misc VM and PDM boilerplate */
    1136 int      virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM);
    1137 int      virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM);
     1213int      virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t cQueues);
     1214int      virtioCoreR3ModernDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uTestVersion, uint32_t cQueues);
     1215int      virtioCoreR3LegacyDeviceLoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uVirtioLegacy_3_1_Beta);
    11381216void     virtioCoreR3VmStateChanged(PVIRTIOCORE pVirtio, VIRTIOVMSTATECHANGED enmState);
    11391217void     virtioCoreR3Term(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC);
     
    11471225 * cb, pv and fWrite are implicit parameters and must be defined by the invoker.
    11481226 */
    1149 
    11501227#ifdef LOG_ENABLED
    11511228
     
    12011278 * the memory described by cb and pv.
    12021279 *
    1203  * cb, pv and fWrite are implicit parameters and must be defined by the invoker.
     1280 * cb, pv and fWrite are implicit parameters and must be defined by invoker.
    12041281 */
    12051282#define VIRTIO_DEV_CONFIG_ACCESS(member, tCfgStruct, uOffsetOfAccess, pCfgStruct) \
     
    12161293/**
    12171294 * Copies bytes into memory described by cb, pv from the specified member field of the config struct.
    1218  * The operation is a nop and logs error if implied parameter fWrite is true.
     1295 * The operation is a NOP, logging an error if an implied parameter, fWrite, is boolean true.
    12191296 *
    12201297 * cb, pv and fWrite are implicit parameters and must be defined by the invoker.
     
    12371314 * the memory described by cb and pv.
    12381315 *
    1239  * cb, pv and fWrite are implicit parameters and must be defined by the invoker.
     1316 * cb, pv and fWrite are implicit parameters and must be defined by invoker.
    12401317 */
    12411318#define VIRTIO_DEV_CONFIG_ACCESS_INDEXED(member, uIdx, tCfgStruct, uOffsetOfAccess, pCfgStruct) \
     
    12541331 * The operation is a nop and logs error if implied parameter fWrite is true.
    12551332 *
    1256  * cb, pv and fWrite are implicit parameters and must be defined by the invoker.
     1333 * cb, pv and fWrite are implicit parameters and must be defined by invoker.
    12571334 */
    12581335#define VIRTIO_DEV_CONFIG_ACCESS_INDEXED_READONLY(member, uidx, tCfgStruct, uOffsetOfAccess, pCfgStruct) \
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